最近一段時間一直在研究怎么將接收到的H264幀數(shù)據(jù),,存為一個FLV文件,初步的想法是用ffmpeg提供的開源庫來實現(xiàn),,但因為之前一直沒接觸過這個,,具體怎么做還是一籌莫展,各位前輩有沒有之前做過這個
的,,提供一些經(jīng)驗唄?。。?br>
或者不用ffmpeg,,有別的方案也行,,但在轉換效率以及穩(wěn)定性上要求很高,因為這是服務器上要做的功能,,而且數(shù)據(jù)量會特別龐大,。。,。,。。 |
|
|
|
|
|
|
- 帖子
- 3349
- 主題
- 256
- 精華
- 2
- 可用積分
- 17557
- 專家積分
- 40
- 在線時間
- 3586 小時
- 注冊時間
- 2005-09-14
- 最后登錄
- 2014-04-04
- 論壇徽章:
- 1
|
靠,, 這個我作過,, FLV 的文件格式非常簡單, 直接找 adobe 的說明,, 照著寫就行了 |
|
授我以魚,, 不要授我以漁
找工作, linux 系統(tǒng)編程,, 服務器編程
30K 左右
|
|
|
|
|
- 帖子
- 12
- 主題
- 2
- 精華
- 0
- 可用積分
- 27
- 專家積分
- 0
- 在線時間
- 67 小時
- 注冊時間
- 2011-08-24
- 最后登錄
- 2014-03-12
- 論壇徽章:
- 0
|
是不是直接就拿H264的幀往flv的tag里面放,,然后那些header自己根據(jù)幀的信息去構造?。?!照這么說,,ffmpeg豈不根本用不到了啊?。,。?/td> |
|
|
|
|
|
|
- 帖子
- 1321
- 主題
- 81
- 精華
- 0
- 可用積分
- 502
- 專家積分
- 10
- 在線時間
- 2030 小時
- 注冊時間
- 2008-07-16
- 最后登錄
- 2014-03-10
- 論壇徽章:
- 0
|
|
|
|
|
|
|
小書僮
- 帖子
- 393
- 主題
- 12
- 精華
- 0
- 可用積分
- 2067
- 專家積分
- 0
- 在線時間
- 1665 小時
- 注冊時間
- 2009-03-30
- 最后登錄
- 2013-11-29
- 論壇徽章:
- 0
|
一個是壓縮算法,,一個是存儲格式,。你要是只保持成文件,按格式存就是了,。
不解碼的話,,應該不涉及ffmpeg。 |
|
強身健體
|
|
|
|
|
- 帖子
- 3349
- 主題
- 256
- 精華
- 2
- 可用積分
- 17557
- 專家積分
- 40
- 在線時間
- 3586 小時
- 注冊時間
- 2005-09-14
- 最后登錄
- 2014-04-04
- 論壇徽章:
- 1
|
本帖最后由 zylthinking 于 2011-10-19 11:08 編輯
那我也不賣漁了,, 摘些代碼- static char* g_lastKeyFrame = NULL;
- static int g_keyfrm_buf = 0;
- static int g_keyfrm_len = 0;
- int FlvSaveKeyFrame(void* data, int len){
- if(len > g_keyfrm_buf){
- free(g_lastKeyFrame);
- g_lastKeyFrame = (char *) malloc(len);
- if(g_lastKeyFrame == NULL){
- g_keyfrm_len = 0;
- return -1;
- }
- g_keyfrm_buf = len;
- }
- g_keyfrm_len = len;
- if(len > 0){
- memcpy(g_lastKeyFrame, data, g_keyfrm_len);
- }
- return 0;
- }
- int FlvGetLastKeyFrame(char*& buf){
- buf = g_lastKeyFrame;
- return g_keyfrm_len;
- }
- static char* g_sps_buf = NULL;
- static int g_sps_buf_len = 0;
- static int g_sps_len = 0;
- int FlvSaveSpsFrame(void* data, int len){
- if(len > g_sps_buf_len){
- free(g_sps_buf);
- g_sps_buf = (char *) malloc(len);
- if(g_sps_buf == NULL){
- g_sps_buf_len = 0;
- return -1;
- }
- g_sps_buf_len = len;
- }
- g_sps_len = len;
- if(len > 0){
- memcpy(g_sps_buf, data, g_sps_len);
- }
- return 0;
- }
- int FlvGetSpsFrame(char*& buf){
- buf = g_sps_buf;
- return g_sps_len;
- }
- static char* g_aac_buf = NULL;
- static int g_aac_buf_len = 0;
- static int g_aac_len = 0;
- int FlvSaveAacFrame(void* data, int len){
- if(len > g_aac_buf_len){
- free(g_aac_buf);
- g_aac_buf = (char *) malloc(len);
- if(g_aac_buf == NULL){
- g_aac_buf_len = 0;
- return -1;
- }
- g_aac_buf_len = len;
- }
- g_aac_len = len;
- if(len > 0){
- memcpy(g_aac_buf, data, g_aac_len);
- }
- return 0;
- }
- int FlvGetAacFrame(char*& buf){
- buf = g_aac_buf;
- return g_aac_len;
- }
- typedef int (*type_parser)(const char* flv_buffer, media_info& info);
- struct flv_media_parser{
- DWORD fourcc;
- type_parser parser;
- };
- //=========================================================
- // stupid compiler
- static void my_free(void* addr){
- free(addr);
- }
- static int h264_parser(const char* flv_buffer, media_info& info){
- info.bit_count = 0;
- info.extra = 1;
- int byte1 = ((int) flv_buffer[1]) & 0xff;
- int byte2 = ((int) flv_buffer[2]) & 0xff;
- int byte3 = ((int) flv_buffer[3]) & 0xff;
- DWORD len = (byte1 << 16) | (byte2 << 8) | byte3;
- int byte4 = ((int) flv_buffer[4]) & 0xff;
- int byte5 = ((int) flv_buffer[5]) & 0xff;
- int byte6 = ((int) flv_buffer[6]) & 0xff;
- int byte7 = ((int) flv_buffer[7]) & 0xff;
- int byte13 = ((int) flv_buffer[13]) & 0xff;
- int byte14 = ((int) flv_buffer[14]) & 0xff;
- int byte15 = ((int) flv_buffer[15]) & 0xff;
- info.dts = (byte7 << 24) | (byte4 << 16) | (byte5 << 8) | byte6;
- int offset = (byte13 << 16) | (byte14 << 8) | byte15;
- info.pts = info.dts + offset;
- int byte12 = ((int) flv_buffer[12]) & 0xff;
- if(byte12 == 0){
- int sps_len = 0;
- int pps_len = 0;
- const char* sps = NULL;
- const char* pps = NULL;
- int nr_sps = ((int) flv_buffer[21]) & 0x1f;
- if(nr_sps == 1){
- int byte22 = ((int) flv_buffer[22]) & 0xff;
- int byte23 = ((int) flv_buffer[23]) & 0xff;
- sps_len = (byte22 << 8) | byte23;
- sps = &flv_buffer[24];
- pps = sps + sps_len;
- sps_len += 4;
- }else{
- // no more than 1 sps currently
- assert(nr_sps == 0);
- }
- int nr_pps = pps[0] & 0xff;
- if(nr_pps == 1){
- int byte1 = ((int) pps[1]) & 0xff;
- int byte2 = ((int) pps[2]) & 0xff;
- pps_len = ((byte1 << 8) | byte2) + 4;
- pps = &pps[3];
- }else{
- pps = NULL;
- // no more than 1 pps currently
- assert(nr_pps == 0);
- }
- int header_len = sps_len + pps_len;
- assert(header_len > 0);
- unsigned char* buffer = (unsigned char *) malloc(header_len);
- if(buffer == NULL){
- return -1;
- }
- info.free = my_free;
- info.length = header_len;
- info.buffer = (char *) buffer;
- if(sps_len > 0){
- sps_len -= 4;
- buffer[0] = sps_len >> 24;
- buffer[1] = sps_len >> 16;
- buffer[2] = sps_len >> 8;
- buffer[3] = sps_len;
- buffer += 4;
- memcpy(buffer, sps, sps_len);
- buffer += sps_len;
- }
- if(pps_len > 0){
- pps_len -= 4;
- buffer[0] = pps_len >> 24;
- buffer[1] = pps_len >> 16;
- buffer[2] = pps_len >> 8;
- buffer[3] = pps_len;
- buffer += 4;
- memcpy(buffer, pps, pps_len);
- buffer += pps_len;
- }
- return len + 11 + 4;
- }else if(byte12 == 1){
- info.length = len - 5;
- info.buffer = (char *) &flv_buffer[16];
- return len + 11 + 4;
- }
- return -1;
- }
- static flv_media_parser flv_h264_parser = {
- make_fourcc('H', '2', '6', '4'),
- h264_parser
- };
- static flv_media_parser* video_parser_of(char codec_id){
- if(codec_id == (char) 0x07){
- return &flv_h264_parser;
- }
- return NULL;
- }
- static int flv_video_unpack(const char* flv_buffer, media_info& info){
- char byte11 = flv_buffer[11] & 0xff;
- BOOL key_frame = (0x10 == (byte11 & 0xf0));
- int codec_id = (byte11 & 0x0f);
- flv_media_parser* parser = video_parser_of(codec_id);
- if(parser == NULL){
- return -1;
- }
- info.fourcc = parser->fourcc;
- return parser->parser(flv_buffer, info);
- }
- //=========================================================
- static char adts[7] = {0xff, 0xf1};
- static int aac_parser(const char* flv_buffer, media_info& info){
- int byte1 = ((int) flv_buffer[1]) & 0xff;
- int byte2 = ((int) flv_buffer[2]) & 0xff;
- int byte3 = ((int) flv_buffer[3]) & 0xff;
- DWORD len = (byte1 << 16) | (byte2 << 8) | byte3;
- int byte4 = ((int) flv_buffer[4]) & 0xff;
- int byte5 = ((int) flv_buffer[5]) & 0xff;
- int byte6 = ((int) flv_buffer[6]) & 0xff;
- int byte7 = ((int) flv_buffer[7]) & 0xff;
- info.dts = (byte7 << 24) | (byte4 << 16) | (byte5 << 8) | byte6;
- info.pts = info.dts;
- // flash only support 44k, 16bits aac
- info.sample_rate = 44100;
- info.bit_count = 16;
- info.chans = (flv_buffer[11] & 0x01) ? 2 : 1;
-
- int type = ((int) flv_buffer[12]) & 0xff;
- if(type == 0){
- int byte13 = ((int) flv_buffer[13]) & 0xff;
- int objType = ((byte13 & 0xf1) >> 3) - 1;
- int byte14 = ((int) flv_buffer[14]) & 0xff;
- int samplerate_indx = ((byte13 & 0x7) << 1 | (byte14 & 0x80) >> 7);
- int chans = (byte14 & 0x71) >> 3;
- // format of flash
- assert(chans == 2 && samplerate_indx == 7);
- adts[2] = (objType << 6) | (samplerate_indx << 2) | ((chans & 0x04) >> 2);
- adts[3] = ((chans & 0x03) << 6);
- return len + 11 + 4;
- }else if(type == 1){
- if(adts[2] == 0){
- cs << "drop audio data, because of header is missing" << endl;
- goto LABEL;
- }
- const static int adts_len = sizeof(adts);
- info.length = len - 2 + adts_len;
- info.buffer = (char *) malloc(info.length);
- if(info.buffer == NULL){
- return -1;
- }
- info.free = my_free;
- assert(sizeof(int) == 4);
- *((int *) &info.buffer[0]) = *((int *) &adts[0]);
- info.buffer[3] |= (info.length & 0x1fff) >> 11;
- info.buffer[4] = (info.length & 0x7ff) >> 3;
- info.buffer[5] = (info.length & 0x07) << 5;
- info.buffer[5] |= 0x1f;
- info.buffer[6] = 0xfc;
- memcpy((void *) &info.buffer[adts_len], &flv_buffer[13], len - 2);
- LABEL:
- return len + 11 + 4;
- }
- return -1;
- }
- static flv_media_parser flv_aac_parser = {
- mpeg4_aac,
- aac_parser
- };
- static flv_media_parser* audio_parser_of(char codec_id){
- if(codec_id == (char) 0xa0){
- return &flv_aac_parser;
- }
- return NULL;
- }
- static int flv_audio_unpack(const char* flv_buffer, media_info& info){
- char byte11 = flv_buffer[11] & 0xff;
- char fmt = byte11 & 0xf0;
- flv_media_parser* parser = audio_parser_of(fmt);
- if(parser == NULL){
- return -1;
- }
- info.fourcc = parser->fourcc;
- return parser->parser(flv_buffer, info);
- }
- //=========================================================
- int FlvUnpack(const char* flv_buffer, media_info& info){
- info.free = NULL;
- info.buffer = NULL;
- info.length = 0;
- int n = -1;
- char audio_or_video = flv_buffer[0];
- if(audio_or_video == 0x09){
- n = flv_video_unpack(flv_buffer, info);
- if(n != -1){
- if(FlvIsSpsFrame((BYTE *) flv_buffer, n)){
- FlvSaveSpsFrame((void *) flv_buffer, n);
- }else if(FlvIsKeyFrame((BYTE *) flv_buffer, n)){
- FlvSaveKeyFrame((void *) flv_buffer, n);
- }
- }
- }
-
- if(audio_or_video == 0x08){
- n = flv_audio_unpack(flv_buffer,info);
- if(n != -1){
- if(FlvIsAacHeaderFrame((BYTE *) flv_buffer, n)){
- FlvSaveAacFrame((void *) flv_buffer, n);
- }
- }
- }
- return n;
- }
- BOOL FlvIsKeyFrame(BYTE* flv_buffer, int len){
- if(len < 12 || flv_buffer[0] != 0x09){
- return FALSE;
- }
- return (0x10 == (flv_buffer[11] & 0xf0));
- }
- BOOL FlvIsSpsFrame(BYTE* flv_buffer, int len){
- if(len < 13 || flv_buffer[0] != 0x09){
- return FALSE;
- }
- return (0 == (flv_buffer[12]));
- }
- BOOL FlvIsAacHeaderFrame(BYTE* flv_buffer, int len){
- if(len < 13 || flv_buffer[0] != 0x08){
- return FALSE;
- }
- return (0 == (flv_buffer[12]));
- }
- int FlvFrameLength(BYTE* flv_buffer, int len){
- if(len < 4){
- return -1;
- }
- int byte1 = ((int) flv_buffer[1]) & 0xff;
- int byte2 = ((int) flv_buffer[2]) & 0xff;
- int byte3 = ((int) flv_buffer[3]) & 0xff;
- int length = (byte1 << 16) | (byte2 << 8) | byte3;
- length += 11 + 4;
- if(length <= len){
- return length;
- }
- return -1;
- }
- DWORD FlvGetDts(BYTE* flv_buffer, int len){
- if(len < 8){
- return (DWORD) (-1);
- }
- int byte4 = ((int) flv_buffer[4]) & 0xff;
- int byte5 = ((int) flv_buffer[5]) & 0xff;
- int byte6 = ((int) flv_buffer[6]) & 0xff;
- int byte7 = ((int) flv_buffer[7]) & 0xff;
- DWORD st = (byte7 << 24) | (byte4 << 16) | (byte5 << 8) | byte6;
- return st;
- }
- void FlvSetDts(UINT32 ts, void* buf, int len, BOOL zeroOffset){
- int left = len;
- char* pch = (char *) buf;
- while(left > 0){
- int n1 = pch[1] & 0xff;
- int n2 = pch[2] & 0xff;
- int n3 = pch[3] & 0xff;
- int n = (n1 << 16) | (n2 << 8) | n3;
- *((char*)pch + 4) = (unsigned char) (ts >> 16);
- *((char*)pch + 5) = (unsigned char) (ts >> 8);
- *((char*)pch + 6) = (unsigned char) ts;
- *((char*)pch + 7) = (unsigned char) (ts >> 24);
- if(zeroOffset){
- *((char*)pch + 13) = 0;
- *((char*)pch + 14) = 0;
- *((char*)pch + 15) = 0;
- }
-
- pch += (n + 11 + 4);
- left -= (n + 11 + 4);
- }
- assert(left == 0);
- }
- int FlvMediaType(const char* flv_buffer, int len){
- if(len < 1){
- goto LABEL;
- }
- if(flv_buffer[0] == 0x09){
- return media_video;
- }else if(flv_buffer[0] == 0x08){
- return media_audio;
- }
- LABEL:
- assert(false);
- return media_none;
- }
- int FlvTagBytes(int* head, int* tail){
- if(head) *head = 11;
- if(tail) *tail = 4;
- return 15;
- }
- const static BYTE hdrflvout[] = {
- 0x46,0x4C,0x56,0x01,0x05,0x00,0x00,0x00,0x09,
- 0x00,0x00,0x00,0x00,
- };
- CFlvWrite::CFlvWrite(void){
- m_bOk = FALSE;
- m_hFile = NULL;
- m_need_sps = TRUE;
- m_need_kfrm = TRUE;
- m_need_aach = TRUE;
- m_base_tick_video = 0;
- m_base_tick_audio = 0;
- }
- CFlvWrite::~CFlvWrite(void){
- Close();
- }
- HRESULT CFlvWrite::Open(LPCTSTR szOutName, LPCTSTR szExtParam){
- if(m_bOk)
- return S_OK; //已經(jīng)打開
- m_bOk = FALSE;
- m_hFile = _tfopen(szOutName, _T("wb"));
- if( m_hFile <= 0)
- return E_FAIL;
- fwrite(hdrflvout, sizeof(hdrflvout), 1, m_hFile);
- m_bOk = TRUE;
- return S_OK;
- }
- HRESULT CFlvWrite::Write(BYTE* ppData, int nLen){
- SingleLock l(m_cs);
- if(!m_bOk){
- return E_FAIL;
- }
- if(m_hFile == NULL){
- ASSERT(FALSE);
- return E_FAIL;
- }
- int sps_len = 0;
- char* sps_buf;
- if(m_need_sps){
- sps_len = FlvGetSpsFrame(sps_buf);
- }
- int keyframe_len = 0;
- char* kfrm_buf;
- if(m_need_kfrm){
- keyframe_len = FlvGetLastKeyFrame(kfrm_buf);
- }
- int aac_len = 0;
- char* aac_buf;
- if(m_need_aach){
- aac_len = FlvGetAacFrame(aac_buf);
- }
- while(nLen > 0){
- int len = FlvFrameLength(ppData, nLen);
- ASSERT(len != -1);
- int type = FlvMediaType((const char *) ppData, len);
- ASSERT(type != media_none);
- if(type == media_audio){
- if(m_need_aach){
- BOOL aach = FlvIsAacHeaderFrame(ppData, len);
- if(aach){
- m_need_aach = FALSE;
- FlvSetDts(0, ppData, len, FALSE);
- fwrite(ppData, 1, len, m_hFile);
- goto LABEL;
- }else if(aac_len){
- FlvSetDts(0, aac_buf, aac_len, FALSE);
- fwrite(aac_buf, 1, aac_len, m_hFile);
- m_need_aach = FALSE;
- }else{
- goto LABEL;
- }
- }
- ASSERT(!m_need_aach);
- DWORD ts = FlvGetDts(ppData, len);
- if(m_base_tick_audio == 0){
- m_base_tick_audio = ts;
- }
- FlvSetDts(ts - m_base_tick_audio, ppData, len, FALSE);
- fwrite(ppData, 1, len, m_hFile);
- }else{
- BOOL sps = FlvIsSpsFrame(ppData, len);
- if(sps){
- FlvSetDts(0, ppData, len, TRUE);
- fwrite(ppData, 1, len, m_hFile);
- m_need_sps = FALSE;
- goto LABEL;
- }
-
- if(m_need_sps){
- if(sps_len == 0){
- goto LABEL;
- }
- FlvSetDts(0, sps_buf, sps_len, TRUE);
- fwrite(sps_buf, 1, sps_len, m_hFile);
- m_need_sps = FALSE;
- }
- DWORD ts = FlvGetDts(ppData, len);
- if(m_base_tick_video == 0){
- m_base_tick_video = ts;
- }
- if(FlvIsKeyFrame(ppData, len)){
- m_need_kfrm = FALSE;
- }else if(m_need_kfrm){
- if(keyframe_len == 0){
- goto LABEL;
- }
- FlvSetDts(0, kfrm_buf, keyframe_len, TRUE);
- fwrite(kfrm_buf, 1, keyframe_len, m_hFile);
- m_need_kfrm = FALSE;
- }
- FlvSetDts(ts - m_base_tick_video, ppData, len, FALSE);
- fwrite(ppData, 1, len, m_hFile);
- }
- LABEL:
- ppData += len;
- nLen -= len;
- }
- return S_OK;
- }
- HRESULT CFlvWrite::Close(){
- if(m_hFile){
- fclose(m_hFile);
- }
- m_base_tick_video = m_base_tick_audio = 0;
- m_need_aach = m_need_sps = m_need_kfrm = TRUE;
- m_hFile = NULL;
- m_bOk = FALSE;
- return S_OK;
- }
復制代碼 |
|
授我以魚,, 不要授我以漁
找工作,, linux 系統(tǒng)編程,, 服務器編程
30K 左右
|
|
|
|
|
- 帖子
- 3748
- 主題
- 583
- 精華
- 0
- 可用積分
- 7912
- 專家積分
- 0
- 在線時間
- 2409 小時
- 注冊時間
- 2008-08-15
- 最后登錄
- 2013-09-19
- 論壇徽章:
- 0
|
貌似能實現(xiàn)無限長度的視頻會議,!Great,!我需要! |
|
|
|
|
|
|
- 帖子
- 12
- 主題
- 2
- 精華
- 0
- 可用積分
- 27
- 專家積分
- 0
- 在線時間
- 67 小時
- 注冊時間
- 2011-08-24
- 最后登錄
- 2014-03-12
- 論壇徽章:
- 0
|
感謝各位,,我們公司就是做網(wǎng)絡會議的,不過我正在做的是會后的一個附加功能,,提供會議的錄制,要求對于會
中當中的視頻數(shù)據(jù),,音頻數(shù)據(jù)等,。最后全部整合成一個文件,,支持會后回放,。我也就是一個新手,今年剛畢業(yè)
的,,在這邊也基本上給前輩打打下手,,以后不懂得地方還得請各位多多關照!?。?/td> |
|
|
|