DShow + OpenGL播放视屏

#include <DShow.h>
#pragma include_alias( "dxtrans.h", "qedit.h" )
#define __IDxtCompositor_INTERFACE_DEFINED__
#define __IDxtAlphaSetter_INTERFACE_DEFINED__
#define __IDxtJpeg_INTERFACE_DEFINED__
#define __IDxtKey_INTERFACE_DEFINED__
#include <uuids.h>
#include <Aviriff.h>
#include <Windows.h>

//for threading
#include <process.h>

#pragma comment(lib,"uuid.lib")
#pragma comment(lib,"Strmiids.lib")
// Due to a missing qedit.h in recent Platform SDKs, we‘ve replicated the relevant contents here
// #include <qedit.h>
MIDL_INTERFACE("0579154A-2B53-4994-B0D0-E773148EFF85")
ISampleGrabberCB : public IUnknown
{
  public:
    virtual HRESULT STDMETHODCALLTYPE SampleCB(
        double SampleTime,
        IMediaSample *pSample) = 0;

    virtual HRESULT STDMETHODCALLTYPE BufferCB(
        double SampleTime,
        BYTE *pBuffer,
        long BufferLen) = 0;

};

MIDL_INTERFACE("6B652FFF-11FE-4fce-92AD-0266B5D7C78F")
ISampleGrabber : public IUnknown
{
  public:
    virtual HRESULT STDMETHODCALLTYPE SetOneShot(
        BOOL OneShot) = 0;

    virtual HRESULT STDMETHODCALLTYPE SetMediaType(
        const AM_MEDIA_TYPE *pType) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
        AM_MEDIA_TYPE *pType) = 0;

    virtual HRESULT STDMETHODCALLTYPE SetBufferSamples(
        BOOL BufferThem) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer(
        /* [out][in] */ long *pBufferSize,
        /* [out] */ long *pBuffer) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetCurrentSample(
        /* [retval][out] */ IMediaSample **ppSample) = 0;

    virtual HRESULT STDMETHODCALLTYPE SetCallback(
        ISampleGrabberCB *pCallback,
        long WhichMethodToCallback) = 0;

};
EXTERN_C const CLSID CLSID_SampleGrabber;
EXTERN_C const IID IID_ISampleGrabber;
EXTERN_C const CLSID CLSID_NullRenderer;

// GetUnconnectedPin
//    Finds an unconnected pin on a filter in the desired direction
HRESULT GetUnconnectedPin(
                          IBaseFilter *pFilter,   // Pointer to the filter.
                          PIN_DIRECTION PinDir,   // Direction of the pin to find.
                          IPin **ppPin)           // Receives a pointer to the pin.
{
    *ppPin = 0;
    IEnumPins *pEnum = 0;
    IPin *pPin = 0;
    HRESULT hr = pFilter->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        return hr;
    }
    while (pEnum->Next(1, &pPin, NULL) == S_OK)
    {
        PIN_DIRECTION ThisPinDir;
        pPin->QueryDirection(&ThisPinDir);
        if (ThisPinDir == PinDir)
        {
            IPin *pTmp = 0;
            hr = pPin->ConnectedTo(&pTmp);
            if (SUCCEEDED(hr))  // Already connected, not the pin we want.
            {
                pTmp->Release();
            }
            else  // Unconnected, this is the pin we want.
            {
                pEnum->Release();
                *ppPin = pPin;
                return S_OK;
            }
        }
        pPin->Release();
    }
    pEnum->Release();
    // Did not find a matching pin.
    return E_FAIL;
}   

// Disconnect any connections to the filter.
HRESULT DisconnectPins(IBaseFilter *pFilter)
{
    IEnumPins *pEnum = 0;
    IPin *pPin = 0;
    HRESULT hr = pFilter->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        return hr;
    }   

    while (pEnum->Next(1, &pPin, NULL) == S_OK)
    {
        pPin->Disconnect();
        pPin->Release();
    }
    pEnum->Release();   

    // Did not find a matching pin.
    return S_OK;
}   

// ConnectFilters
//    Connects a pin of an upstream filter to the pDest downstream filter
HRESULT ConnectFilters(
                       IGraphBuilder *pGraph, // Filter Graph Manager.
                       IPin *pOut,            // Output pin on the upstream filter.
                       IBaseFilter *pDest)    // Downstream filter.
{
    if ((pGraph == NULL) || (pOut == NULL) || (pDest == NULL))
    {
        return E_POINTER;
    }
#ifdef debug
    PIN_DIRECTION PinDir;
    pOut->QueryDirection(&PinDir);
    _ASSERTE(PinDir == PINDIR_OUTPUT);
#endif   

    // Find an input pin on the downstream filter.
    IPin *pIn = 0;
    HRESULT hr = GetUnconnectedPin(pDest, PINDIR_INPUT, &pIn);
    if (FAILED(hr))
    {
        return hr;
    }
    // Try to connect them.
    hr = pGraph->Connect(pOut, pIn);
    pIn->Release();
    return hr;
}   

// ConnectFilters
//    Connects two filters
HRESULT ConnectFilters(
                       IGraphBuilder *pGraph,
                       IBaseFilter *pSrc,
                       IBaseFilter *pDest)
{
    if ((pGraph == NULL) || (pSrc == NULL) || (pDest == NULL))
    {
        return E_POINTER;
    }   

    // Find an output pin on the first filter.
    IPin *pOut = 0;
    HRESULT hr = GetUnconnectedPin(pSrc, PINDIR_OUTPUT, &pOut);
    if (FAILED(hr))
    {
        return hr;
    }
    hr = ConnectFilters(pGraph, pOut, pDest);
    pOut->Release();
    return hr;
}   

// LocalFreeMediaType
//    Free the format buffer in the media type
void LocalFreeMediaType(AM_MEDIA_TYPE& mt)
{
    if (mt.cbFormat != 0)
    {
        CoTaskMemFree((PVOID)mt.pbFormat);
        mt.cbFormat = 0;
        mt.pbFormat = NULL;
    }
    if (mt.pUnk != NULL)
    {
        // Unecessary because pUnk should not be used, but safest.
        mt.pUnk->Release();
        mt.pUnk = NULL;
    }
}   

// LocalDeleteMediaType
//    Free the format buffer in the media type,
//    then delete the MediaType ptr itself
void LocalDeleteMediaType(AM_MEDIA_TYPE *pmt)
{
    if (pmt != NULL)
    {
        LocalFreeMediaType(*pmt); // See FreeMediaType for the implementation.
        CoTaskMemFree(pmt);
    }
}

HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath)
{
    const WCHAR wszStreamName[] = L"ActiveMovieGraph";
    HRESULT hr;

    IStorage *pStorage = NULL;
    hr = StgCreateDocfile(
        wszPath,
        STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
        0, &pStorage);
    if(FAILED(hr))
    {
        return hr;
    }

    IStream *pStream;
    hr = pStorage->CreateStream(
        wszStreamName,
        STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
        0, 0, &pStream);
    if (FAILED(hr))
    {
        pStorage->Release();
        return hr;
    }

    IPersistStream *pPersist = NULL;
    pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersist);
    hr = pPersist->Save(pStream, TRUE);
    pStream->Release();
    pPersist->Release();
    if (SUCCEEDED(hr))
    {
        hr = pStorage->Commit(STGC_DEFAULT);
    }
    pStorage->Release();
    return hr;
}

//-------------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
// DirectShowVideo - contains a simple directshow video player implementation
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------------

static int comRefCount = 0; 

static void retainCom(){
    if( comRefCount == 0 ){
        //printf("com is initialized!\n");
        CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    }
    comRefCount++;
}

static void releaseCom(){
    comRefCount--;
    if( comRefCount == 0 ){
        //printf("com is uninitialized!\n");
        CoUninitialize();
    }
}

class DirectShowVideo : public ISampleGrabberCB{
    public:

    DirectShowVideo(){
        retainCom();
        clearValues();
        InitializeCriticalSection(&critSection);
    }

    ~DirectShowVideo(){
        tearDown();
        releaseCom();
        DeleteCriticalSection(&critSection);
    }

    void tearDown(){
        //printf("tearDown\n"); 

        if(m_pControl){
            m_pControl->Release();
        }
        if(m_pEvent){
            m_pEvent->Release();
        }
        if(m_pSeek){
            m_pSeek->Release();
        }
        if(m_pAudio){
            m_pAudio->Release();
        }
        if(m_pBasicVideo){
            m_pBasicVideo->Release();
        }
        if(m_pGrabber){
            m_pGrabber->Release();
        }
        if(m_pGrabberF){
            m_pGrabberF->Release();
        }
        if(m_pGraph){
            m_pGraph->Release();
        }
        if(m_pNullRenderer){
            m_pNullRenderer->Release();
        }
        if( m_pSourceFile ){
            m_pSourceFile->Release();
        }
        if( m_pPosition ){
            m_pPosition->Release();
        }

        if(rawBuffer){
            delete rawBuffer;
        }
        clearValues();
    }

    void clearValues(){
        hr = 0;

        m_pGraph = NULL;
        m_pControl = NULL;
        m_pEvent = NULL;
        m_pSeek = NULL;
        m_pAudio = NULL;
        m_pGrabber = NULL;
        m_pGrabberF = NULL;
        m_pBasicVideo = NULL;
        m_pNullRenderer = NULL;
        m_pSourceFile = NULL;
        m_pPosition = NULL;

        rawBuffer = NULL;

        timeNow = 0;
        lPositionInSecs = 0;
        lDurationInNanoSecs = 0;
        lTotalDuration = 0;
        rtNew = 0;
        lPosition = 0;
        lvolume = -1000;
        evCode = 0;
        width = height = 0;
        videoSize = 0;
        bVideoOpened = false;
        bLoop = true;
        bPaused = false;
        bPlaying = false;
        bEndReached = false;
        bNewPixels = false;
        bFrameNew = false;
        curMovieFrame = -1;
        frameCount = -1;

        movieRate = 1.0;
        averageTimePerFrame = 1.0/30.0;
    }

    //------------------------------------------------
    STDMETHODIMP_(ULONG) AddRef() { return 1; }
    STDMETHODIMP_(ULONG) Release() { return 2; }

    //------------------------------------------------
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject){
        *ppvObject = static_cast<ISampleGrabberCB*>(this);
        return S_OK;
    }

    //------------------------------------------------
    STDMETHODIMP SampleCB(double Time, IMediaSample *pSample){

        BYTE * ptrBuffer = NULL;
        HRESULT hr = pSample->GetPointer(&ptrBuffer);

        if(hr == S_OK){
            long latestBufferLength = pSample->GetActualDataLength();
            if(latestBufferLength == videoSize ){
                EnterCriticalSection(&critSection);
                memcpy(rawBuffer, ptrBuffer, latestBufferLength);
                bNewPixels = true;

                //this is just so we know if there is a new frame
                frameCount++;

                LeaveCriticalSection(&critSection);
            }else{
                printf("ERROR: SampleCB() - buffer sizes do not match\n");
            }
        }

        return S_OK;
    }

    //This method is meant to have more overhead
    STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen){
        return E_NOTIMPL;
    }

    bool loadMovie(std::string path)
    {
        tearDown();

    // Create the Filter Graph Manager and query for interfaces.

        //printf("step 1\n");
        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)&m_pGraph);
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        //printf("step 2\n");
        hr = m_pGraph->QueryInterface(IID_IMediaSeeking, (void**)&m_pSeek);
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        hr = m_pGraph->QueryInterface(IID_IMediaPosition, (LPVOID *)&m_pPosition);
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        hr = m_pGraph->QueryInterface(IID_IBasicAudio,(void**)&m_pAudio);
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        // Use IGraphBuilder::QueryInterface (inherited from IUnknown) to get the IMediaControl interface.
        //printf("step 4\n");
        hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl);
        if (FAILED(hr)){
            tearDown();
            return false;
        }  

        // And get the Media Event interface, too.
        //printf("step 5\n");
        hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **)&m_pEvent);
        if (FAILED(hr)){
            tearDown();
            return false;
        } 

        //SAMPLE GRABBER (ALLOWS US TO GRAB THE BUFFER)//
        // Create the Sample Grabber.
        hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&m_pGrabberF);
        if (FAILED(hr)){
            tearDown();
            return false;
        } 

        hr = m_pGraph->AddFilter(m_pGrabberF, L"Sample Grabber");
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        hr = m_pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&m_pGrabber);
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        m_pGrabber->SetCallback(this, 0);
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        //MEDIA CONVERSION
        //Get video properties from the stream‘s mediatype and apply to the grabber (otherwise we don‘t get an RGB image)
        AM_MEDIA_TYPE mt;
        ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));

        mt.majortype    = MEDIATYPE_Video;
        mt.subtype      = MEDIASUBTYPE_RGB24;
        mt.formattype   = FORMAT_VideoInfo;

        //printf("step 5.5\n");
        hr = m_pGrabber->SetMediaType(&mt);
        if (FAILED(hr)){
            tearDown();
            return false;
        }

        //printf("step 6\n");
        std::wstring filePathW = std::wstring(path.begin(), path.end());

        //this is the easier way to connect the graph, but we have to remove the video window manually
        hr = m_pGraph->RenderFile(filePathW.c_str(), NULL);

        //this is the more manual way to do it - its a pain though because the audio won‘t be connected by default
        /*hr = m_pGraph->AddSourceFilter(filePathW.c_str(), L"Source", &m_pSourceFile);
        if (FAILED(hr)){
            printf("unable to AddSourceFilter\n");
            tearDown();
            return false;
        }*/
        //hr = ConnectFilters(m_pGraph, m_pSourceFile, m_pGrabberF);
        //if (FAILED(hr)){
        //  printf("unable to ConnectFilters(m_pGraph, m_pSourceFile, m_pGrabberF)\n");
        //  tearDown();
        //  return false;
        //}

        //printf("step 7\n");
        if (SUCCEEDED(hr)){

            //Set Params - One Shot should be false unless you want to capture just one buffer
            hr = m_pGrabber->SetOneShot(FALSE);
            if (FAILED(hr)){
                printf("unable to set one shot\n");
                tearDown();
                return false;
            }

            hr = m_pGrabber->SetBufferSamples(TRUE);
            if (FAILED(hr)){
                printf("unable to set buffer samples\n");
                tearDown();
                return false;
            }

            //NULL RENDERER//
            //used to give the video stream somewhere to go to.
            hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)(&m_pNullRenderer));
            if (FAILED(hr)){
                printf("null renderer error\n");
                tearDown();
                return false;
            }       

            hr = m_pGraph->AddFilter(m_pNullRenderer, L"Render");
            if (FAILED(hr)){
                printf("unable to add null renderer\n");
                tearDown();
                return false;
            }

            //hr = ConnectFilters(m_pGraph, m_pGrabberF, m_pNullRenderer);
            //if (FAILED(hr)){
            //  printf("unable to ConnectFilters(m_pGraph, m_pGrabberF, m_pNullRenderer)\n");
            //  tearDown();
            //  return false;
            //}

            AM_MEDIA_TYPE mt;
            ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));

            m_pGrabber->GetConnectedMediaType(&mt);
            if (FAILED(hr)){
                printf("unable to call GetConnectedMediaType\n");
                tearDown();
                return false;
            }

            VIDEOINFOHEADER * infoheader = (VIDEOINFOHEADER*)mt.pbFormat;
            width = infoheader->bmiHeader.biWidth;
            height = infoheader->bmiHeader.biHeight;
            averageTimePerFrame = infoheader->AvgTimePerFrame / 10000000.0;   

            videoSize = width * height * 3;
            //printf("video dimensions are %i %i\n", width, height); 

            //we need to manually change the output from the renderer window to the null renderer
            IBaseFilter * m_pVideoRenderer;
            IPin* pinIn = 0;
            IPin* pinOut = 0;

            IBaseFilter * m_pColorSpace;

            m_pGraph->FindFilterByName(L"Video Renderer", &m_pVideoRenderer);
            if (FAILED(hr)){
                printf("failed to find the video renderer\n");
                tearDown();
                return false;
            }

            //we disconnect the video renderer window by finding the output pin of the sample grabber
            hr = m_pGrabberF->FindPin(L"Out", &pinOut);
            if (FAILED(hr)){
                printf("failed to find the sample grabber output pin\n");
                tearDown();
                return false;
            }

            hr = pinOut->Disconnect();
            if (FAILED(hr)){
                printf("failed to disconnect grabber output pin\n");
                tearDown();
                return false;
            }

            //SaveGraphFile(m_pGraph, L"test1.grf");

            //we have to remove it as well otherwise the graph builder will reconnect it
            hr = m_pGraph->RemoveFilter(m_pVideoRenderer);
            if (FAILED(hr)){
                printf("failed to remove the default renderer\n");
                tearDown();
                return false;
            }else{
                m_pVideoRenderer->Release();
            }

            //now connect the null renderer to the grabber output, if we don‘t do this not frames will be captured
            hr = m_pNullRenderer->FindPin(L"In", &pinIn);
            if (FAILED(hr)){
                printf("failed to find the input pin of the null renderer\n");
                tearDown();
                return false;
            }

            hr = pinOut->Connect(pinIn, NULL);
            if (FAILED(hr)){
                printf("failed to connect the null renderer\n");
                tearDown();
                return false;
            }

            //printf("step 8\n");
            // Run the graph.

            //SaveGraphFile(m_pGraph, L"test2.grf");
            hr = m_pControl->Run();
            //SaveGraphFile(m_pGraph, L"test3.grf");

            // Now pause the graph.
            hr = m_pControl->Stop();
            updatePlayState();

            if( FAILED(hr) || width == 0 || height == 0 ){
                tearDown();
                printf("Error occured while playing or pausing or opening the file\n");
                return false;
            }else{
                rawBuffer = new unsigned char[videoSize];
                //printf("success!\n");
            }
        }else{
            tearDown();
            printf("Error occured while playing or pausing or opening the file\n");
            return false;
        }

        bVideoOpened = true;
        return true;
    }

    void update(){
        if( bVideoOpened ){

            long eventCode = 0;
#ifdef _WIN64
            long long ptrParam1 = 0;
            long long ptrParam2 = 0;
#else
            long ptrParam1 = 0;
            long ptrParam2 = 0;
#endif
            long timeoutMs = 2000;

            if( curMovieFrame != frameCount ){
                bFrameNew = true;
            }else{
                bFrameNew = false;
            }
            curMovieFrame = frameCount;

            while (S_OK == m_pEvent->GetEvent(&eventCode, &ptrParam1, &ptrParam2, 0)){
                if (eventCode == EC_COMPLETE ){
                    if(bLoop){
                        //printf("Restarting!\n");
                        setPosition(0.0);
                    }else{
                        bEndReached = true;
                        //printf("movie end reached!\n");
                        stop();
                        updatePlayState();
                    }
                }
                //printf("Event code: %#04x\n Params: %d, %d\n", eventCode, ptrParam1, ptrParam2);
                m_pEvent->FreeEventParams(eventCode, ptrParam1, ptrParam2);
            }
        }
    }

    bool isLoaded(){
        return bVideoOpened;
    }

    //volume has to be log corrected/converted
    void setVolume(float volPct){
        if( isLoaded() ){
            if( volPct < 0 ) volPct = 0.0;
            if( volPct > 1 ) volPct = 1.0; 

            long vol = log10(volPct) * 4000.0;
            m_pAudio->put_Volume(vol);
        }
    }

    float getVolume(){
        float volPct = 0.0;
        if( isLoaded() ){
            long vol = 0;
            m_pAudio->get_Volume(&vol);
            volPct = powf(10, (float)vol/4000.0);
        }
        return volPct;
    }

    double getDurationInSeconds(){
        if( isLoaded() ){
            long long lDurationInNanoSecs = 0;
            m_pSeek->GetDuration(&lDurationInNanoSecs);
            double timeInSeconds = (double)lDurationInNanoSecs/10000000.0;

            return timeInSeconds;
        }
        return 0.0;
    }

    double getCurrentTimeInSeconds(){
        if( isLoaded() ){
            long long lCurrentTimeInNanoSecs = 0;
            m_pSeek->GetCurrentPosition(&lCurrentTimeInNanoSecs);
            double timeInSeconds = (double)lCurrentTimeInNanoSecs/10000000.0;

            return timeInSeconds;
        }
        return 0.0;
    }

    void setPosition(float pct){
        if( bVideoOpened ){
            if( pct < 0.0 ) pct = 0.0;
            if( pct > 1.0 ) pct = 1.0; 

            long long lDurationInNanoSecs = 0;
            m_pSeek->GetDuration(&lDurationInNanoSecs);

            rtNew = ((float)lDurationInNanoSecs * pct);
            hr = m_pSeek->SetPositions(&rtNew, AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
        }
    }

    float getPosition(){
        if( bVideoOpened ){
            float timeDur = getDurationInSeconds();
            if( timeDur > 0.0 ){
                return getCurrentTimeInSeconds() / timeDur;
            }
        }
        return 0.0;
    }

    void setSpeed(float speed){
        if( bVideoOpened ){
            m_pPosition->put_Rate(speed);
            m_pPosition->get_Rate(&movieRate);
        }
    }

    double getSpeed(){
        return movieRate;
    }

    void processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip){

        int widthInBytes = width * 3;
        int numBytes = widthInBytes * height;

        if(!bRGB){

            int x = 0;
            int y = 0;

            if(bFlip){
                for(int y = 0; y < height; y++){
                    memcpy(dst + (y * widthInBytes), src + ( (height -y -1) * widthInBytes), widthInBytes);
                }

            }else{
                memcpy(dst, src, numBytes);
            }
        }else{
            if(bFlip){

                int x = 0;
                int y = (height - 1) * widthInBytes;
                src += y;

                for(int i = 0; i < numBytes; i+=3){
                    if(x >= width){
                        x = 0;
                        src -= widthInBytes*2;
                    }

                    *dst = *(src+2);
                    dst++;

                    *dst = *(src+1);
                    dst++;

                    *dst = *src;
                    dst++;

                    src+=3;
                    x++;
                }
            }
            else{
                for(int i = 0; i < numBytes; i+=3){
                    *dst = *(src+2);
                    dst++;

                    *dst = *(src+1);
                    dst++;

                    *dst = *src;
                    dst++;

                    src+=3;
                }
            }
        }
    }

    void play(){
        if( bVideoOpened ){
            m_pControl->Run();
            bEndReached = false;
            updatePlayState();
        }
    }

    void stop(){
        if( bVideoOpened ){
            if( isPlaying() ){
                setPosition(0.0);
            }
            m_pControl->Stop();
            updatePlayState();
        }
    }

    void setPaused(bool bPaused){
        if( bVideoOpened ){
            if( bPaused ){
                m_pControl->Pause();
            }else{
                m_pControl->Run();
            }
            updatePlayState();
        }

    }

    void updatePlayState(){
        if( bVideoOpened ){
            FILTER_STATE fs;
            hr = m_pControl->GetState(4000, (OAFilterState*)&fs);
            if(hr==S_OK){
                if( fs == State_Running ){
                    bPlaying = true;
                    bPaused = false;
                }
                else if( fs == State_Paused ){
                    bPlaying = false;
                    bPaused = true;
                }else if( fs == State_Stopped ){
                    bPlaying = false;
                    bPaused = false;
                }
            }
        }
    }

    bool isPlaying(){
        return bPlaying;
    }

    bool isPaused(){
        return bPaused;
    }

    bool isLooping(){
        return bLoop;
    }

    void setLoop(bool loop){
        bLoop = loop;
    }

    bool isMovieDone(){
        return bEndReached;
    }

    float getWidth(){
        return width;
    }

    float getHeight(){
        return height;
    }

    bool isFrameNew(){
        return bFrameNew;
    }

    void nextFrame(){
        //we have to do it like this as the frame based approach is not very accurate
        if( bVideoOpened && ( isPlaying() || isPaused() ) ){
            int curFrame = getCurrentFrameNo();
            float curFrameF = curFrame;
            for(int i = 1; i < 20; i++){
                setAproximateFrameF( curFrameF + 0.3 * (float)i );
                if( getCurrentFrameNo() >= curFrame + 1 ){
                    break;
                }
            }
        }
    }

    void preFrame(){
        //we have to do it like this as the frame based approach is not very accurate
        if( bVideoOpened && ( isPlaying() || isPaused() ) ){
            int curFrame = getCurrentFrameNo();
            float curFrameF = curFrame;
            for(int i = 1; i < 20; i++){
                setAproximateFrameF( curFrameF - 0.3 * (float)i );
                if( getCurrentFrameNo() <= curFrame + 1 ){
                    break;
                }
            }
        }
    }

    void setAproximateFrameF(float frameF){
        if( bVideoOpened ){
            float pct = frameF / (float)getAproximateNoFrames();
            if( pct > 1.0 ) pct = 1.0;
            if( pct < 0.0 ) pct = 0.0;
            setPosition(pct);
        }
    }

    void setAproximateFrame(int frame){
        if( bVideoOpened ){
            float pct = (float)frame / (float)getAproximateNoFrames();
            if( pct > 1.0 ) pct = 1.0;
            if( pct < 0.0 ) pct = 0.0;
            setPosition(pct);
        }
    }

    int getCurrentFrameNo(){
        if( bVideoOpened ){
            return getPosition() * (float) getAproximateNoFrames();
        }
        return 0;
    }

    int getAproximateNoFrames(){
        if( bVideoOpened && averageTimePerFrame > 0.0 ){
            return getDurationInSeconds() / averageTimePerFrame;
        }
        return 0;
    }

    void getPixels(unsigned char * dstBuffer){

        if(bVideoOpened && bNewPixels){

            EnterCriticalSection(&critSection);
                processPixels(rawBuffer, dstBuffer, width, height, true, true);
                bNewPixels = false;
            LeaveCriticalSection(&critSection);

        }
    }

    //this is the non-callback approach
    //void getPixels(unsigned char * dstBuffer){
    //
    //  if(bVideoOpened && isFrameNew()){
    //      long bufferSize = videoSize;
    //      HRESULT hr = m_pGrabber->GetCurrentBuffer(&bufferSize, (long *)rawBuffer);
    //
    //      if(hr==S_OK){
    //          if (videoSize == bufferSize){
    //              processPixels(rawBuffer, dstBuffer, width, height, true, true);
    //          }else{
    //              printf("ERROR: GetPixels() - bufferSizes do not match!\n");
    //          }
    //      }else{
    //          printf("ERROR: GetPixels() - Unable to get pixels for device  bufferSize = %i \n", bufferSize);
    //      }
    //  }
    //}

    protected:

    HRESULT hr;                         // COM return value
    IGraphBuilder *m_pGraph;        // Graph Builder interface
    IMediaControl *m_pControl;  // Media Control interface
    IMediaEvent   *m_pEvent;        // Media Event interface
    IMediaSeeking *m_pSeek;     // Media Seeking interface
    IMediaPosition * m_pPosition;
    IBasicAudio   *m_pAudio;        // Audio Settings interface
    ISampleGrabber * m_pGrabber;
    IBaseFilter * m_pSourceFile;
    IBaseFilter * m_pGrabberF;
    IBasicVideo * m_pBasicVideo;
    IBaseFilter * m_pNullRenderer;

    REFERENCE_TIME timeNow;             // Used for FF & REW of movie, current time
    LONGLONG lPositionInSecs;       // Time in  seconds
    LONGLONG lDurationInNanoSecs;       // Duration in nanoseconds
    LONGLONG lTotalDuration;        // Total duration
    REFERENCE_TIME rtNew;               // Reference time of movie
    long lPosition;                 // Desired position of movie used in FF & REW
    long lvolume;                   // The volume level in 1/100ths dB Valid values range from -10,000 (silence) to 0 (full volume), 0 = 0 dB -10000 = -100 dB
    long evCode;                    // event variable, used to in file to complete wait.

    long width, height;
    long videoSize;

    double averageTimePerFrame; 

    bool bFrameNew;
    bool bNewPixels;
    bool bVideoOpened;
    bool bPlaying;
    bool bPaused;
    bool bLoop;
    bool bEndReached;
    double movieRate;
    int curMovieFrame;
    int frameCount;

    CRITICAL_SECTION critSection;
    unsigned char * rawBuffer;
};

class MiDirectShowPlayer
{
public:
    DirectShowVideo  m_Player;
    unsigned char* buffer;

    GLuint   m_Texid;
    int   m_Width;
    int   m_Height;

public:
    bool Load(std::string filename)
    {
        buffer = NULL;

        return m_Player.loadMovie(filename);
    }

    void close()
    {

    }

    void update()
    {
        if(m_Player.isLoaded())
        {
            m_Width = m_Player.getWidth();
            m_Height = m_Player.getHeight();

            m_Player.update();

            if(buffer == NULL)
            {
                int sizei = m_Player.getWidth() * m_Player.getHeight() * 3;
                buffer = new unsigned char[sizei];
            }

            m_Player.getPixels(buffer);
            BuildTex();

        }

    }

    void BuildTex()
    {
        if(m_Texid !=0)
        {
            glDeleteTextures(1,&m_Texid);
        }

        glGenTextures(1,&m_Texid);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D,m_Texid);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D,0,3,m_Width,m_Height,0,GL_RGB,GL_UNSIGNED_BYTE,buffer);

        printf("texid:%d \n",m_Texid);

    }

    void Play()
    {
        if(m_Player.isLoaded())
        {
            m_Player.play();
        }
    }

    void Stop()
    {
        if(m_Player.isLoaded())
        {
            m_Player.stop();
        }
    }

    bool isFrameNew()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.isFrameNew();
        }
    }

    float  GetWidth()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.getWidth();
        }
    }

    float GetHeight()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.getHeight();
        }
    }

    bool isPaused()
    {
        return m_Player.isPaused();
    }

    bool isLoaded()
    {
        return m_Player.isLoaded();
    }

    bool isPlaying()
    {
        return m_Player.isPlaying();
    }

    float GetPostion()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.getPosition();
        }
        return 0.0f;
    }

    float GetSpeed()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.getSpeed();
        }
        return 0.0f;
    }

    float getDuration()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.getDurationInSeconds();
        }
        return 0.0f;
    }

    void SetPause(bool p)
    {
        if(m_Player.isLoaded())
        {
            m_Player.setPaused(p);
        }
    }

    void setPostion(float f)
    {
        if(m_Player.isLoaded())
        {
            m_Player.setPosition(f);
        }
    }

    void  setVolume(float volume)
    {
        if(m_Player.isLoaded())
        {
            m_Player.setVolume(volume);
        }
    }

    void setLoopState(bool b)
    {
        if(m_Player.isLoaded())
        {
            m_Player.setLoop(b);
        }
    }

    int getCurrentFrame()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.getCurrentFrameNo();
        }

        return 0;
    }

    int getTotalNumFrames()
    {
        if(m_Player.isLoaded())
        {
            return m_Player.getAproximateNoFrames();
        }

        return 0;
    }

    void SetFrame(int f)
    {
        if(m_Player.isLoaded())
        {
            if(f <0)
                f =0;
            if(f > getTotalNumFrames())
                f = getTotalNumFrames();

            m_Player.setAproximateFrame(f);

        }
    }

};

代码里先把视屏的每一帧图像得到,放到一个缓冲buffer里,然后用这个buffer生成纹理,纹理贴到窗口上就好了

下面这个OpenGL更新

        m_DShowPlayer.update();
            /* OpenGL animation code goes here */

            glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
            glClear (GL_COLOR_BUFFER_BIT);

            glPushMatrix ();
           // glRotatef (0, 0.0f, 0.0f, 1.0f);

            glEnable(GL_TEXTURE_2D);
            glBindTexture(GL_TEXTURE_2D,m_DShowPlayer.m_Texid);
            DrawRect(0,0,1024,768);
            glPopMatrix ();

            SwapBuffers (hDC);
时间: 2024-08-02 01:40:02

DShow + OpenGL播放视屏的相关文章

实验6 在应用程序中播放音频和视屏

实验报告 课程名称 基于Android平台移动互联网开发 实验日期 4.15 实验项目名称 在应用程序中播放音频和视屏 实验地点 S3010 实验类型 □验证型    √设计型    □综合型 学  时 1学时 一.实验目的及要求(本实验所涉及并要求掌握的知识点) 实现在应用程序中处理音频和视频 实现播放音频,音频播放控制 实现播放视屏,视屏播放控制 使用service服务播放项目原文件的音乐 二.实验环境(本实验所使用的硬件设备和相关软件) (1)PC机 (2)操作系统:Windows XP

最简单的视音频播放示例4:OpenGL播放RGB/YUV

本文记录OpenGL播放视频的技术.OpenGL是一个和Direct3D同一层面的技术.相比于Direct3D,OpenGL具有跨平台的优势.尽管在游戏领域,DirectX的影响力已渐渐超越OpenGL并被大多数PC游戏开发商所采用,但在专业高端绘图领域,OpenGL因为色彩准确,仍然是不能被取代的主角. OpenGL简介 从网上搜集了一些有关OpenGL简介方面的知识,在这里列出来.开放图形库(英语:Open Graphics Library,缩写为OpenGL)是个定义了一个跨编程语言.跨平

Android中使用SurfaceView+MediaPlayer+自定义的MediaController实现自定义的视屏播放器

效果图如下: (PS本来是要给大家穿gif动态图的,无奈太大了,没法上传) 功能实现:暂停,播放,快进,快退,全屏,退出全屏,等基本功能 实现的思路: 在主布局中放置一个SurfaceView,在SurfaceView中放置一个MediaPlayer ,在其下方自定义一个MediaController,不过也不能称之为MediaController,使用的是PupupWindow来实现的,在PupupWindow布局中放置几个textView,Button,最重要的使我们的SeekBar控件,创

最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)

本文记录OpenGL播放视频的技术.上一篇文章中,介绍了一种简单的使用OpenGL显示视频的方式.但是那还不是OpenGL显示视频技术的精髓.和Direct3D一样,OpenGL更好的显示视频的方式也是通过纹理(Texture).本文介绍OpenGL通过纹理的方式显示视频的技术. OpenGL中坐标和Direct3D坐标的不同 OpenGL中的纹理的坐标和Direct3D中的坐标是不一样的. 在Direct3D中.纹理坐标如下图所示.取值是0到1.坐标系原点在左上角. 物体表面坐标如下图所示.取

使用videoview连续自动播放网络视屏

需求:网络请求接口,实现自动依次播放视频 1:xml布局文件 <VideoView android:id="@+id/video" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" /> 2.MainActivity页面,开启线程请求视屏接口 线程请求接口

android 下的一段视屏播放的逻辑

android 下的一段视屏播放的逻辑只是Activity的一部分逻辑源码 DemoActivity: public class DemoActivity extends Activity implements OnClickListener { EditText et_path; Button bt_start; Button bt_pause; Button bt_restart; Button bt_stop; SurfaceView sv; SurfaceHolder holder; M

h5-自定义视屏播放器

1.html代码 1 <h3 class="playerTitle">视屏播放器</h3> 2 <div class="player"> 3 <video src="../mp4/chrome.mp4"></video> 4 <div class="controls"> 5 <!--比如这里的开始和暂停图标就是font-awesome.css文件中的

u3d加载外部视屏

u3d的外部加载视屏,采用www方式,可以使用gui播放,也可以绑定到gameobject上作为动态材质使用,不过目前只支持.ogg格式,需要转... using UnityEngine;using System.Collections; public class movie : MonoBehaviour{    private MovieTexture movTexture;     private string movPath;     void Start()    {        m

opencv视屏流嵌入wxpython框架

前几篇博客分享搭建人脸识别与情绪判断的环境和源码,但是没有UI,界面很难看,一打开就是opencv弹出的一个视屏框.处女座的我看着非常难受,于是决定做一个UI,稍微规矩好看一点,再怎么说,这样的话也算是一个小软件,不再是运行源码了. 上网到处查了一圈之后,发现这是一个空缺,好像没有人在做这个,看到的唯一一个有点相似的是用wxpython制作一个视屏播放器.和这个显示opencv的实时视屏还是有点差距的,但是也有指导作用. 使用版本:python-3.6.3(anaconda)   opencv-