Feeds:
文章
留言

Archive for 2008 年 10 月

今天修改程式之後出現了 Fatal: Unable to open file ‘.obj’ 這個錯誤訊息

看到這個訊息我還真不知道錯在哪裡,查了 Google 也找不出原因

經過一陣查時間檢查後發現,居然是因為這一行

#pragma comment(lib, "")

原本要加上一個 Library 結果切換頁面修改程式後竟忘了,結果出現這個傻眼的錯誤訊息,啊~~~~~~~~~~~~~ 今天真不適合工作

要是知道今天這麼不順,早上腳踏車壞了,就請假一天 T_T

 

ps. 以上的錯誤訊息是發生在 C++ Builder 6.0,如果同樣的錯誤語法在 VC8 則會出現

fatal error LNK1146: no argument specified with option ‘/DEFAULTLIB:’   

查詢 MSDN 可以約略猜出是 Linker 的參數問題,內容摘要如下

no argument specified with option ‘option’. The given linker option requires an argument.

Read Full Post »

Read Full Post »

最近發現用 C# 撰寫的 FluorineFx 專案,這個專案特別的地方是支援 RTMP Protocol, AMF0, AMF3,更棒的是有提供 RTMP Client API。雖然 Red5 也有提供類似的 API 不過實作尚未完成。至於 FluorineFx 的 RTMP Client 測試之後也發現沒有我想像中的好,目前只支援 NetConnection, SharedObject,但是獨缺我最需要要的 NetStream….

只用 NetConnection+SharedObject 可讓 .NET 透過 Flash Remoting 與遠端的 RTMP Server 溝通。以下使用 Red5 附得 SOSample 這個簡單聊天程式來測試 FluorineFx。測試環境如下:

1. Windows XP SP2
2. Red5 0.7
3. FluorineFx 1.0.0.13
4. VS2005

程式碼(修改 FluorineFx 內附的 SharedObjectTest 範例)

using System;
using FluorineFx;
using FluorineFx.Net;

namespace SharedObjectTest
{
    class Program
    {
        NetConnection _netConnection;
        RemoteSharedObject _sharedObject;

        static void Main(string[] args)
        {
            Program program = new Program();
            program.Connect();

            System.Console.WriteLine("Connecting to server...");
            string cmd;
            do{
                cmd = System.Console.ReadLine();
                if (cmd == "exit") {
                    break;
                }

                program.send(cmd);
            }while(true);
        }

        public void Connect()
        {
            // Create NetConnection client
            _netConnection = new NetConnection();
            _netConnection.OnConnect += new ConnectHandler(_netConnection_OnConnect);
            _netConnection.OnDisconnect += new DisconnectHandler(_netConnection_OnDisconnect);
            _netConnection.NetStatus += new NetStatusHandler(_netConnection_NetStatus);
            
            _netConnection.Connect("rtmp://localhost:1935/SOSample");
        }

        void _netConnection_OnConnect(object sender, EventArgs e)
        {
            System.Console.WriteLine("Connected to server. Connecting to RSO...");
            //_sharedObject = RemoteSharedObject.GetRemote("users", _netConnection.Uri.ToString(), false);
            //Our custom UsersRSO will handle "ChatMsg" messages
            _sharedObject = RemoteSharedObject.GetRemote("SampleChat" /*typeof(UsersRSO), "users"*/, _netConnection.Uri.ToString(), false);
            
            _sharedObject.OnConnect += new ConnectHandler(_sharedObject_OnConnect);
            _sharedObject.OnDisconnect += new DisconnectHandler(_sharedObject_OnDisconnect);
            _sharedObject.NetStatus += new NetStatusHandler(_sharedObject_NetStatus);
            _sharedObject.Sync += new SyncHandler(_sharedObject_Sync);
            _sharedObject.Connect(_netConnection);
        }

        void _netConnection_OnDisconnect(object sender, EventArgs e)
        {
            System.Console.WriteLine("Connection disconnected.");
        }

        void _netConnection_NetStatus(object sender, NetStatusEventArgs e)
        {
            string level = e.Info["level"] as string;
            if (level == "error")
            {
                //received an error
                System.Console.WriteLine("Error: " + e.Info["code"] as string);
                System.Console.WriteLine("Client not connected. Press 'Enter' to exit");
            }
            if (level == "status")
            {
                System.Console.WriteLine("Status: " + e.Info["code"] as string);
            }
        }

        void _sharedObject_OnConnect(object sender, EventArgs e)
        {
            System.Console.WriteLine("Connected to RSO.");
        }

        void _sharedObject_OnDisconnect(object sender, EventArgs e)
        {
            System.Console.WriteLine("Disconnected RSO.");
        }

        void _sharedObject_Sync(object sender, SyncEventArgs e)
        {
            
            ASObject[] changeList = e.ChangeList;
            for (int i = 0; i < changeList.Length; i++)
            {
                ASObject info = changeList[i];

                if (info["name"] != null && info["code"] == "change") {
                    String d = _sharedObject.GetAttribute("SampleChat").ToString();
                    Console.WriteLine("Receive Data: " + d);
                } else
                    System.Console.WriteLine(info["code"].ToString());
            }

        }

        public void send(String data) {
            _sharedObject.SetProperty("SampleChat", data);
        }

        void _sharedObject_NetStatus(object sender, NetStatusEventArgs e)
        {
            string level = e.Info["level"] as string;
            if (level == "error")
            {
                //received an error
                //System.Console.WriteLine("Error: " + e.Info["code"] as string);
            }
            if (level == "status")
            {
                System.Console.WriteLine("Status: " + e.Info["code"] as string);
            }
        }
    }
}

image

Read Full Post »

今天收到同事的訊息說,知名品牌孔雀餅乾居然含"三聚氰胺" 真是晴天霹靂1133770370.jpg ,以下是相關新聞連結

想不到我的生活也遭到侵襲,之前超市特價時我買了一大包,本來打算颱風/地震斷糧時食用,啊~~

誰可以告訴我要怎麼退貨呀 (ps. 發票可能已經消失)~~~~~~~~~~~

還是我準備五公升的水把大包孔雀餅乾給吞了當晚餐

Read Full Post »

Read Full Post »

如果視訊不想顯示在全螢幕,可設定 IVideoWindow.Owner 將視訊內嵌在指定的視窗中。如下程式片段

// 將 Video 繪製在記事本上
HWND hWnd = ::FindWindow(L"Notepad", NULL);
m_pVW->put_Owner((OAHWND)hWnd);

//設定窗口樣式
m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

//設定窗口大小
RECT rect;
GetClientRect(hWnd, &rect);
m_pVW->SetWindowPosition(0, 0, rect.right – rect.left, rect.bottom – rect.top);
m_pVW->SetWindowForeground(OATRUE);

//設定可視
m_pVW->put_Visible(OATRUE);

參考資料
[1] MSDN, "IVideoWindow Interface"

Read Full Post »

IVideoWindow 介面用來設定視訊視窗的屬性,其中 FullScreenMode 屬性設為 true 則會以全螢幕方式呈現。

以下是切換到全螢幕呈現的程式片段

CComQIPtr<IVideoWindow> m_pVW = pGraphBuilder;
m_pVW->put_FullScreenMode(OATRUE);

CComQIPtr<IMediaControl> m_pMC = pGraphBuilder;
// 啟動
m_pMC->Run();

參考資料
[1] MSDN, "IVideoWindow Interface"

Read Full Post »

之前的程式我都偷懶使用一個無權空迴圈來觀看執行結果。實際上,DirectShow 有一個 IMediaEvent 介面可用來接收媒體的相關事件。

其中 WaitForCompletion( msTimeout, pEvCode) 可用來等待視訊執行結束。

如果要等待影片執行完成,可用如下的程式

CComQIPtr<IMediaEvent> pMediaEvent = pGraphBuilder;
long eventCode;
pMediaEvent->WaitForCompletion(INFINITE, &eventCode);       

如果你只希望他執行 10 秒就結束,修改 timeout 時間
pMediaEvent->WaitForCompletion(10000, &eventCode);       

參考資料
[1] MSDN, "IMediaEvent::WaitForCompletion"
[2] MSDN, "IMediaEvent Interface"

Read Full Post »

因為 Webcam 屬於一個設備,沒有辦法使用"利用 DirectShow 播放音訊和視訊"所提到的 RenderFile。因此,對於這種設備就需要使用 ICaptureGraphBuilder2.RenderStream()。

另外,我要如何知道那個輸入設備是要 Render,一個方法是透過列舉給使用者選擇,我的範例假設只有一個視訊輸入設備。

下面是我的測試範例

 

#include "stdafx.h"
#include <rpcsal.h>
#include <dshow.h>
#include <iostream>

#pragma comment(lib, "strmiids.lib")

using namespace std;

int main(){
    ::CoInitialize(NULL);
    {
        CComPtr<IGraphBuilder> pGraphBuilder;
        pGraphBuilder.CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER);

        CComPtr<ICaptureGraphBuilder2> m_pCapture; 
        m_pCapture.CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC);
    
        // Filter 和 Capture 進行連接 
        m_pCapture->SetFiltergraph(pGraphBuilder); 

        // 列舉設備 
        CComPtr<ICreateDevEnum> pCde;         
        pCde.CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC);

        CComPtr<IEnumMoniker> pEm;
        pCde->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEm, 0);

        CComPtr<IMoniker> pM; 
        ULONG cFetched; 
        CComPtr<IBaseFilter> pBf; 
        if(pEm->Next(1, &pM, &cFetched)==S_OK) {
            //設備聯接 
            pM->BindToObject(0,0,IID_IBaseFilter, (void**)&pBf); 
            pM.Release(); 
        } else { 
            // 沒有 Webcam 設備
            return 0; 
        } 

        //將設備添加到graph 
        pGraphBuilder->AddFilter(pBf, L"Video Capture"); 

        // 連接一個源插口 
        m_pCapture->RenderStream(
            &PIN_CATEGORY_PREVIEW,
            &MEDIATYPE_Video,
            pBf,
            NULL,
            NULL
        );         
        
        CComQIPtr<IMediaControl> m_pMC = pGraphBuilder; 

        // 啟動
        m_pMC->Run();

        while(1){
            ::Sleep(1000);
        }
    }
    ::CoUninitialize();    
    return 0;
}

參考資料
[1] MSDN, "ICaptureGraphBuilder2 Interface"
[2] MSDN, "ICreateDevEnum Interface"

Read Full Post »

使用 IGraphBuilder 和 IMediaControl 介面可以簡單的播放任何音訊和視訊檔案,以下是播放 mp3 的程式 ^^

#include "stdafx.h"
#include <rpcsal.h>
#include <dshow.h>
#pragma comment(lib, "strmiids.lib")
int _tmain(int argc, _TCHAR* argv[]){ ::CoInitialize(NULL);


{ CComPtr<IGraphBuilder> pGraphBuilder; CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraphBuilder ); CComPtr<IMediaControl> pMediaControl; pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMediaControl); // 建立 the filter graph pGraphBuilder->RenderFile(L"c:\02.mp3", NULL); // 播放媒體 pMediaControl->Run(); while(1){ ::Sleep(1000); }

} ::CoUninitialize(); return 0; }

如果你要播放 avi, wmv 等視訊,只要將程式的 mp3 檔改成你系統中的 avi 視訊檔名即可。不同的是因為我沒有設定呈現的 Window 所以會出現如下的視窗播放影片

image

參考資料
[1] MSDN, "IGraphBuilder Interface"
[2] MSDN, "IMediaControl Interface"

Read Full Post »

Older Posts »