日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > > liwen01

前言

MP4是目前非常常用的一種視頻封裝格式,關(guān)于MP4的介紹資料也非常多。我們常用的封裝庫或工具有:ffmpeg,libmp4v2,GPAC,MP4.js,它們的優(yōu)點(diǎn)是功能基本上都是比較全面,缺點(diǎn)就是它們占用的資源相對(duì)來說也是非常多的。

在嵌入式系統(tǒng)中,不管是RAM還是FLASH空間,一般都是非常小,這個(gè)時(shí)候,如果要將音視頻封裝成MP4,或是解碼MP4格式就會(huì)顯得非常困難,因?yàn)樯厦娼榻B的那些庫都放不下或是因?yàn)閮?nèi)存不夠運(yùn)行不起來,只能根據(jù)MP4協(xié)議自己去解析。

這里介紹一個(gè)輕量級(jí)的MP4封裝方法(minimp4),集成MP4編碼,解碼,信息查詢功能,整體執(zhí)行文件大小如下:

biao@ubuntu:~/minimp4_test$ mips-linux-uclibc-gnu-size test text    data     bss     dec     hex filename
 354696    1460   13624  369780   5a474 t
 biao@ubuntu:~/minimp4_test$ 

(一)功能需求介紹

在一般嵌入式設(shè)備上,我們一般只需要MP4的一些簡(jiǎn)單操作,比如封裝,解封裝及文件信息查看。具體功能要求如下:

  • 支持合入H.264 和H.265 視頻格式視頻
  • 支持合入AAC音頻
  • 支持MP4格式文件解封裝
  • 支持獲取MP4文件信息

性能上的限制,我們希望:

  • 代碼空間小于500K
  • 運(yùn)行內(nèi)存小于100K

要在有限的資源上實(shí)現(xiàn)上面這些功能,我們可以在minimp4的基礎(chǔ)再進(jìn)一步完善。

minimp4的源代碼可以直接在github上下載,官方有個(gè)minimp4_test.c,里面有些使用的demo,但不是非常完善,可以參考使用。

(二)支持H.264與H.265格式

(1)H.264與H.265的區(qū)別

使用工具打開官方自帶的foreman.264文件,我們可以看到:

  • 該文件中包含SPS,PPS,IDR,P幀,在其它文件中,可能還會(huì)有B幀
  • 頭標(biāo)簽為00 00 00 01,后面一個(gè)是幀類型
  • 視頻分辨率352*288
  • 流類型AVC/H.264
  • 總共300幀

另外打開一個(gè)H.265文件

我們可以看到:

  • 該文件中包含VPS SPS,PPS,IDR,TRAIL_R,TRAIL_N幀
  • 頭標(biāo)簽為00 00 00 01,后面是幀類型
  • 視頻分辨率1280*720
  • 流類型HEVC/H.265
  • 總共770幀

從應(yīng)用的角度看,H.265 是有多一個(gè)VPS幀,它主要是用來描述視頻中各種類型幀(比如I幀、P幀、B幀)的使用和順序,以及它們之間的相關(guān)性.

在實(shí)際使用的時(shí)候,需要注意VPS、SPS、PPS這些幀的封裝和解析。

(2)手動(dòng)添加VPS信息

正常使用minimp4 的時(shí)候,使用h.265進(jìn)行封裝的是沒有問題的,但是在解封裝的時(shí)候,它并不會(huì)去提取VPS信息,這里比較簡(jiǎn)單的做法是自己補(bǔ)充上相關(guān)的信息到文件頭:

if(is_hevc){ static unsigned char h265_vps_sps_pps[84]={ 0x00,0x00,0x00,0x01,0x40,0x01,0x0C,0x01, 0xFF,0xFF,0x00,0x80,0x00,0x00,0x03,0x00, 0x00,0x03,0x00,0x00,0x03,0x00,0x00,0x03, 0x00,0x00,0xB5,0x02,0x40,0x00,0x00,0x00, 0x01,0x42,0x01,0x01,0x00,0x80,0x00,0x00, 0x03,0x00,0x00,0x03,0x00,0x00,0x03,0x00, 0x00,0x03,0x00,0x00,0xA0,0x02,0x80,0x80, 0x2D,0x1F,0xE5,0xB5,0x92,0x46,0xD0,0xCE, 0x49,0x24,0xB7,0x24,0xAA,0x49,0xF2,0x92, 0xC8,0x00,0x00,0x00,0x01,0x44,0x01,0xC1, 0xA5,0x58,0x1E,0x48,
 }; if(fwrite(h265_vps_sps_pps, 1, sizeof(h265_vps_sps_pps), foutV)!= sizeof(h265_vps_sps_pps)){ goto END;
 }
 }

h265_vps_sps_pps里面的內(nèi)容,需要根據(jù)自己實(shí)際的碼流信息進(jìn)行修改

(三)支持AAC音頻格式

AAC與PCM之間的編碼與轉(zhuǎn)換,可以查看上一篇文章:嵌入式音頻應(yīng)用開發(fā)介紹

主要需要注意的是AAC的配置,需要根據(jù)實(shí)際參數(shù)進(jìn)行修改

// unsigned char  conf[] = {0x11, 0x90};  //AAL-LC 48kHz 2 channle static unsigned char aac_conf[4]={0x11, 0x90, 0x0, 0x0}; unsigned int length = 2;
 MP4E_set_dsi(mux, audio_track_id, aac_conf,4); printf("%s %d \r\n",__FUNCTION__,__LINE__);

(四)獲取mp4文件信息

這部分需要對(duì) mp4 協(xié)議比較熟悉,具體的協(xié)議介紹,可以去查詢MP4標(biāo)準(zhǔn)。這里介紹幾個(gè)簡(jiǎn)單概念:

概念 描述
Box MP4中的基本構(gòu)建單元,也稱為Atom。每個(gè)Box都有特定類型的標(biāo)識(shí)符和長(zhǎng)度字段,用于描述它自己的內(nèi)容和大小。不同類型的Box包含不同類型的信息。
Sample 視頻和音頻編解碼中的最小可操作單元。對(duì)于視頻,每個(gè)樣本代表一個(gè)畫面或圖像幀;對(duì)于音頻,每個(gè)樣本可能代表一小段聲音。它們按特定順序組成媒體文件。
Track 用于組織媒體數(shù)據(jù)的單獨(dú)通道。MP4文件可以包含多個(gè)軌道,如視頻軌道、音頻軌道。每個(gè)軌道包含相應(yīng)類型的媒體數(shù)據(jù)和描述信息,如視頻軌道包含視頻樣本和元數(shù)據(jù)。
Chunk 一組樣本的集合。在媒體文件中,樣本可以組織成不同大小的塊,可以是連續(xù)的或分散的。塊可以包含一個(gè)或多個(gè)樣本,物理上可以存儲(chǔ)在文件的不同位置。

mp4中包含很多的Box,mp4的基本信息和索引是在moov box中的:

Box類型 描述
mvhd 影片整體信息
trak 包含一個(gè)或多個(gè)軌道的詳細(xì)描述
udta 存儲(chǔ)用戶自定義的數(shù)據(jù)

其中mvhd Box(Movie Header Box):這個(gè)Box包含了影片的整體信息,比如時(shí)長(zhǎng)、時(shí)間刻度等。它描述了整個(gè)媒體文件的基本屬性。

我們打開一個(gè)使用miniMP4封裝的MP4文件,可以看到moov box 是后置的,也就是在文件的后面,而在一些其它的庫中,moov box的偏移位置是在比較靠近文件開始的位置。

如果我們要快速的查看mp4文件的信息,比如視頻時(shí)間長(zhǎng)度,對(duì)于使用minimp4封裝的Mp4文件,它的moov box后置,我們可以從后面開始解析。

#define CHUNK_SIZE (10*1024) typedef struct { unsigned char mvhd[4]; unsigned char version; unsigned char flags[3]; unsigned int creation_time; unsigned int modification_time; unsigned int timescale; unsigned int duration;
}MVHD_ST;

MVHD_ST g_stMVDHInfo; /**
 * @brief 字節(jié)序翻轉(zhuǎn)
 * @param  val
 * @return unsigned int 
 */ unsigned int videoinfo_flip(unsigned int val) { unsigned long new = 0; new += (val & 0x000000FF) << 24; new += (val & 0xFF000000) >> 24; new += (val & 0x0000FF00) << 8; new += (val & 0x00FF0000) >> 8; return new;
} /**
 * @brief 查找特定ASCII碼字符串位置
 * @param  file_name
 * @param  search_str
 * @return long long 
 */ long long find_string_position(const char *file_name, const char *search_str) {
 FILE *file = NULL; char *buffer =NULL; int read_size = 0; int length = 0; long long file_size = 0; long long search_position =0; long long position = 0; if(file_name==NULL || search_str==NULL){ printf("%s %d input para error \r\n",__FUNCTION__,__LINE__); return -1;
 }
 file = fopen(file_name, "rb"); if (file == NULL) { printf("%s %d file open error\r\n",__FUNCTION__,__LINE__); return -2;
 }
 length = strlen(search_str);
 fseek(file, 0, SEEK_END); 
 file_size = ftell(file); 
 search_position = file_size - CHUNK_SIZE; if (search_position < 0) {
 search_position = 0;
 }

 buffer = (char *)malloc(CHUNK_SIZE + 1); if (buffer == NULL) {
 fclose(file); printf("%s %d malloc error\r\n",__FUNCTION__,__LINE__); return -3; 
 } int cnt = 0; while (search_position >= 0) { /**限制檢索最大值,避免輸入文件損壞一直在檢索**/ if(cnt ++>30){ break;
 }
 fseek(file, search_position, SEEK_SET); size_t read_size = fread(buffer, 1, CHUNK_SIZE, file); for (int i = read_size - 1; i >= 0; i--) { int j; for (j = 0; j < length; j++) { if (i - j < 0 || buffer[i - j] != search_str[length - j - 1]) { break;
 }
 } if (j == length) {
 position = search_position + i - length + 1; break;
 }
 }
 search_position = search_position - CHUNK_SIZE; if(search_position<0){
 search_position = 0;
 } if(position!=0){ break;
 }
 } printf("read cnt=%d \r\n",cnt); if(position>0){
 fseek(file, position, SEEK_SET); 
 read_size = fread(&g_stMVDHInfo, 1, sizeof(g_stMVDHInfo), file);
 }
 fclose(file); free(buffer); return position;
}

MP4的詳細(xì)格式定義,可以查看MP4標(biāo)準(zhǔn):Text of ISO/IEC 14496-12 5th edition

(五)減少內(nèi)存的使用

在minimp4源碼中,它有個(gè)preload函數(shù),它的主要作用是將輸入的文件全部讀取到內(nèi)存中去,后面數(shù)據(jù)解析的時(shí)候直接去內(nèi)存Buff中獲取,這種方式的優(yōu)點(diǎn)是處理速度快,缺點(diǎn)就是耗內(nèi)存。

在嵌入式系統(tǒng)設(shè)備中,有些設(shè)備可能整個(gè)系統(tǒng)總共才幾十M的內(nèi)存,一次把整個(gè)文件讀取到內(nèi)存中去解析,如果要處理比較大的mp4文件,顯然是有問題的,會(huì)直接導(dǎo)致系統(tǒng)內(nèi)存不夠用。

有一個(gè)處理方式是按需讀取數(shù)據(jù),需要多少就讀取多少,這樣的處理方式可以以速度換空間。將preload改為preload_file,write_callback改read_file_callback,同時(shí),有對(duì)內(nèi)存數(shù)據(jù)進(jìn)行操作的地方也需要修改。

static FILE *preload_file(const char *path, ssize_t *data_size) {
 FILE *file = fopen(path, "rb"); uint8_t *data;
 *data_size = 0; if (!file){ return 0;
 } if (fseek(file, 0, SEEK_END)){ exit(1);
 }

 *data_size = (ssize_t)ftell(file); if (*data_size < 0){ exit(1);
 } if (fseek(file, 0, SEEK_SET)){ exit(1);
 } return file;
} static int read_file_callback(int64_t offset, void *buffer, size_t size, void *token) { static int total_len = 0;
 INPUT_FILE_BUF *buf = (INPUT_FILE_BUF*)token; int read = 0; int ret = 0; size_t to_copy = MINIMP4_MIN(size, buf->size - offset - size);
 fseek(buf->fin,offset,SEEK_SET);
 read = fread(buffer,1,to_copy,buf->fin); return to_copy != size;
}

(六)工程資料下載

如需上面介紹的工程,測(cè)試文件,以及查看工具,可以在公眾號(hào)中回復(fù)資源獲取,內(nèi)容在音視頻連接中。工程目錄如下:

biao@ubuntu:~/test/minimp4/minimp4_test$ tree
.
├── adts.c
├── adts.h
├── file
│   ├── decode_audio.aac
│   ├── decode_foreman_.264
│   ├── decode_foreman.264
│   ├── decode_test.h265
│   ├── decode_video.h265
│   ├── faac_adts.aac
│   ├── foreman.264
│   ├── h264_aac.mp4
│   ├── h265_aac.mp4
│   └── surfing_aa.h265
├── Makefile
├── minimp4.h
├── obj
│   ├── adts.o
│   └── write_demux_mp4.o
├── test └── write_demux_mp4.c

2 directories, 18 files
biao@ubuntu:~/test/minimp4/minimp4_test$ 

結(jié)尾

minimp4適用于內(nèi)存和存儲(chǔ)空間都非常受限的嵌入式設(shè)備,很多功能并不十分完善,需要自己根據(jù)實(shí)際應(yīng)用進(jìn)行適配。如果只是在設(shè)備上進(jìn)行簡(jiǎn)單的MP4封裝和解封裝,它的功能也是足夠了的。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉