操作系統與網絡 2019-4-19

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

// strcpy_s(ssr.m_szName, sizeof(ssr.m_szName), m_name);
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章