本文轉載自:http://www.cnblogs.com/chutianyao/archive/2012/04/13/2446140.html
錄製程式要添加新功能:錄製CMMB電視節目,我們的板卡發送出來的是RTP流(H264視頻和AAC音頻),錄製程式要做的工作是:
(1)接收並解析RTP包,分離出H264和AAC資料流;
(2)將H264視頻和AAC音頻以某種格式封裝,最後存成檔案,供使用者查看。
第一步已經有部分代碼可供參考,因此很快就完成了。
第二步,我們決定封裝成mp4,尋找了一些資料後,決定使用開源庫mp4v2來合成mp4檔案。
技術路線已確定,就開工幹活。
(一)mp4格式的基礎知識。
關於mp4格式,網上介紹的不少,有以下內容可供參考:
(1)兩個ISO標準:
[ISO/IEC 14496-12]:ISO base media file format --”is a general format forming the basis for a number of other more specific file formats. This format contains the timing, structure, and media information for timed sequences of media data, such as audio-visual presentations ”
[ISO/IEC 14496-14]:MP4 file format --”This specification defines MP4 as an instance of the ISO Media File format [ISO/IEC 14496-12 and ISO/IEC
15444-12]. ”
定義了mp4檔案格式標準。
(2)http://wenku.baidu.com/view/673482284b73f242336c5f4c.html
是上面兩個標準的解釋,建議先看這個,瞭解大概,具體細節再看ISO標準檔案。
(二)技術驗證。主要就是寫驗證代碼,驗證技術可行性。
去官網下載mp4v2源碼、編譯、安裝過程略過不提。所有資料可以在http://code.google.com/p/mp4v2/找到。
先寫部分驗證代碼,很快完成了,但封裝出來的檔案有問題,無法播放。
合成部分,代碼如下:
1 static void* writeThread(void* arg) 2 { 3 rtp_s* p_rtp = (rtp_s*) arg; 4 if (p_rtp == NULL) 5 { 6 printf("ERROR!\n"); 7 return; 8 } 9 10 MP4FileHandle file = MP4CreateEx("test.mp4", MP4_DETAILS_ALL, 0, 1, 1, 0, 0, 0, 0);//建立mp4檔案11 if (file == MP4_INVALID_FILE_HANDLE)12 {13 printf("open file fialed.\n");14 return;15 }16 17 MP4SetTimeScale(file, 90000);18 19 //添加h264 track 20 MP4TrackId video = MP4AddH264VideoTrack(file, 90000, 90000 / 25, 320, 240,21 0x64, //sps[1] AVCProfileIndication22 0x00, //sps[2] profile_compat23 0x1f, //sps[3] AVCLevelIndication24 3); // 4 bytes length before each NAL unit25 if (video == MP4_INVALID_TRACK_ID)26 {27 printf("add video track failed.\n");28 return;29 }30 MP4SetVideoProfileLevel(file, 0x7F);31 32 //添加aac音頻33 MP4TrackId audio = MP4AddAudioTrack(file, 48000, 1024, MP4_MPEG4_AUDIO_TYPE);34 if (video == MP4_INVALID_TRACK_ID)35 {36 printf("add audio track failed.\n");37 return;38 }39 MP4SetAudioProfileLevel(file, 0x2);40 41 42 int ncount = 0;43 while (1)44 {45 frame_t* pf = NULL; //frame46 pthread_mutex_lock(&p_rtp->mutex);47 pf = p_rtp->p_frame_header;48 if (pf != NULL)49 {50 if (pf->i_type == 1)//video51 {52 MP4WriteSample(file, video, pf->p_frame, pf->i_frame_size, MP4_INVALID_DURATION, 0, 1);53 }54 else if (pf->i_type == 2)//audio55 {56 MP4WriteSample(file, audio, pf->p_frame, pf->i_frame_size , MP4_INVALID_DURATION, 0, 1);57 }58 59 ncount++;60 61 //clear frame.62 p_rtp->i_buf_num--;63 p_rtp->p_frame_header = pf->p_next;64 if (p_rtp->i_buf_num <= 0)65 {66 p_rtp->p_frame_buf = p_rtp->p_frame_header;67 }68 free_frame(&pf);69 pf = NULL;70 71 if (ncount >= 1000)72 {73 break;74 }75 }76 else77 {78 //printf("BUFF EMPTY, p_rtp->i_buf_num:%d\n", p_rtp->i_buf_num);79 }80 pthread_mutex_unlock(&p_rtp->mutex);81 usleep(10000);82 }83 84 MP4Close(file);85 }
現象:沒有映像,也沒有聲音,根本無法播放。
於是,艱苦的工作開始了:跟蹤尋找原因。
(1)使用 vlc播放合成的mp4檔案,查看詳細輸出:
1 vlc -vvv test.mp42 [0x8e9357c] mp4 stream debug: found Box: ftyp size 24 3 [0x8e9357c] mp4 stream debug: found Box: free size 136 4 [0x8e9357c] mp4 stream debug: skip box: "free" 5 [0x8e9357c] mp4 stream debug: found Box: mdat size 985725 6 [0x8e9357c] mp4 stream debug: skip box: "mdat" 7 [0x8e9357c] mp4 stream debug: found Box: moov size