=====================================================

Media Player Classic - HC 源代码分析系列文章列表:

Media Player Classic - HC 源代码分析 1:整体结构

Media Player Classic - HC 源代码分析 2:核心类 (CMainFrame)(1)

Media Player Classic - HC 源代码分析 3:核心类 (CMainFrame)(2)

Media Player Classic - HC 源代码分析 4:核心类 (CMainFrame)(3)

Media Player Classic - HC 源代码分析 5:关于对话框 (CAboutDlg)

Media Player Classic - HC 源代码分析 6:MediaInfo选项卡 (CPPageFileMediaInfo)

Media Player Classic - HC 源代码分析 7:详细信息选项卡(CPPageFileInfoDetails)

=====================================================

前几篇文章分析了Media Player Classic - HC(mpc-hc)的核心类(CMainFrame):

Media Player Classic - HC 源代码分析 2:核心类 (CMainFrame)(1)

Media Player Classic - HC 源代码分析 3:核心类 (CMainFrame)(2)

Media Player Classic - HC 源代码分析 4:核心类 (CMainFrame)(3)

核心类分析完之后,分析了其他几个重要的类:

Media Player Classic - HC 源代码分析 5:关于对话框 (CAboutDlg)

Media Player Classic - HC 源代码分析 5:MediaInfo选项卡 (CPPageFileMediaInfo)

本文分析一下mpc-hc的详细信息选项卡。在播放视频的时候,右键点击视频->选择“属性”后默认打开的就是该选项卡。一般情况下,该选项卡给出了正在播放的视频文件的一些基本参数:视频大小,分辨率,时长等。注意:详细信息选项卡和MediaInfo选项卡获得视频参数的原理是不一样的。详细信息选项卡是通过调用DirectShow函数接口而获得的视频的参数。而MediaInfo选项卡则是通过调用MediaInfo类库而获得视频的参数。

先看看选项卡长什么样子:

先来看看详细信息选项卡类的定义是什么样的吧。该类的定义位于PPageFileInfoDetails.h文件中。

/* 雷霄骅
 * 中国传媒大学/数字电视技术
 * leixiaohua1020@126.com
 *
 */
/*
 * (C) 2003-2006 Gabest
 * (C) 2006-2012 see Authors.txt
 *
 * This file is part of MPC-HC.
 *
 * MPC-HC 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 3 of the License, or
 * (at your option) any later version.
 *
 * MPC-HC 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, see <http://www.gnu.org/licenses/>.
 *
 */

#pragma once

#include "../SubPic/ISubPic.h"
#include <afxwin.h>

//取得一些基本信息
// CPPageFileInfoDetails dialog

class CPPageFileInfoDetails : public CPropertyPage
{
    DECLARE_DYNAMIC(CPPageFileInfoDetails)

private:
    CComPtr<IFilterGraph> m_pFG;
    CComPtr<ISubPicAllocatorPresenter> m_pCAP;

    HICON m_hIcon;

    void InitEncoding();

public:
    CPPageFileInfoDetails(CString fn, IFilterGraph* pFG, ISubPicAllocatorPresenter* pCAP);
    virtual ~CPPageFileInfoDetails();

    // Dialog Data
    enum { IDD = IDD_FILEPROPDETAILS };

    CStatic m_icon;
    CString m_fn;
    CString m_type;
    CString m_size;
    CString m_time;
    CString m_res;
    CString m_created;
    CEdit   m_encoding;

protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    virtual BOOL OnInitDialog();
    virtual BOOL OnSetActive();
    virtual LRESULT OnSetPageFocus(WPARAM wParam, LPARAM lParam);

    DECLARE_MESSAGE_MAP()

public:
};

该类的定义和普通的MFC对话框类差不多,有以下几点是需要注意的:

1.以下两个变量是用于获得对话框上显示的相关的信息的:

CComPtr<IFilterGraph> m_pFG;

CComPtr<ISubPicAllocatorPresenter> m_pCAP;

2.有一系列的字符串变量:m_fn, m_type, m_size, m_time等用于存储获得的信息

详细信息选项卡类的实现位于PPageFileInfoDetails.cpp文件中。

/* 雷霄骅
 * 中国传媒大学/数字电视技术
 * leixiaohua1020@126.com
 *
 */
/*
 * (C) 2003-2006 Gabest
 * (C) 2006-2013 see Authors.txt
 *
 * This file is part of MPC-HC.
 *
 * MPC-HC 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 3 of the License, or
 * (at your option) any later version.
 *
 * MPC-HC 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, see <http://www.gnu.org/licenses/>.
 *
 */
//取得一些基本信息
#include "stdafx.h"
#include "mplayerc.h"
#include "PPageFileInfoDetails.h"
#include <atlbase.h>
#include "DSUtil.h"
#include "text.h"
#include <d3d9.h>
#include <vmr9.h>
#include "moreuuids.h"

// CPPageFileInfoDetails dialog

IMPLEMENT_DYNAMIC(CPPageFileInfoDetails, CPropertyPage)
CPPageFileInfoDetails::CPPageFileInfoDetails(CString fn, IFilterGraph* pFG, ISubPicAllocatorPresenter* pCAP)
    : CPropertyPage(CPPageFileInfoDetails::IDD, CPPageFileInfoDetails::IDD)
    , m_fn(fn)
    , m_pFG(pFG)
    , m_pCAP(pCAP)
    , m_hIcon(nullptr)
    , m_type(ResStr(IDS_AG_NOT_KNOWN))
    , m_size(ResStr(IDS_AG_NOT_KNOWN))
    , m_time(ResStr(IDS_AG_NOT_KNOWN))
    , m_res(ResStr(IDS_AG_NOT_KNOWN))
    , m_created(ResStr(IDS_AG_NOT_KNOWN))
{
}

CPPageFileInfoDetails::~CPPageFileInfoDetails()
{
    if (m_hIcon) {
        DestroyIcon(m_hIcon);
    }
}

void CPPageFileInfoDetails::DoDataExchange(CDataExchange* pDX)
{
    __super::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_DEFAULTICON, m_icon);
    DDX_Text(pDX, IDC_EDIT1, m_fn);
    DDX_Text(pDX, IDC_EDIT4, m_type);
    DDX_Text(pDX, IDC_EDIT3, m_size);
    DDX_Text(pDX, IDC_EDIT2, m_time);
    DDX_Text(pDX, IDC_EDIT5, m_res);
    DDX_Text(pDX, IDC_EDIT6, m_created);
    DDX_Control(pDX, IDC_EDIT7, m_encoding);
}

#define SETPAGEFOCUS (WM_APP + 252) // arbitrary number, can be changed if necessary

BEGIN_MESSAGE_MAP(CPPageFileInfoDetails, CPropertyPage)
    ON_MESSAGE(SETPAGEFOCUS, OnSetPageFocus)
END_MESSAGE_MAP()

// CPPageFileInfoDetails message handlers

static bool GetProperty(IFilterGraph* pFG, LPCOLESTR propName, VARIANT* vt)
{
    BeginEnumFilters(pFG, pEF, pBF) {
        if (CComQIPtr<IPropertyBag> pPB = pBF)
            if (SUCCEEDED(pPB->Read(propName, vt, nullptr))) {
                return true;
            }
    }
    EndEnumFilters;

    return false;
}

static CString FormatDateTime(FILETIME tm)
{
    SYSTEMTIME st;
    FileTimeToSystemTime(&tm, &st);
    TCHAR buff[256];
    GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, nullptr, buff, _countof(buff));
    CString ret(buff);
    ret += _T(" ");
    GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, nullptr, buff, _countof(buff));
    ret += buff;
    return ret;
}

BOOL CPPageFileInfoDetails::OnInitDialog()
{
    __super::OnInitDialog();

    if (m_fn.IsEmpty()) {
        BeginEnumFilters(m_pFG, pEF, pBF) {
            CComQIPtr<IFileSourceFilter> pFSF = pBF;
            if (pFSF) {
                LPOLESTR pFN = nullptr;
                AM_MEDIA_TYPE mt;
                if (SUCCEEDED(pFSF->GetCurFile(&pFN, &mt)) && pFN && *pFN) {
                    m_fn = CStringW(pFN);
                    CoTaskMemFree(pFN);
                }
                break;
            }
        }
        EndEnumFilters;
    }

    CString ext = m_fn.Left(m_fn.Find(_T("://")) + 1).TrimRight(':');
    if (ext.IsEmpty() || !ext.CompareNoCase(_T("file"))) {
        ext = _T(".") + m_fn.Mid(m_fn.ReverseFind('.') + 1);
    }

    m_hIcon = LoadIcon(m_fn, false);
    if (m_hIcon) {
        m_icon.SetIcon(m_hIcon);
    }

    if (!LoadType(ext, m_type)) {
        m_type.LoadString(IDS_AG_NOT_KNOWN);
    }

    CComVariant vt;
    if (::GetProperty(m_pFG, L"CurFile.TimeCreated", &vt)) {
        if (V_VT(&vt) == VT_UI8) {
            ULARGE_INTEGER uli;
            uli.QuadPart = V_UI8(&vt);

            FILETIME ft;
            ft.dwLowDateTime = uli.LowPart;
            ft.dwHighDateTime = uli.HighPart;

            m_created = FormatDateTime(ft);
        }
    }

    WIN32_FIND_DATA wfd;
    HANDLE hFind = FindFirstFile(m_fn, &wfd);
    if (hFind != INVALID_HANDLE_VALUE) {
        FindClose(hFind);

        __int64 size = (__int64(wfd.nFileSizeHigh) << 32) | wfd.nFileSizeLow;
        const int MAX_FILE_SIZE_BUFFER = 65;
        WCHAR szFileSize[MAX_FILE_SIZE_BUFFER];
        StrFormatByteSizeW(size, szFileSize, MAX_FILE_SIZE_BUFFER);
        CString szByteSize;
        szByteSize.Format(_T("%I64d"), size);
        m_size.Format(_T("%s (%s bytes)"), szFileSize, FormatNumber(szByteSize));

        if (m_created.IsEmpty()) {
            m_created = FormatDateTime(wfd.ftCreationTime);
        }
    }
	//获取时常
    REFERENCE_TIME rtDur = 0;
    CComQIPtr<IMediaSeeking> pMS = m_pFG;
    if (pMS && SUCCEEDED(pMS->GetDuration(&rtDur)) && rtDur > 0) {
        m_time = ReftimeToString2(rtDur);
    }

    CSize wh(0, 0), arxy(0, 0);
	//获取宽和高
    if (m_pCAP) {
        wh = m_pCAP->GetVideoSize(false);
        arxy = m_pCAP->GetVideoSize(true);
    } else {
        if (CComQIPtr<IBasicVideo> pBV = m_pFG) {
            if (SUCCEEDED(pBV->GetVideoSize(&wh.cx, &wh.cy))) {
                if (CComQIPtr<IBasicVideo2> pBV2 = m_pFG) {
                    pBV2->GetPreferredAspectRatio(&arxy.cx, &arxy.cy);
                }
            } else {
                wh.SetSize(0, 0);
            }
        }

        if (wh.cx == 0 && wh.cy == 0) {
            BeginEnumFilters(m_pFG, pEF, pBF) {
                if (CComQIPtr<IBasicVideo> pBV = pBF) {
                    pBV->GetVideoSize(&wh.cx, &wh.cy);
                    if (CComQIPtr<IBasicVideo2> pBV2 = pBF) {
                        pBV2->GetPreferredAspectRatio(&arxy.cx, &arxy.cy);
                    }
                    break;
                } else if (CComQIPtr<IVMRWindowlessControl> pWC = pBF) {
                    pWC->GetNativeVideoSize(&wh.cx, &wh.cy, &arxy.cx, &arxy.cy);
                    break;
                } else if (CComQIPtr<IVMRWindowlessControl9> pWC9 = pBF) {
                    pWC9->GetNativeVideoSize(&wh.cx, &wh.cy, &arxy.cx, &arxy.cy);
                    break;
                }
            }
            EndEnumFilters;
        }
    }

    if (wh.cx > 0 && wh.cy > 0) {
        m_res.Format(_T("%dx%d"), wh.cx, wh.cy);

        int gcd = GCD(arxy.cx, arxy.cy);
        if (gcd > 1) {
            arxy.cx /= gcd;
            arxy.cy /= gcd;
        }

        if (arxy.cx > 0 && arxy.cy > 0 && arxy.cx * wh.cy != arxy.cy * wh.cx) {
            CString ar;
            ar.Format(_T(" (AR %d:%d)"), arxy.cx, arxy.cy);
            m_res += ar;
        }
    }

    m_fn.TrimRight('/');
    m_fn.Replace('\\', '/');
    m_fn = m_fn.Mid(m_fn.ReverseFind('/') + 1);

    UpdateData(FALSE);

    InitEncoding();

    m_pFG = nullptr;
    m_pCAP = nullptr;

    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}

BOOL CPPageFileInfoDetails::OnSetActive()
{
    BOOL ret = __super::OnSetActive();
    PostMessage(SETPAGEFOCUS, 0, 0L);
    return ret;
}

LRESULT CPPageFileInfoDetails::OnSetPageFocus(WPARAM wParam, LPARAM lParam)
{
    CPropertySheet* psheet = (CPropertySheet*) GetParent();
    psheet->GetTabControl()->SetFocus();
    return 0;
}

void CPPageFileInfoDetails::InitEncoding()
{
    CAtlList<CString> sl;

    BeginEnumFilters(m_pFG, pEF, pBF) {
        CComPtr<IBaseFilter> pUSBF = GetUpStreamFilter(pBF);

        if (GetCLSID(pBF) == CLSID_NetShowSource) {
            continue;
        } else if (GetCLSID(pUSBF) != CLSID_NetShowSource) {
            if (IPin* pPin = GetFirstPin(pBF, PINDIR_INPUT)) {
                CMediaType mt;
                if (FAILED(pPin->ConnectionMediaType(&mt)) || mt.majortype != MEDIATYPE_Stream) {
                    continue;
                }
            }

            if (IPin* pPin = GetFirstPin(pBF, PINDIR_OUTPUT)) {
                CMediaType mt;
                if (SUCCEEDED(pPin->ConnectionMediaType(&mt)) && mt.majortype == MEDIATYPE_Stream) {
                    continue;
                }
            }
        }

        BeginEnumPins(pBF, pEP, pPin) {
            CMediaTypeEx mt;
            PIN_DIRECTION dir;
            if (FAILED(pPin->QueryDirection(&dir)) || dir != PINDIR_OUTPUT
                    || FAILED(pPin->ConnectionMediaType(&mt))) {
                continue;
            }

            CString str = mt.ToString();

            if (!str.IsEmpty()) {
                if (mt.majortype == MEDIATYPE_Video) { // Sort streams, set Video streams at head
                    bool found_video = false;
                    for (POSITION pos = sl.GetTailPosition(); pos; sl.GetPrev(pos)) {
                        CString Item = sl.GetAt(pos);
                        if (!Item.Find(_T("Video:"))) {
                            sl.InsertAfter(pos, str + CString(L" [" + GetPinName(pPin) + L"]"));
                            found_video = true;
                            break;
                        }
                    }
                    if (!found_video) {
                        sl.AddHead(str + CString(L" [" + GetPinName(pPin) + L"]"));
                    }
                } else {
                    sl.AddTail(str + CString(L" [" + GetPinName(pPin) + L"]"));
                }
            }
        }
        EndEnumPins;
    }
    EndEnumFilters;

    CString text = Implode(sl, '\n');
    text.Replace(_T("\n"), _T("\r\n"));
    m_encoding.SetWindowText(text);
}

从代码中可以看出,CPPageFileInfoDetails的功能是在OnInitDialog()中完成的。通过调用DirectShow相应的接口,分别获取了视频的宽高,时长等信息。

Media Player Classic - HC 源代码分析 7:详细信息选项卡(CPPageFileInfoDetails)的更多相关文章

  1. Media Player Classic - HC 源代码分析 6:MediaInfo选项卡 (CPPageFileMediaInfo)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  2. Media Player Classic - HC 源代码分析 5:关于对话框 (CAboutDlg)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  3. Media Player Classic - HC 源代码分析 4:核心类 (CMainFrame)(3)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  4. Media Player Classic - HC 源代码分析 3:核心类 (CMainFrame)(2)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  5. Media Player Classic - HC 源代码分析 2:核心类 (CMainFrame)(1)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  6. Media Player Classic - HC 源代码分析 1:整体结构

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  7. 转:Media Player Classic - HC 源代码分析

    VC2010 编译 Media Player Classic - Home Cinema (mpc-hc) Media Player Classic - Home Cinema (mpc-hc)播放器 ...

  8. MediaInfo源代码分析 1:整体结构

    MediaInfo 用来分析视频和音频文件的编码和内容信息,是一款是自由软件 (免费使用.免费获得源代码).之前编程的时候,都是直接调用它提供的Dll,这次突然来了兴趣,想研究一下它内部究竟是怎么实现 ...

  9. Android应用程序内部启动Activity过程(startActivity)的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6703247 上文介绍了Android应用程序的 ...

随机推荐

  1. Redis源码剖析--源码结构解析

    请持续关注我的个人博客:https://zcheng.ren 找工作那会儿,看了黄建宏老师的<Redis设计与实现>,对redis的部分实现有了一个简明的认识.在面试过程中,redis确实 ...

  2. MyEclipse如何全局搜索

    1全局搜索的启动方式 CTRL+H 2全局搜索自己选择搜索方式 自己选择要搜索的东西,简单吧,里面还有很多好玩的东西需要你去发现,加油! [正在看本人博客的这位童鞋,我看你气度不凡,谈吐间隐隐有王者之 ...

  3. Java中synchronized的使用实例

    一.使用场景 在负责后台开发的时候,很多时候都是提供接口给前端开发人员去调用,会遇到这样的场景: 需要提供一个领奖接口,每个用户名只能领取一次,我们可以将成功领取的用户在数据库用个标记保存起来.如果这 ...

  4. C++ 虚函数表 单继承

    本文研究单继承情况下,c++对象的虚函数表的具体情况. 假设有两个类A,B, 其中B由A派生出来,A含有虚函数fun1,B含有虚函数fun2. 测试的代码如下: #include<iostrea ...

  5. Android的SharedPreferences(首选项)保存键值对

    使用共享首选项 如果您有想要保存的相对较小键值集合,您应使用 SharedPreferences API.SharedPreferences 对象指向包含键值对的文件并提供读写这些文件的简单方法. 每 ...

  6. Findbug在项目中的运用--提高代码质量

     FindBugs是一个静态分析工具,它检查类或者 JAR文件,将字节码与一组缺陷模式进行对比以发现可能的问题.有了静态分析工具,就可以在不实际运行程序的情况对软件进行分析 第一 手动安装 在Ec ...

  7. java的四种引用类型

    java的引用分为四个等级:4种级别由高到低依次为:强引用.软引用.弱引用和虚引用. ⑴强引用(StrongReference) 强引用是使用最普遍的引用.如果一个对象具有强引用,那垃圾回收器绝不会回 ...

  8. Unity插件 - MeshEditor(六) 变形动画状态机

    变形动画状态机--MeshAnimator,是针对MeshAnimation的状态管理器,有大量类似Unity animator的功能,但MeshAnimator操作会更加简便,更加直观,居家旅(zh ...

  9. FFmpeg示例程序合集-Git批量获取脚本

    此前做了一系列有关FFmpeg的示例程序,组成了<FFmpeg示例程序合集>,其中包含了如下项目:simplest ffmpeg player:                  最简单的 ...

  10. SSH深度历险(七) 剖析SSH核心原理(一)

    接触SSH有一段时间了,但是对于其原理,之前说不出来莫模模糊糊(不能使用自己的语言描述出来的就是没有掌握),在视频和GXPT学习,主要是实现了代码,一些原理性的内容还是欠缺的,这几天我自己也一直在反问 ...