1.添加部分新文件
1.1 給 DlgMain 對話框上添加兩個按鈕: 開始直播 按鈕和 停止直播 按鈕
1.2 本次直播項目中使用的是 FFMPEG 來處理視頻,視頻是通過 h264 進行編碼的(進行編碼的原因是每一幀圖像較大,每秒想發送25幀圖像,因此佔用的網絡資源較大,需要編碼進行減小佔用的網絡資源)
1.3 本次直播項目中使用的是 WSAAPI 獲取音頻,並將音頻進行 aac 編碼
1.4 將圖像與音頻都進行編碼之後將這兩個編碼爲 mp4 文件,這其中涉及到 時間戳的對齊
1.5 將下載的文件放到項目中,將 dll 文件放到 Debug 目錄下
1.6 添加一個新的篩選器 FFMPEG ,用來放 FFMPEG 相關的文件
1.7 添加庫目錄: …/lib;
1.8 添加附加依賴項,將下列語句添加到 附加依賴項 中
SDL2main.lib
SDL2.lib
avcodec.lib
avdevice.lib
avfilter.lib
swscale.lib
avformat.lib
avutil.lib
postproc.lib
swresample.lib
2.更改錯誤
2.1 新添加的文件需要 附加包含目錄 : …/;
2.2 將項目的字符集更改爲 Unicode (因爲FFMPEG的默認編碼形式爲 Unicode)
2.3 將所有有關字符串操作的更改爲 Unicode 相關的,將所有 strcpy_s 全部改爲 WideCharToMultiByte ,將所有字符串全部改爲 TCHAR
WideCharToMultiByte(CP_ACP, 0, m_name, -1, ssr.m_szName, sizeof(ssr.m_szName), 0, 0);
2.4 查看自己的攝像頭的名稱,在 Myffmpeg.cpp 中更改過來
void Myffmpeg::Factory(bool desk,bool camera,bool audio,bool microphone)
{
if(desk == true && m_pDesktop == NULL)
{
m_pDesktop = new MyCollectDesktop(this);
m_pDesktop->Initial();
}
if(audio == true && m_pAudio == NULL)
{
m_pAudio = new CCollectAudio(this);
m_pAudio->Initial();
}
if(camera == true && m_pCamera == NULL)
{
m_pCamera = new CCollectCamera(_T("video=Lenovo EasyCamera"));
m_pCamera->Start();
}
}
3.完成DlgMain對話框
3.1 在對話框上添加三個check控件: 攝像頭、桌面、聲卡;添加一個 設置參數 按鈕;
3.2 給三個check控件添加三個變量,類型都是 value BOOL 型: m_b_camera 、 m_b_desktop 、 m_b_voice ;
3.3 在 DlgMain 類中添加一個 FFMPEG 類對象,用來獲取攝像頭數據: Myffmpeg m_ffmpeg ;
3.4 在 設置參數 按鈕中,獲取控件上選中的check信息,使用ffmpeg調用工廠模式;
- 1.我這裏由於直接使用了新建對話框上面的按鈕,因此這裏的函數名爲 OnBnClickedOk ,應該爲 OnBnClickedButton 這種類型,請大家自己修改;
void CDlgMain::OnBnClickedOk()
{
UpdateData(TRUE);
m_ffmpeg.Factory(m_b_desktop, m_b_camera, m_b_voice);
}
3.5 添加一個 開始直播 按鈕
- 1.在這個按鈕中我們需要用 m_ffmpeg 對象來調用其中的 SetStart 函數;
void CDlgMain::OnBnClickedButton1()
{
m_ffmpeg.SetStart(m_b_desktop, m_b_camera, m_b_voice);
}
3.6 在項目目錄下新建一個 TempFile 文件夾,用來存儲生成的 mp4 文件
3.7 註釋掉 MyCollectDesktop::CollectDesktop 中的 ((TCPKernel*)theApp.m_p_kernel)->SendFileData(szPath,szFileName) 這行代碼,即可將攝像頭顯示到對話框上
4.完成 TCPKernel 類
4.1 給 TCPKernel 類添加一個 SendFileData 函數,用來發送文件信息,這個函數已經被寫好了,直接使用(也需自己看一遍,理解一下)
bool TCPKernel::SendFileData(char* szpath, char* szFileName)
{
FILE *pFile = NULL;
fopen_s(&pFile,szpath,"rb");
if(pFile == NULL)
return false;
fseek(pFile,0,SEEK_END);
int nFileSize = ftell(pFile);
fseek(pFile,0,SEEK_SET);
STRU_UPLOADFILE su;
su.m_n_type = _DEF_PROTOCOL_STREAMINFO_RQ;
WideCharToMultiByte(CP_ACP,0,((CDlgMain*)theApp.m_pMainWnd)->m_name,-1,su.m_sz_name,sizeof(su.m_sz_name),0,0);
strcpy_s(su.m_sz_content,sizeof(su.m_sz_content),szFileName);
su.m_n_len = nFileSize;
SendData((char*)&su,sizeof(su));
while(1)
{
su.m_n_type = _DEF_PROTOCOL_STREAMCONNECT_RQ;
su.m_n_len = fread_s(su.m_sz_content,sizeof(su.m_sz_content),sizeof(char),sizeof(su.m_sz_content),pFile);
if(su.m_n_len==0)
{
break;
}
SendData((char*)&su,sizeof(su));
}
fclose(pFile);
return true;
}
4.2 在 PackDef.h 中添加一個結構體聲明,這個結構體用來存放發送的文件的信息
#define MAX_CONTENTNUM 300
struct STRU_UPLOADFILE
{
PackType m_n_type;
char m_sz_name[DEF_SIZE];
char m_sz_content[MAX_CONTENTNUM];
int m_n_len;
}
4.3 將之前註釋掉的 MyCollectDesktop::CollectDesktop 裏的 ((TCPKernel*)theApp.m_p_kernel)->SendFileData(szPath,szFileName) 取消註釋
5.繼續 開始直播 按鈕
5.1 完成按鈕響應函數
- 1.首先使用 m_ffmpeg 對象調用 SetStart 函數(之前已寫);
- 2.定義一個 開始傳送 的結構體對象;
- 3.給這個結構體賦值;
- 4.使用 Kernel 進行發送數據包;
void CDlgMain::OnBnClickedButton1()
{
m_ffmpeg.SetStart(m_b_desktop, m_b_camera, m_b_voice);
STRU_STARTTRANSFER_RQ ssr;
ssr.m_nType = _DEF_PROTOCOL_STARTTRANSFER_RQ;
WideCharToMultiByte(CP_ACP, 0, m_name, -1, ssr.m_szName, sizeof(ssr.m_szName), 0, 0);
theApp.m_p_kernel->SendData((char*)&ssr, sizeof(ssr));
}
5.2 給服務器端添加四個函數: StartTransferRq 、 StreamInfoRq 、 StreamContentRq 、 SelectAuthor 函數;
bool TCPKernel::StartTransferRq(SOCKET sock,char* szbuf)
{
return true;
}
bool TCPKernel::StreamInfoRq(SOCKET sock,char* szbuf)
{
return true;
}
bool TCPKernel::StreamContentRq(SOCKET sock,char* szbuf)
{
return true;
}
bool TCPKernel::SelectAuthorRq(SOCKET sock,char* szbuf)
{
return true;
}