周星馳來也!

像很多80,90後年輕人(老男人吧)一樣,周星馳一直就是哥喜愛的電影演員之一,不僅喜歡星爺的人物形象,更是喜歡這種樂觀向上的精神!(哥16年的QQ一直就是周星馳這個昵稱)。
轉入主題吧:
本文demo下載下傳位址http://download.csdn.net/download/xjb2006/10119982
在QQ技術群裡,很多人都在研究ffmpeg,因為功能強大,簡單直接就能實作想要的功能,但是想要用好,還是要下一些功夫。
今天的主題就是怎樣實作對h264,aac流輸入,合成後輸出ts,m3u8,即HLS,蘋果裝置的點播方案!!!!!!!!!!!!!!!!!!!!
網上有很多關于檔案轉mp4或者其他檔案格式的例子,但是換成資料流輸入了,怎麼辦呢?很多人也是一籌莫展。網上也鮮有這種代碼或者文章。
今天,哥哥就順便說幾句,關于我自己的一些想法。
晚上有很多例子是關于輸入視訊檔案的,對我們有些參考,但是要換成輸入h264或者aac資料流,大家都是沒辦法啊。
1、HLS是什麼?
HLS (HTTP Live Streaming)是Apple的動态碼率自适應技術(複制過來的),隻有蘋果的浏覽器才能直接用,因為蘋果不支援flash控件(自然也不支援rtmp),是以才有了HLS技術用于點播直播。調試的時候可以下載下傳一個VLC播放器,這個播放器可以打開m3u8。
2、TS檔案
百度這樣說的:“ts是高清錄影機拍攝下進行的封裝格式,全稱為MPEG2-TS。ts即"Transport Stream"的縮寫。MPEG2-TS格式的特點就是要求從視訊流的任一片段開始都是可以獨立解碼的。先不管這些了,反正HLS就要用到TS格式的檔案,一個一個的。貼張圖吧,百說不如一見:
3、m3u8檔案
M3U8檔案是指UTF-8編碼格式的M3U檔案。M3U檔案是記錄了一個索引純文字檔案,打開它時播放軟體并不是播放它,而是根據它的索引找到對應的音視訊檔案的網絡位址進行線上播放。
M3U8檔案舉例,例如使用雲圖TV點播直播節目時,發送請求:
http://121.199.63.236:7613/m3u8/cckw1/szws.m3u8?
看到沒,其實蘋果的點播就是http上直接通路。
4、實作過程和思路:
設定存ts,m3u8的路徑,輸入h264和aac流,根據設定的ts長度和個數,不斷更新ts檔案和m3u8檔案
說了這麼多基礎,來點實際的吧:
我封裝的最後的接口函數:
void StartHLS(CString szPath,CString szName="xiao");//開始啟動hls,路徑為儲存m3u8和ts的路徑
void SetAudioProperty(int channels, int samplerate, int bitspersample);
void SetVideoProperty(int width, int height, double framerate);
void StopHLS(void);
void H264In(BYTE* pH264, LONG nH264Len, LONG nTimeStamp=0);
void AACIn(BYTE* pAAC, LONG nAACLen, LONG nTimeStamp=0);
調用ffmpeg的步驟:
av_register_all();
定義幾個全局的:
AVFormatContext* output_format_context;//輸出檔案結構上下文
AVStream* o_video_stream ;
AVStream *o_audio_stream ;
輸入h264關鍵幀:
通過關鍵幀擷取視訊資訊并
avio_alloc_context(這個函數很多文章或者代碼裡面都沒有提到過吧),生成一個自定義輸入io,用來探測h264的格式
//讀入資料avformat_open_input
//設定輸入結構體資訊
avformat_find_stream_info
//設定輸出檔案格式資訊
avformat_alloc_output_context2
//打開輸出檔案
avio_open
//添加音視訊流
avformat_new_stream
//寫入頭
av_dump_format、avformat_write_header
至此,檔案初始化工作完成
接下來寫資料啦
av_packet_from_data、av_packet_rescale_ts、av_interleaved_write_frame、av_write_trailer
最後記得釋放
avio_close、avformat_free_context
完了,搞完收工!!!!!!看看效果
中間有很多困擾:枚舉下:比如ts檔案格式必須輸入的aac為 ADTS編碼的,即有7個位元組的頭,沒有就别想播放。
音視訊同步,主要還是通過音視訊時間戳pts,dts同步的。m3u8及ts檔案更新,根據設定的一個ts檔案秒數和個數進行不斷更新,比如設定的5秒一個,一共3個,那麼,每隔3秒,儲存ts并建立新的ts,然後更新m3u8檔案資訊.
我的m3u8檔案内容:
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:103
#EXTINF:10,
xiao-103.ts
#EXTINF:10,
xiao-104.ts
#EXTINF:10,
xiao-105.ts
測試的時候,裝備一台蘋果手機(腎沒了沒辦法就下載下傳個VLC播放器也行),一個免費的http伺服器軟體,我下的免費的easywebserver。準備h264資料源和AAC資料源,這方面辦法很多,讀h264,aac檔案,截取螢幕或者攝像頭,aac擷取麥克風轉成AAC,或者輸入音頻檔案轉成AAC(編碼一定要有 ADTS 頭啊,切記切記)
但是上面說了這麼多,應該也能自己做了吧。什麼時候傳個DEMO上來,有空再說吧
傳點代碼(關鍵的一段):
[cpp] view plain copy
[cpp] view plain copy
- void CHLSSend::H264In(BYTE* pH264, LONG nH264Len, LONG nTimeStamp)
- {
- MP4ENC_NaluUnit nalu;
- int pos = 0, len = 0;
- bool bKeyFrame=false;
- while (len = ReadOneNaluFromBuf((const unsigned char *)pH264,nH264Len,pos,nalu))
- {
- if(nalu.type==0x05)
- {
- bKeyFrame=true;
- break;
- }
- pos += len;
- }
- if(bKeyFrame)
- {
- try
- {
- s_write_file_head(pH264, nH264Len);
- }
- catch(...)
- {
- TRACE("寫入檔案頭異常!\n");
- isfirst=true;
- return;
- }
- }
- if (isfirst)
- return;
- if(nTimeStamp==0)
- nTimeStamp=::GetTickCount();
- if(m_bFirstVideo)
- {
- m_uFirstVideo=nTimeStamp;
- m_u64VideoPTS = nTimeStamp;
- m_bFirstVideo=false;
- }
- AVPacket pkt;
- av_init_packet(&pkt);
- uint8_t* avdata = (uint8_t*)av_malloc(nH264Len + AV_INPUT_BUFFER_PADDING_SIZE);
- memcpy(avdata, pH264, nH264Len);
- //
- int iiiii = av_packet_from_data(&pkt, (uint8_t*)avdata, nH264Len);
- if (iiiii == 0)
- {
- Lock.Lock();
- int pts=PTS2TIME_SCALE(nTimeStamp, m_uFirstVideo, m_fps);
- //TRACE("視訊時間:%0.2f 視訊時間2: %d\n",(double)pts*1000/(double)m_fps,(m_nVideoCount));
- pkt.pts = (m_nVideoCount++);//音頻幀率=48000/1024 視訊幀率:30=30*1024/1024
- pkt.dts = pkt.pts;
- av_packet_rescale_ts(&pkt, o_video_stream->codec->time_base, o_video_stream->time_base);
- pkt.stream_index = o_video_stream->index;
- pkt.duration = 1;
- pkt.pos = -1;
- if(bKeyFrame)
- pkt.flags |= AV_PKT_FLAG_KEY;
- int result = av_interleaved_write_frame(output_format_context, &pkt);
- if(result!=0)
- {
- printf("fail2\n");
- //MessageBox(0,"111",0,MB_OK);
- }
- //判斷一個TS是否完成
- m_nOneTsTime=GetVideoTime(m_nVideoCount);
- int current_segment_duration = (int)(m_nOneTsTime-m_nFirstTime + 0.5);
- //actual_segment_durations[last_segment] = (current_segment_duration > 0 ? current_segment_duration: 1);
- if(m_nOneTsTime-m_nFirstTime>=ONETSLEN)//
- {
- StopWriteAndNewTs();
- m_nFirstTime=m_nOneTsTime;//第一次檔案寫入時間
- TRACE("10秒到,寫入檔案并建立新檔案\n");
- }
- Lock.Unlock();
- }
- else
- {
- printf("fail\n");
- //MessageBox(0,"222",0,MB_OK);
- }
- av_free_packet(&pkt);//他會把buff清理掉
- }
今天花了2個小時把DEMO做好了,可以下載下傳看看效果,有問題或者需要交流,可以聯系我,謝謝(前面一個是v2版本,後面是v1版本)
http://download.csdn.net/download/xjb2006/10119982
http://download.csdn.net/download/xjb2006/10106146
*需要合作的聯系QQ35744025,可以當當技術顧問或者核心技術提供,本人03年從事工作,“精通”音視訊應用程式設計技術(勉強加個精通,吸引眼球,哈哈),精通VC,MFC,多媒體教學軟體,錄播軟體,直播軟體的核心技術大部分已掌握,如ffmpeg技術,Directshow技術,MP4,FLV編碼合成,H264,AAC,MP3,可以運用IPP進行高效圖像空間轉換等,可以運用INTEL和cuda進行硬體H264編解碼,可以實作240幀1080P實時編碼,完全同步及平滑度極高,rtmp,HLS直播推送,rtmp伺服器,YV12,YUV422,NV12,RGB24,RGB32熟悉轉換,縮放,wav,AAC, mp3的編碼解碼,視訊切換特效算法,視訊水印,LOGO,文字。螢幕截取錄像,攝像頭捕獲錄像,D3D高效視訊圖像顯示,OPENCV,圖像庫ximage,GDI,GDIPLUS熟練應用,語音識别及文字轉換,人臉識别及比對,區域網路内遠端控制,音視訊實時通話,聲霸卡捕獲回放等,另外SQL資料庫,ACCESS,EXCEL資料庫,DOC,PDF檔案打開提取,FTPServer,Client,以上所有代碼均已商用。