Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

/* ========================================================================
*  PROJECT: DirectShow Video Processing Library (DSVL)
*  Version: 0.0.8 (05/13/2005)
*  ========================================================================
*  Author:  Thomas Pintaric, Vienna University of Technology
*  Contact: pintaric@ims.tuwien.ac.at http://ims.tuwien.ac.at/~thomas
*  =======================================================================
*
*  Copyright (C) 2005  Vienna University of Technology
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
*  For further information please contact Thomas Pintaric under
*  <pintaric@ims.tuwien.ac.at> or write to Thomas Pintaric,
*  Vienna University of Technology, Favoritenstr. 9-11/E188/2, A-1040
*  Vienna, Austria.
* ========================================================================*/


#include "Streams.h"
#include <comutil.h>
#include <atlbase.h>
#include "DSVL_Helpers.h"

#include <string.h>
#include <stdlib.h>
#include "math.h"

// -----------------------------------------------------------------------------------------------------------------
double avg2fps(REFERENCE_TIME AvgTimePerFrame, int precision)
{
        return(RoundDouble(10000000.0 / (double)AvgTimePerFrame,precision));
}
// -----------------------------------------------------------------------------------------------------------------
REFERENCE_TIME fps2avg(double fps)
{
        return((REFERENCE_TIME)(1.0/fps*10000000.0));
}
// -----------------------------------------------------------------------------------------------------------------

HRESULT getPin(IBaseFilter *flt, PIN_DIRECTION dir, int number, CComPtr<IPin> &pRetPin)
{
        int n=0;
        IPin* Pin;
        IEnumPins*      EnumPins;
        ULONG           fetched;
        PIN_INFO        pinfo;

        flt->EnumPins(&EnumPins);
        EnumPins->Reset();
        EnumPins->Next(1, &Pin, &fetched);
        Pin->QueryPinInfo(&pinfo);
        //pinfo.pFilter->Release();

        do
        {
                // the pFilter member has an outstanding ref count -> release it, we do not use it anyways!
                pinfo.pFilter->Release();
                pinfo.pFilter = 0;
                if(pinfo.dir == dir)
                {
                        n++;
                        if(n==number)
                        {
                                EnumPins->Release();
                                pRetPin = Pin;
                                return S_OK;
                        }
                        else
                        {
                                Pin->Release();
                                EnumPins->Next(1, &Pin, &fetched);
                                if(fetched == 0) // no more pins
                                {
                                        EnumPins->Release();
                                        pRetPin = NULL;
                                        return(E_FAIL);
                                }
                                Pin->QueryPinInfo(&pinfo);
                        }
                }
                else //if (pinfo.dir != dir)
                {
                        Pin->Release();
                        EnumPins->Next(1, &Pin, &fetched);
                        if(fetched == 0) // no more pins
                        {
                                EnumPins->Release();
                                pRetPin = NULL;
                                return(E_FAIL);
                        }
                        Pin->QueryPinInfo(&pinfo);
                        //pinfo.pFilter->Release();
                }
        } while(Pin != NULL);

        EnumPins->Release();
        return E_FAIL;
}
// -----------------------------------------------------------------------------------------------------------------
HRESULT ConnectFilters(IBaseFilter *filter_out, int out_pin_nr,
                                           IBaseFilter *in_filter, int in_pin_nr)
{
        HRESULT hr;
        CComPtr<IPin> OutPin = NULL;
        CComPtr<IPin> InPin = NULL;
        if(FAILED(hr = getPin(filter_out,PINDIR_OUTPUT,out_pin_nr,OutPin))) return(hr);
        if(FAILED(hr = getPin(in_filter,PINDIR_INPUT,in_pin_nr,InPin))) return(hr);
        if(OutPin == NULL || InPin== NULL) return(E_FAIL);
       
        if(FAILED(hr = OutPin->Connect(InPin,NULL))) return(E_FAIL);
        else return(S_OK);
}
// -----------------------------------------------------------------------------------------------------------------

HRESULT AutoConnectFilters(IBaseFilter *filter_out, int out_pin_nr, IBaseFilter *in_filter,
                                                                                          int in_pin_nr, IGraphBuilder *pGraphBuilder)
{
        HRESULT hr;
        CComPtr<IPin> OutPin  = NULL;
        CComPtr<IPin> InPin  = NULL;
        if(FAILED(hr = getPin(filter_out,PINDIR_OUTPUT,out_pin_nr,OutPin))) return(hr);
        if(FAILED(hr = getPin(in_filter,PINDIR_INPUT,in_pin_nr,InPin))) return(hr);
        if(OutPin == NULL || InPin== NULL) return(E_FAIL);
       
        if(FAILED(hr = pGraphBuilder->Connect(OutPin,InPin))) return(E_FAIL);
        else return(S_OK);
}
// -----------------------------------------------------------------------------------------------------------------

char* strtok_prefix(char* str, const char* prefix)
{
        if(strstr(str,prefix) != 0)
                return(str+strlen(prefix));
        else return(NULL);
}
// -----------------------------------------------------------------------------------------------------------------

void uuidToString(char* dest, int dest_size, GUID* uuid_p)
{
        ZeroMemory(dest,dest_size);
        WideCharToMultiByte(CP_ACP,WC_DEFAULTCHAR,CComBSTR(*uuid_p).m_str,
                                                CComBSTR(*uuid_p).Length(),dest,dest_size,NULL,NULL);
}

// -----------------------------------------------------------------------------------------------------------------

float Round(const float &number, const int num_digits)
{
        float doComplete5i, doComplete5(number * powf(10.0f, (float) (num_digits + 1)));

        if(number < 0.0f)
                doComplete5 -= 5.0f;
        else
                doComplete5 += 5.0f;

        doComplete5 /= 10.0f;
        modff(doComplete5, &doComplete5i);

        return doComplete5i / powf(10.0f, (float) num_digits);
}

// -----------------------------------------------------------------------------------------------------------------

double RoundDouble(double doValue, int nPrecision)
{
        static const double doBase = 10.0f;
        double doComplete5, doComplete5i;

        doComplete5 = doValue * pow(doBase, (double) (nPrecision + 1));

        if(doValue < 0.0f)
                doComplete5 -= 5.0f;
        else
                doComplete5 += 5.0f;

        doComplete5 /= doBase;
        modf(doComplete5, &doComplete5i);

        return doComplete5i / pow(doBase, (double) nPrecision);
}

// -----------------------------------------------------------------------------------------------------------------

HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
// see Microsoft DirectX SDK 9.0 "Loading a Graph From an External Process"
{
        CComPtr<IMoniker> pMoniker;
        CComPtr<IRunningObjectTable> pROT;
        if (FAILED(GetRunningObjectTable(0, &pROT))) {
                return E_FAIL;
        }
        CHAR wsz[256];
        sprintf(wsz, "FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
        HRESULT hr = CreateItemMoniker(L"!", _bstr_t(wsz), &pMoniker);
        if (SUCCEEDED(hr)) {
                hr = pROT->Register(0, pUnkGraph, pMoniker, pdwRegister);
        }
        return hr;
}

// -----------------------------------------------------------------------------------------------------------------

void RemoveFromRot(DWORD pdwRegister)
{
        CComPtr<IRunningObjectTable> pROT;
        if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
                pROT->Revoke(pdwRegister);
        }
}

// -----------------------------------------------------------------------------------------------------------------

HRESULT DisplayPinProperties(CComPtr<IPin> pSrcPin, HWND hWnd)
{
        CComPtr<ISpecifyPropertyPages> pPages;

        HRESULT hr = pSrcPin->QueryInterface(IID_ISpecifyPropertyPages, (void**)&pPages);
        if (SUCCEEDED(hr))
        {
                PIN_INFO PinInfo;
                pSrcPin->QueryPinInfo(&PinInfo);

                CAUUID caGUID;
                pPages->GetPages(&caGUID);

                OleCreatePropertyFrame(
                        hWnd,
                        0,
                        0,
                        L"Property Sheet",
                        1,
                        (IUnknown **)&(pSrcPin.p),
                        caGUID.cElems,
                        caGUID.pElems,
                        0,
                        0,
                        NULL);
                CoTaskMemFree(caGUID.pElems);
                PinInfo.pFilter->Release();
        }
        else return(hr);

        return(S_OK);
}

// -----------------------------------------------------------------------------------------------------------------

HRESULT DisplayFilterProperties(IBaseFilter *pFilter, HWND hWnd)
{
        CComPtr<ISpecifyPropertyPages> pProp;
        HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
        if (SUCCEEDED(hr))
        {
                // Get the filter's name and IUnknown pointer.
                FILTER_INFO FilterInfo;
                pFilter->QueryFilterInfo(&FilterInfo);

                // Show the page.
                CAUUID caGUID;
                pProp->GetPages(&caGUID);
                OleCreatePropertyFrame(
                        hWnd,                   // Parent window
                        0, 0,                   // (Reserved)
                        FilterInfo.achName,     // Caption for the dialog box
                        1,                      // Number of objects (just the filter)
                        (IUnknown **)&pFilter,  // Array of object pointers.
                        caGUID.cElems,          // Number of property pages
                        caGUID.pElems,          // Array of property page CLSIDs
                        0,                      // Locale identifier
                        0, NULL);               // Reserved

                // Clean up.
                if(FilterInfo.pGraph != NULL) FilterInfo.pGraph->Release();
                CoTaskMemFree(caGUID.pElems);
        }
        return(hr);
}


// -----------------------------------------------------------------------------------------------------------------

HRESULT FindCaptureDevice(IBaseFilter ** ppSrcFilter,
                                                  LPWSTR filterNameSubstring,
                                                  bool matchDeviceName,
                                                  char* ieee1394id_str)
{
        HRESULT hr;
        IBaseFilter * pSrc = NULL;
        CComPtr <IMoniker> pMoniker =NULL;
        ULONG cFetched;

        // Create the system device enumerator
        CComPtr <ICreateDevEnum> pDevEnum =NULL;

        hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
                IID_ICreateDevEnum, (void ** ) &pDevEnum);
        if (FAILED(hr))
        {
                AMErrorMessage(hr,"Couldn't create system enumerator!");
                return hr;
        }

        // Create an enumerator for the video capture devices
        CComPtr <IEnumMoniker> pClassEnum = NULL;

        hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
        if (FAILED(hr))
        {
                AMErrorMessage(hr,"Couldn't create system enumerator!");
                return hr;
        }

        // If there are no enumerators for the requested type, then
        // CreateClassEnumerator will succeed, but pClassEnum will be NULL.
        if (pClassEnum == NULL)
        {
                MessageBox(NULL,TEXT("No video capture device was detected.\r\n\r\n")
                        TEXT("You need at least one WDM video capture device, such as a USB WebCam.\r\n"),
                        TEXT("No Video Capture Hardware"), MB_OK | MB_ICONINFORMATION);
                return E_FAIL;
        }

        while(S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
        {
                CComPtr<IPropertyBag> pProp;
                pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pProp);
                VARIANT varName;
                VariantInit(&varName); // Try to match the friendly name.
                HRESULT name_hr = pProp->Read(L"FriendlyName", &varName, 0);

                //              (SUCCEEDED(hr) && (wcsstr(varName.bstrVal, filterNameSubstring) != NULL)))
                if(filterNameSubstring != NULL)
                {
                        // Bind Moniker to a filter object
                        hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);

                        if(matchDeviceName)
                        {
                                LPOLESTR strName = NULL;
                                hr = pMoniker->GetDisplayName(NULL, NULL, &strName);
                                if(wcsstr(strName, filterNameSubstring) != NULL)
                                {
                                        *ppSrcFilter = pSrc;
                                        return(S_OK);
                                }
                        }
                        else // matchFriendlyName
                        {
                                if(SUCCEEDED(name_hr) && wcsstr(varName.bstrVal, filterNameSubstring) != NULL)
                                {
                                        // check for matching IEEE-1394 identifier
                                        if(ieee1394id_str != NULL)
                                        {
                                                IAMExtDevice *pExtDev = NULL;
                                                hr = pSrc->QueryInterface(IID_IAMExtDevice, (void**)&pExtDev);
                                                if(SUCCEEDED(hr))
                                                {
                                                        LPOLESTR ole_str = NULL;
                                                        bool matching_id = false;
                                                        hr = pExtDev->get_ExternalDeviceID(&ole_str);

                                                        unsigned __int64 msdv_id = *((unsigned __int64*) ole_str);
                                                        if(ole_str != NULL) CoTaskMemFree(ole_str);

                                                        char* temp_str = (char*) CoTaskMemAlloc(sizeof(char) * MAX_PATH);
                                                        _ui64toa(msdv_id,temp_str,16);
                                                        if(strcmp(ieee1394id_str,temp_str) == 0) matching_id = true;
                                                        CoTaskMemFree(temp_str);

                                                        if(SUCCEEDED(hr) && matching_id)
                                                        {
                                                                *ppSrcFilter = pSrc;
                                                                return(S_OK);
                                                        }
                                                        else // pExtDev->get_ExternalDeviceID() failed || identifier mismatch
                                                        {
                                                                pSrc->Release();
                                                        }
                                                }
                                                else
                                                {
                                                        pSrc->Release();
                                                }
                                        }
                                        else // (ieee1394id == 0)
                                        {
                                                *ppSrcFilter = pSrc;
                                                return(S_OK);
                                        }
                                }
                                else // friendlyName substrings don't match
                                {
                                        pSrc->Release();
                                }
                        }
                }
                VariantClear(&varName);
                pMoniker = NULL; // Release for the next loop.
        }

        pClassEnum->Reset();

        // Use the first video capture device on the device list.
        // Note that if the Next() call succeeds but there are no monikers,
        // it will return S_FALSE (which is not a failure).  Therefore, we
        // check that the return code is S_OK instead of using SUCCEEDED() macro.
        if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
        {
                // Bind Moniker to a filter object
                hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
                if (FAILED(hr))
                {
                        AMErrorMessage(hr,"Couldn't bind moniker to filter object!");
                        return hr;
                }
        }
        else
        {
                MessageBox(NULL,"Unable to access video capture device!","ERROR",MB_OK);
                return E_FAIL;
        }

        // Copy the found filter pointer to the output parameter.
        // Do NOT Release() the reference, since it will still be used
        // by the calling function.
        *ppSrcFilter = pSrc;

        return hr;
}

// -----------------------------------------------------------------------------------------------------------------

bool CanDeliverVideo(IPin *pin)
// checks if a pin can deliver MEDIAFORMAT_Video
{
        HRESULT hr;
        CComPtr <IEnumMediaTypes> enum_mt;
        pin->EnumMediaTypes(&enum_mt);
        enum_mt->Reset();
        AM_MEDIA_TYPE *p_mt = NULL;
        while(S_OK == (hr = enum_mt->Next(1,&p_mt,NULL)))
        {
                if(p_mt->majortype == MEDIATYPE_Video)
                {
                        DeleteMediaType(p_mt);
                        return(true);
                }
                else DeleteMediaType(p_mt);
        }

        return(false);
}

// -----------------------------------------------------------------------------------------------------------------
bool CanDeliverDV(IPin *pin)
// checks if a pin can deliver compressed DV formats
// (refer to Microsoft DirectX Documentation, "DV Video Subtypes" for more information)

/*
FOURCC  GUID                            Data Rate       Description
'dvsl'  MEDIASUBTYPE_dvsl       12.5 Mbps       SD-DVCR 525-60 or SD-DVCR 625-50
'dvsd'  MEDIASUBTYPE_dvsd       25 Mbps         SDL-DVCR 525-60 or SDL-DVCR 625-50
'dvhd'  MEDIASUBTYPE_dvhd       50 Mbps         HD-DVCR 1125-60 or HD-DVCR 1250-50
*/

{
        HRESULT hr;
        CComPtr <IEnumMediaTypes> enum_mt;
        pin->EnumMediaTypes(&enum_mt);
        enum_mt->Reset();
        AM_MEDIA_TYPE *p_mt = NULL;
        while(S_OK == (hr = enum_mt->Next(1,&p_mt,NULL)))
        {
                if((p_mt->subtype == MEDIASUBTYPE_dvsl) ||
                        (p_mt->subtype == MEDIASUBTYPE_dvsd) ||
                        (p_mt->subtype == MEDIASUBTYPE_dvhd))
                {
                        DeleteMediaType(p_mt);
                        return(true);
                }
                else DeleteMediaType(p_mt);
        }

        return(false);
}

// -----------------------------------------------------------------------------------------------------------------
HRESULT AMErrorMessage(HRESULT hr, char* error_title)
{
        TCHAR buffer[MAX_PATH];
        DWORD cRet = AMGetErrorText(hr,buffer,MAX_PATH);
        if(cRet > 0) MessageBox(NULL,_T(buffer),error_title,MB_OK);
        else return(E_FAIL);
        return(S_OK);
}

// -----------------------------------------------------------------------------------------------------------------

void FlipImageRGB32(BYTE* pBuf, int width, int height,
                                        bool flipImageH, bool flipImageV)
{
        DWORD *ptr = (DWORD*)pBuf;
        int pixelCount = width * height;

        if (!pBuf)
                return;

        // Added code for more image manipulations
        // Gerhard Reitmayr <reitmayr@ims.tuwien.ac.at

        if( flipImageV )
        {
                if( flipImageH )
                {
                        // both flips set -> rotation about 180 degree
                        for (int index = 0; index < pixelCount/2; index++)
                        {
                                ptr[index] = ptr[index] ^ ptr[pixelCount - index - 1];
                                ptr[pixelCount - index - 1] = ptr[index] ^ ptr[pixelCount - index - 1];
                                ptr[index] = ptr[index] ^ ptr[pixelCount - index - 1];
                        }
                }
                else  
                {
                        // only vertical flip
                        for( int line = 0; line < height/2; line++ )
                                for( int pixel = 0; pixel < width; pixel ++ )
                                {
                                        ptr[line*width+pixel] = ptr[line*width+pixel] ^ ptr[pixelCount - line*width - (width - pixel )];
                                        ptr[pixelCount - line*width - (width - pixel )] = ptr[line*width+pixel] ^ ptr[pixelCount - line*width - (width - pixel )];
                                        ptr[line*width+pixel] = ptr[line*width+pixel] ^ ptr[pixelCount - line*width - (width - pixel )];
                                }
                }
        }
        else
        {
                if( flipImageH )
                {
                        // only horizontal flip
                        for( int line = 0; line < height; line++ )
                                for( int pixel = 0; pixel < width/2; pixel ++ )
                                {
                                        ptr[line*width+pixel] = ptr[line*width+pixel] ^ ptr[line*width + (width - pixel )];
                                        ptr[line*width + (width - pixel )] = ptr[line*width+pixel] ^ ptr[line*width + (width - pixel )];
                                        ptr[line*width+pixel] = ptr[line*width+pixel] ^ ptr[line*width + (width - pixel )];
                                }
                }
        }
}