通过 directshow 播放文件 wmv

如何解决通过 directshow 播放文件 wmv

我有一个通过 directshow 播放文件 wmv 的 dll。

这里的主要功能: 玩家:

    include "common.h"
    #include "dshow.player.h"
    #include "dshow.playback.h"
    
    class DShowWindow
    {
    public:
        DShowWindow(std::wstring name);
        ~DShowWindow();
    
    public:
        static HRESULT PlayVideo(HWND owner,std::wstring name,std::wstring filename);
    
    private:
        static LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
        LRESULT HandleMessages(HWND hwnd,LPARAM lParam);
        static void CALLBACK GraphEventProc(HWND hwnd,long evCode,LONG_PTR param1,LONG_PTR param2);
        void OnGraphEvent(HWND hwnd,LONG_PTR param2);
        void OnPaint(HWND hwnd);
        void OnSize(HWND hwnd);
        HRESULT Play(HWND owner,std::wstring filename);
    
    private:
        ATOM classAtom;
        HWND windowHandle;
    
        std::unique_ptr<DShowPlayer> player;
    
        bool continuePlayback;
        bool userInterrupted;
    };
    
    DShowWindow::DShowWindow(std::wstring name)
    {
        this->userInterrupted = false;
    
        WNDCLASS wc{};
        wc.lpfnWndProc = DShowWindow::WndProc;
        wc.lpszClassName = name.c_str();
    
        this->classAtom = RegisterClass(&wc);
    
        if (!this->classAtom)
        {
            return;
        }
    
        this->windowHandle = CreateWindowEx(
            0,(LPWSTR)this->classAtom,L"DirectShow Playback",WS_POPUP | WS_EX_TOPMOST,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN),nullptr,nullptr);
    
        if (this->windowHandle == nullptr)
        {
            return;
        }
    
        SetWindowLongPtr(this->windowHandle,GWLP_USERDATA,reinterpret_cast<LONG_PTR>(this));
    }
    
    DShowWindow::~DShowWindow()
    {
        if (this->windowHandle)
        {
            DestroyWindow(this->windowHandle);
        }
    
        if (this->classAtom)
        {
            UnregisterClass((LPWSTR)this->classAtom,nullptr);
        }
    }
    
    HRESULT DShowWindow::PlayVideo(HWND owner,std::wstring filename)
    {
        DShowWindow window{ name };
    
        HRESULT hr = window.Play(owner,filename);
    
        if (FAILED(hr))
        {
            return hr;
        }
    
        return window.userInterrupted ? S_FALSE : S_OK;
    }
    
    LRESULT CALLBACK DShowWindow::WndProc(HWND hwnd,LPARAM lParam)
    {
        LONG_PTR ptr = GetWindowLongPtr(hwnd,GWLP_USERDATA);
    
        if (ptr == 0)
        {
            return DefWindowProc(hwnd,uMsg,wParam,lParam);
        }
    
        return reinterpret_cast<DShowWindow*>(ptr)->HandleMessages(hwnd,lParam);
    }
    
    LRESULT DShowWindow::HandleMessages(HWND hwnd,LPARAM lParam)
    {
        switch (uMsg)
        {
        case WM_DESTROY:
            this->continuePlayback = false;
            this->userInterrupted = true;
            return 0;
    
        case WM_DISPLAYCHANGE:
            if (this->player)
            {
                this->player->DisplayModeChanged();
            }
            break;
    
        case WM_ERASEBKGND:
            return 1;
    
        case WM_PAINT:
            OnPaint(hwnd);
            return 0;
    
        case WM_SIZE:
            OnSize(hwnd);
            return 0;
    
        case WM_KEYDOWN:
            switch (wParam)
            {
            case VK_ESCAPE:
            case VK_SPACE:
            case VK_RETURN:
            case VK_BACK:
                this->continuePlayback = false;
                this->userInterrupted = true;
                break;
            }
            break;
    
        case WM_LBUTTONDOWN:
        case WM_RBUTTONDOWN:
            this->continuePlayback = false;
            this->userInterrupted = true;
            break;
    
        case WM_GRAPH_EVENT:
            if (this->player)
            {
                this->player->HandleGraphEvent(DShowWindow::GraphEventProc);
            }
            return 0;
        }
    
        return DefWindowProc(hwnd,lParam);
    }
    
    void CALLBACK DShowWindow::GraphEventProc(HWND hwnd,LONG_PTR param2)
    {
        LONG_PTR ptr = GetWindowLongPtr(hwnd,GWLP_USERDATA);
    
        if (ptr == 0)
        {
            return;
        }
    
        return reinterpret_cast<DShowWindow*>(ptr)->OnGraphEvent(hwnd,evCode,param1,param2);
    }
    
    void DShowWindow::OnGraphEvent(HWND hwnd,LONG_PTR param2)
    {
        switch (evCode)
        {
        case EC_COMPLETE:
        case EC_ERRORABORT:
            this->player->Stop();
            this->continuePlayback = false;
            break;
    
        case EC_USERABORT:
            this->player->Stop();
            this->continuePlayback = false;
            this->userInterrupted = true;
            break;
        }
    }
    
    void DShowWindow::OnPaint(HWND hwnd)
    {
        PAINTSTRUCT ps;
        HDC hdc;
    
        hdc = BeginPaint(hwnd,&ps);
    
        if (this->player->State() != STATE_NO_GRAPH && this->player->HasVideo())
        {
            this->player->Repaint(hdc);
        }
        else
        {
            FillRect(hdc,&ps.rcPaint,(HBRUSH)GetStockObject(BLACK_BRUSH));
        }
    
        EndPaint(hwnd,&ps);
    }
    
    void DShowWindow::OnSize(HWND hwnd)
    {
        if (this->player)
        {
            RECT rc;
            GetClientRect(hwnd,&rc);
    
            this->player->UpdateVideoWindow(&rc);
        }
    }
    
    HRESULT DShowWindow::Play(HWND owner,std::wstring filename)
    {
        this->continuePlayback = true;
        this->userInterrupted = false;
    
        if (!this->windowHandle)
        {
            return E_FAIL;
        }
    
        this->player = std::make_unique<DShowPlayer>(this->windowHandle);
    
        if (this->player == nullptr)
        {
            return E_FAIL;
        }
    
        HRESULT hr;
    
        hr = this->player->OpenFile(filename.c_str());
        if (FAILED(hr))
        {
            return hr;
        }
    
        InvalidateRect(this->windowHandle,NULL,FALSE);
        this->OnSize(this->windowHandle);
    
        ShowWindow(this->windowHandle,SW_MAXIMIZE);
    
        while (ShowCursor(FALSE) >= 0);
    
        hr = this->player->Play();
        if (FAILED(hr))
        {
            return hr;
        }
    
        MSG msg{};
        while (this->continuePlayback && GetMessage(&msg,this->windowHandle,0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
         this->player.reset();
    
    
        return S_OK;
    }
    
    int DShowPlayVideo(std::wstring filename)
    {
        HWND xwaWindow = *(HWND*)0x9F701A;
        LPDIRECTDRAW xwaDirectDraw = *(LPDIRECTDRAW*)0x9F7026;
        int& xwaUserInterrupted = *(int*)0x9F4B40;
    
        xwaDirectDraw->RestoreDisplayMode();
    
        // Free DirectDraw resources
        ((void(*)())0x5407F0)();
    
        int returnValue = 0;
    
        HRESULT hr;
        if (FAILED(hr = DShowWindow::PlayVideo(xwaWindow,L"tgsmushPlayer",filename)))
        {
            wchar_t error[MAX_ERROR_TEXT_LEN];
            AMGetErrorText(hr,error,MAX_ERROR_TEXT_LEN);
    
            OutputDebugString(error);
        }
        else if (hr == S_FALSE)
        {
            xwaUserInterrupted = 1;
            returnValue = 1;
        }
    
         SetForegroundWindow(xwaWindow);
         ShowWindow(xwaWindow,SW_MAXIMIZE);
    
        // Init DirectDraw resources
         ((void(*)())0x540370)();
    
        return returnValue;
    }

回放:

DShowPlayer::DShowPlayer(HWND hwnd)
    :m_state(STATE_NO_GRAPH),m_hwnd(hwnd)
{
}

DShowPlayer::~DShowPlayer()
{
    // Stop sending event messages
    if (m_pEvent)
    {
        m_pEvent->SetNotifyWindow((OAHWND)NULL,NULL);
    }
}

// Open a media file for playback.
HRESULT DShowPlayer::OpenFile(PCWSTR pszFileName)
{
    HRESULT hr;
    ComPtr<IBaseFilter> pSource;

    // Create a new filter graph. (This also closes the old one,if any.)
    hr = InitializeGraph();

    if (SUCCEEDED(hr))
    {
        // Add the source filter to the graph.
        hr = m_pGraph->AddSourceFilter(pszFileName,&pSource);
    }

    if (SUCCEEDED(hr))
    {
        // Try to render the streams.
        hr = RenderStreams(pSource);
    }

    return hr;
}


// Respond to a graph event.
//
// The owning window should call this method when it receives the window
// message that the application specified when it called SetEventWindow.
//
// Caution: Do not tear down the graph from inside the callback.

HRESULT DShowPlayer::HandleGraphEvent(GraphEventFN pfnOnGraphEvent)
{
    if (!m_pEvent)
    {
        return E_UNEXPECTED;
    }

    long evCode = 0;
    LONG_PTR param1 = 0,param2 = 0;

    HRESULT hr = S_OK;

    // Get the events from the queue.
    while (SUCCEEDED(m_pEvent->GetEvent(&evCode,&param1,&param2,0)))
    {
        // Invoke the callback.
        pfnOnGraphEvent(m_hwnd,param2);

        // Free the event data.
        hr = m_pEvent->FreeEventParams(evCode,param2);
        if (FAILED(hr))
        {
            break;
        }
    }

    return hr;
}

HRESULT DShowPlayer::Play()
{
    if (m_state != STATE_PAUSED && m_state != STATE_STOPPED)
    {
        return VFW_E_WRONG_STATE;
    }

    HRESULT hr = m_pControl->Run();

    if (SUCCEEDED(hr))
    {
        m_state = STATE_RUNNING;
    }

    return hr;
}

HRESULT DShowPlayer::Pause()
{
    if (m_state != STATE_RUNNING)
    {
        return VFW_E_WRONG_STATE;
    }

    HRESULT hr = m_pControl->Pause();

    if (SUCCEEDED(hr))
    {
        m_state = STATE_PAUSED;
    }

    return hr;
}

HRESULT DShowPlayer::Stop()
{
    if (m_state != STATE_RUNNING && m_state != STATE_PAUSED)
    {
        return VFW_E_WRONG_STATE;
    }

    HRESULT hr = m_pControl->Stop();

    if (SUCCEEDED(hr))
    {
        m_state = STATE_STOPPED;
    }

    return hr;
}


// EVR/VMR functionality

BOOL DShowPlayer::HasVideo() const
{
    return (m_pVideo && m_pVideo->HasVideo());
}

// Sets the destination rectangle for the video.

HRESULT DShowPlayer::UpdateVideoWindow(const LPRECT prc)
{
    if (m_pVideo)
    {
        return m_pVideo->UpdateVideoWindow(m_hwnd,prc);
    }
    else
    {
        return S_OK;
    }
}

// Repaints the video. Call this method when the application receives WM_PAINT.

HRESULT DShowPlayer::Repaint(HDC hdc)
{
    if (m_pVideo)
    {
        return m_pVideo->Repaint(m_hwnd,hdc);
    }
    else
    {
        return S_OK;
    }
}


// Notifies the video renderer that the display mode changed.
//
// Call this method when the application receives WM_DISPLAYCHANGE.

HRESULT DShowPlayer::DisplayModeChanged()
{
    if (m_pVideo)
    {
        return m_pVideo->DisplayModeChanged();
    }
    else
    {
        return S_OK;
    }
}


// Graph building

// Create a new filter graph. 
HRESULT DShowPlayer::InitializeGraph()
{
    HRESULT hr;

    // Create the Filter Graph Manager.
    hr = CoCreateInstance(CLSID_FilterGraph,CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&m_pGraph));

    if (FAILED(hr))
    {
        return hr;
    }

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pControl));
    if (FAILED(hr))
    {
        return hr;
    }

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pEvent));
    if (FAILED(hr))
    {
        return hr;
    }

    // Set up event notification.
    hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwnd,WM_GRAPH_EVENT,NULL);
    if (FAILED(hr))
    {
        return hr;
    }

    m_state = STATE_STOPPED;

    return hr;
}


HRESULT DShowPlayer::CreateVideoRenderer()
{
    HRESULT hr = E_FAIL;

    enum { Try_EVR,Try_VMR9,Try_VMR7 };

    for (DWORD i = Try_EVR; i <= Try_VMR7; i++)
    {
        switch (i)
        {
        case Try_EVR:
            m_pVideo = std::make_unique<CEVR>();
            break;

        case Try_VMR9:
            m_pVideo = std::make_unique<CVMR9>();
            break;

        case Try_VMR7:
            m_pVideo = std::make_unique<CVMR7>();
            break;
        }

        if (m_pVideo == nullptr)
        {
            hr = E_OUTOFMEMORY;
            break;
        }

        hr = m_pVideo->AddToGraph(m_pGraph,m_hwnd);

        if (SUCCEEDED(hr))
        {
            break;
        }

        m_pVideo.reset();
    }

    return hr;
}


// Render the streams from a source filter. 

HRESULT DShowPlayer::RenderStreams(IBaseFilter *pSource)
{
    HRESULT hr;
    BOOL bRenderedAnyPin = FALSE;

    ComPtr<IFilterGraph2> pGraph2;
    ComPtr<IEnumPins> pEnum;
    ComPtr<IBaseFilter> pAudioRenderer;

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&pGraph2));
    if (FAILED(hr))
    {
        return hr;
    }

    // Add the video renderer to the graph
    hr = CreateVideoRenderer();
    if (FAILED(hr))
    {
        return hr;
    }

    // Add the DSound Renderer to the graph.
    hr = AddFilterByCLSID(m_pGraph,CLSID_DSoundRender,&pAudioRenderer,L"Audio Renderer");
    if (FAILED(hr))
    {
        return hr;
    }

    // Enumerate the pins on the source filter.
    hr = pSource->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        return hr;
    }

    // Loop through all the pins
    ComPtr<IPin> pPin;
    while (pEnum->Next(1,&pPin,nullptr) == S_OK)
    {
        // Try to render this pin. 
        // It's OK if we fail some pins,if at least one pin renders.
        HRESULT hr2 = pGraph2->RenderEx(pPin,AM_RENDEREX_RENDERTOEXISTINGRENDERERS,NULL);

        if (SUCCEEDED(hr2))
        {
            bRenderedAnyPin = TRUE;
        }
    }

    hr = m_pVideo->FinalizeGraph(m_pGraph);
    if (FAILED(hr))
    {
        return hr;
    }

    // Remove the audio renderer,if not used.
    BOOL bRemoved;
    hr = RemoveUnconnectedRenderer(m_pGraph,pAudioRenderer,&bRemoved);

    // If we succeeded to this point,make sure we rendered at least one 
    // stream.
    if (SUCCEEDED(hr))
    {
        if (!bRenderedAnyPin)
        {
            hr = VFW_E_CANNOT_RENDER;
        }
    }

    return hr;
}

这个 dll 是一个钩子,用于添加对高分辨率视频文件的支持。

方法:播放播放wmv文件,效果很好。

但遗憾的是,在完成视频后,出现了 1 秒或更短的黑屏。

DLL 包含其他方法,可以播放 avi 文件而不会出现任何黑屏,但无法读取 60 FPS 文件(播放限制为 15 FPS)。

所以实际上最好的折衷方案是这 2 个运行良好的 cpp 文件,但在完成播放时添加了这个简短的黑屏。

我已尝试重新整理这些行:

   // MSG msg{};
    //  while (this->continuePlayback && GetMessage(&msg,0))
   //   {
   //       TranslateMessage(&msg);
   //       DispatchMessage(&msg);
   //   }
    
   //    this->player.reset();

并且没有黑屏但不能播放视频。

我怀疑在收到消息时会产生这种短黑屏。

但我没有任何直播播放经验。

你能帮我吗?

谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res