該文章敘述的一些問題,主要偏windows方面,不著重與linux的比較,接續在如何用vs08編譯ffmpeg這件事情之後。內容大多搜集於網上,為轉載。
————————————————————————————————————————————————————
這篇文章列舉了些資料結構與介面的相關:windows下網路編程筆記之linux到windows程式移植
————————————————————————————————————————————————————
1. 小問題,其實也不是網路技術問題了:if ((int)fds[i].fd > n),條件真還是假(int n = -1;)?
看看linux下pollfd結構的定義:
struct pollfd { int fd; /* file des to poll */ short events; /* events to look for */ short revents; /* events that occurred */};
看看windows下pollfd結構的定義:
typedef struct pollfd { SOCKET fd; SHORT events; SHORT revents;} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD;
typedef UINT_PTR SOCKET;
類型不符,導致的隱式轉換,在windows下,題中的條件運算式基本恒為真。
2. WSAStartup函數
int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData);
3. ffmpeg代碼中getaddrinfo函數的使用
#if defined(_WIN32){int (WSAAPI *win_getaddrinfo)(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);char moduleName[36] = {0};int num_chars = 0;wchar_t moduleName_w[36] = {0};snprintf(moduleName, sizeof(moduleName), "ws2_32.dll");///* convert UTF-8 to wide chars */num_chars = MultiByteToWideChar(CP_UTF8, 0, moduleName, -1, NULL, 0);if (num_chars <= 0)return -1;MultiByteToWideChar(CP_UTF8, 0, moduleName, -1, moduleName_w, num_chars);HMODULE ws2mod = GetModuleHandle((const WCHAR *)moduleName_w);win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo");if (win_getaddrinfo)return win_getaddrinfo(node, service, hints, res);}#endif
4. 在ioctlsocket設定非阻塞之後,connect 10035(WSAEWOULDBLOCK)錯誤?
可參考:connect 10035錯誤
“non blocking模式,connect不會等到成功,而是馬上返回。你需要再select()來判斷成功與否。
for (i = 0; i < TotalSockets; i++)
FD_SET(SocketArray[i]->Socket, &ReadSet);
if ((Total = select(0, &ReadSet, NULL, NULL, NULL)) == SOCKET_ERROR)
{
printf("select() returned with error %d\n", WSAGetLastError());
return;
}”
“10035不是錯誤。改變為nonblock模式後第一個改變的觀念就是:不能認為凡是遇到SOCKET_ERROR都認為遇到錯誤了。WSAEWOULDBLOCK是一種正常性的錯誤碼,他告訴你現在這個操作無法立即完成,必須等待後續的通知。你可以通過樓上說的select方式去檢查是否連結成功建立”
或看:http://www.verydemo.com/demo_c173_i9565.html
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);//先建立通訊端if(sock == INVALID_SOCKET){ AfxMessageBox("建立通訊端失敗!"); return 0;}SOCKADDR_IN addrTo;addrTo.sin_family=AF_INET;addrTo.sin_port=htons(4000);addrTo.sin_addr.S_un.S_addr=inet_addr(ip);//--------------------------------------------------------------------------//設定為非阻塞方式串連unsigned long ul = 1;int err;int ret = ioctlsocket(sock, FIONBIO, (unsigned long*)&ul);if(ret == SOCKET_ERROR){err = WSAGetLastError(); closesocket(sock); sock = NULL; return FALSE;}TIMEVAL timeval;fd_set r; FD_ZERO(&r);FD_SET(sock, &r);timeval.tv_sec = 1; //秒timeval.tv_usec =200; //毫秒//上面的代碼是要connect在1.2秒之後返回,不管是否已經串連上,這樣就不會阻塞啦,簡單吧connect(sock, (SOCKADDR*)&addrTo, sizeof(SOCKADDR));ret = select(0, 0, &r, 0, &timeval); if ( ret <= 0 ){ char ch[20] = {0}; sprintf(ch, "和%s連線逾時, 取原參數失敗", ip); MessageBox(ch, "錯誤", MB_ICONSTOP); err = WSAGetLastError(); closesocket(sock); sock = NULL; return FALSE;}
順便記錄這個問題:How to set a socket connection timeout
是說,有時候connect當目標不能到達,逾時太久。就先設定非阻塞,connect立即返回,然後重新設為阻塞,最後做select看看socket是否準備好。
5. 在ffmpeg的dshow中,去枚舉裝置名稱,與上層傳下來的裝置名稱匹配。
如:漢字的unicode編碼,常用漢字的UTF-8編碼,漢字GBK編碼錶。上層擷取的是GBK碼,下面卻用UTF-8去匹配,所以總是失敗。
引自 文字編碼 ASCII 漢字GB2312 UTF-8解析
“ASCII,美國資訊交換標準代碼(America standard code of Information Interchange),用一個位元組的7位,美國專用。歐洲也要編碼,於是位元組的8位全用上,有了IBM/ISO Latin-1。然後是第三世界國家,中國,韓國等,於是就必須得擴充了,我們中文輻射區的文字表示甚是複雜,於是兩個位元組的UNICODE出世。但是在幾種編碼的相容問題出現了,怎樣讓中文的一個檔案能在美國讀出來呢?一種權衡方案出台--UTF系列。UTF,Universal
Transformation Format,通用轉換格式。UTF-8是一種非定長的字元表示方式,具體實現可以參見相關資料。”
引自 漢字怎樣轉換成ascii碼
“ascii碼是根據http編碼得出的,首先要知道這個字的http編碼,先進入百度貼吧,把你想查看的字輸入,點擊搜尋,比如說我輸入“牛”,因為地址太長了,再點一下左上方百度貼吧旁的“牛吧”,就會出現比較短的地址,這個地址是 http://tieba.baidu.com/f?kw=%C5%A3 kw=後面的%C5%A3就是http編碼,把%去掉,變成C5A3,使用系統內建的計算機把他變為10進位(開始——所有程式——附件——計算機),查看——科學型,先選擇十六進位,再輸入C5A3,然後選擇十進位,上面的數字就會變成50595,也就說alt+50595能打出“牛””
下面貼兩段代碼,gbk與utf-8的轉換,調用了windows下的介面,代碼醜陋與否無所謂了。
//using cchar *gbk_to_utf8_c(const char *src_gbk, void *(* local_malloc)(size_t), void (* local_free)(void *)){int n;char *dst_utf8 = NULL;wchar_t *tmp = NULL;if (!src_gbk || !local_malloc || !local_free){return NULL;}n = MultiByteToWideChar(CP_ACP, 0, src_gbk, -1, NULL, 0);tmp = (wchar_t *)local_malloc(n*2+2);memset(tmp, 0, n * 2 + 2);MultiByteToWideChar(CP_ACP, 0, src_gbk, -1, tmp, n);n = WideCharToMultiByte(CP_UTF8, 0, tmp, -1, NULL, 0, NULL, NULL);dst_utf8 = (char *)local_malloc(n+1);memset(dst_utf8, 0, n + 1);WideCharToMultiByte(CP_UTF8, 0, tmp, -1, dst_utf8, n, NULL, NULL);local_free((void *)tmp);return dst_utf8;}char *utf8_to_gbk_c(const char *src_utf8, void *(* local_malloc)(size_t), void (* local_free)(void *)){int n = MultiByteToWideChar(CP_UTF8, 0, src_utf8, -1, NULL, 0);wchar_t *tmp = (wchar_t *)local_malloc(n*2+2);char *dst_gbk = NULL;memset(tmp, 0, n * 2 + 2);MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)src_utf8, -1, (LPWSTR)tmp, n);n = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)tmp, -1, NULL, 0, NULL, NULL);dst_gbk = (char *)local_malloc(n+1);memset(dst_gbk, 0, n + 1);WideCharToMultiByte(CP_ACP,0, (LPCWSTR)tmp, -1, dst_gbk, n, NULL, NULL);local_free((void *)tmp);return dst_gbk;}
還可以參考:UTF-8, Unicode, GB2312格式串轉換之C語言版
除了編碼問題,在dshow介面調用的時候,(對於一些硬體裝置名稱,xp win7下不同,win7下通常會有首碼,這樣使裝置名稱很長),裝置易記名稱擷取不完整,而用dsound介面擷取又是沒有問題的。下面是dshow調用的部分介面:
*.讀取裝置名稱的屬性step1: Call IMoniker::BindToStorage to get a pointer to the IPropertyBag interface. IPropertyBag *pPropBag; HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag)); step2: Call IPropertyBag::Read to read the property. VARIANT var; VariantInit(&var); // Get description or friendly name. hr = pPropBag->Read(L"Description", &var, 0);
沒轍,在這裡做名字匹配的時候,只好通過,兩個字串是否包含的關係,去做比較。