⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 player.~pas

📁 delphi版的无缝播放器
💻 ~PAS
📖 第 1 页 / 共 2 页
字号:
// Translate from GMFPlay(Demo of the GMFBridge). Done by Zhang Jianyu 2006-05-05
// http://www.panensoft.com
// email:  admin@panensoft.com

//
// Sample DirectShow player that uses
// GDCL Multigraph Framework to play a sequence of
// multiple clips
//
// Copyright (c) GDCL 2004. All Rights Reserved.
// You are free to re-use this as the basis for your own filter development,
// provided you retain this copyright notice in the source.
// http://www.gdcl.co.uk

unit Player;

interface

uses
  DirectShow9, Dspack, SysUtils, GMFBridgeLib_TLB, Classes, ActiveX, Windows, Messages,ComObj;

const
		MSG_ENDOFSEGMENT	=	WM_USER+100;
		MSG_DSEVENT			=	WM_USER+101;

type
//  TMSG_ENDOFSEGMENT
//  TMSG_DSEVENT

  TClipEntry = class(TObject)
  private
    m_pGraph: IGraphBuilder;
    m_pSinkFilter: IUnknown;
    m_strName: string;
    m_tOffset, m_tStart, m_tStop: REFERENCE_TIME;
    FGraphEditID  : Integer;
  public
    // rewound ready to re-use
    m_bPrimed: boolean;
    constructor Create;
    destructor Destroy;
    function CreateClip(pController: IGMFBridgeController; path: string): HRESULT;
    function SetLimits(tStart, tStop: REFERENCE_TIME): HRESULT;
    procedure GetLimits(var ptStart, ptStop: REFERENCE_TIME);
    function Duration: REFERENCE_TIME;
    function CurrentPosition: REFERENCE_TIME;
    function Graph: IUnknown;
    function SinkFilter: IUnknown;
    function Name: string;
    procedure SetStartPosition(tOffset: REFERENCE_TIME);
    function GetStartPosition: REFERENCE_TIME;
    function SetPosition(tStart: REFERENCE_TIME): HRESULT;
    function IsPrimed: boolean;
    procedure InUse;
    // set position and run
    procedure Prime(tStart: REFERENCE_TIME = 0);
    procedure Stop;
    // returns whole file duration even when limits applied
    function NativeDuration: REFERENCE_TIME;
    // updates the graph stop time to reflect the limits (for active clip)
    function SetStopTime: HRESULT;
  end;

  TClipPlayer = class(TObject)
  public
//    m_pRenderGraph: IGraphBuilder;
    FFilterGraph: TFilterGraph;
    constructor Create( hwnd: THandle; msgSegment, msgEvent: word);
    Destructor Destroy;
  {
 ClipPlayer(HWND hwnd, UINT msgSegment, UINT msgEvent);
 ~ClipPlayer();
  }
    function AddClip(path: string; Clip: TClipEntry): HRESULT;
    function Play: HRESULT;
    function Pause: HRESULT;
    function Stop: HRESULT;

    procedure OnEndOfSegment;
    procedure OnEvent;

    function TotalDuration: REFERENCE_TIME;
    function IsCued: boolean;

    function SetClipLimits(pClip: TClipEntry; tStart, tEnd: REFERENCE_TIME): HRESULT;
    function GetClipByIndex(idx: integer): TClipEntry;
    procedure PlayNext(pClip: TClipEntry);
    function CurrentPosition: REFERENCE_TIME;
    function SetPosition(tStart: REFERENCE_TIME): HRESULT;
    function CurrentClip: TClipEntry;
    procedure UpdateDuration;
    procedure SetLoop(bLoop: boolean);
    function IsLooping: boolean;

  private
    m_pController: IGMFBridgeController;
    m_Clips: TList; //list<ClipEntry> ;
    m_itCurrent: TClipEntry;        

//?    list<ClipEntry>::iterator m_itCurrent;

    m_pRenderGraphSourceFilter: IUnknown;
    m_tDuration, m_tStartPosition: REFERENCE_TIME;
    m_bLoop, m_bActive: boolean;

    m_hwndApp: Thandle;
    m_msgSegment: Word;
    m_msgEvent: Word;
    m_pPlayNext: TClipEntry;
    function SeekSourceGraphs(): HRESULT;
    procedure ResizeWindowToVideo();
    function GetState(): FILTER_STATE;
  end;

implementation



 //----------------------------------------------------------------------------
  // Enable Graphedit to connect with your filter graph
  //----------------------------------------------------------------------------
  function AddGraphToRot(Graph: IFilterGraph; out ID: integer): HRESULT;
  var
    Moniker: IMoniker;
    ROT    : IRunningObjectTable;
    wsz    : WideString;
  begin
    result := GetRunningObjectTable(0, ROT);
    if (result <> S_OK) then exit;
    wsz := format('FilterGraph %p pid %x',[pointer(graph),GetCurrentProcessId()]);
    result  := CreateItemMoniker('!', PWideChar(wsz), Moniker);
    if (result <> S_OK) then exit;
    result  := ROT.Register(0, Graph, Moniker, ID);
    Moniker := nil;
  end;

  //----------------------------------------------------------------------------
  // Disable Graphedit to connect with your filter graph
  //----------------------------------------------------------------------------
  function RemoveGraphFromRot(ID: integer): HRESULT;
  var ROT: IRunningObjectTable;
  begin
    result := GetRunningObjectTable(0, ROT);
    if (result <> S_OK) then exit;
    result := ROT.Revoke(ID);
    ROT := nil;
  end;

constructor TClipEntry.Create;
begin
  m_tOffset := 0;
  m_tStart := 0;
  m_tStop := 0;
  m_bPrimed := false;
end;

destructor TClipEntry.Destroy;
var
  pMC: IMediaControl;
begin
  if (assigned(m_pGraph)) then
    m_pGraph.QueryInterface(IID_IMediaControl, pmc);
  if (assigned(pMC)) then
    pMC.Stop;

    RemoveGraphFromRot(FGraphEditID);    
end;

function TClipEntry.CreateClip(pController: IGMFBridgeController; path: string): HRESULT;
begin
  m_bPrimed := false;

  result := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER,
    IID_IFilterGraph, m_pGraph);
  // old version of (GMFBridge)
  // pController.CreateSourceGraph(StringToOleStr(path), m_pGraph, m_pSinkFilter);

    AddGraphToRot(IFilterGraph2(m_pGraph), FGraphEditID);

  try
    m_pSinkFilter:= pController.CreateSourceGraph(StringToOleStr(path), m_pGraph);
    result:= S_OK;
  except
    on  e: EOleException do
    begin
      result:= EOleException(e).ErrorCode;
    end;
  end;

  m_strName := path;
end;

function TClipEntry.SetLimits(tStart, tStop: REFERENCE_TIME): HRESULT;
begin
  m_tStart := tStart;
  m_tStop := tStop;
  m_bPrimed := false;
  result := S_OK;
end;

procedure TClipEntry.GetLimits(var ptStart, ptStop: REFERENCE_TIME);
begin
  ptStart := m_tStart;
  ptStop := m_tStop;
end;

function TClipEntry.Duration: REFERENCE_TIME;
var
  tDur: REFERENCE_TIME;
  pMS: IMediaSeeking;
  hr: HRESULT;
begin
  if (m_tStop = 0) then
  begin
    tDur := 0;
    m_pGraph.QueryInterface(IID_IMediaSeeking, pMS);
    hr := pMS.GetDuration(tDur);
    if ((hr <> S_OK)) then
    begin
      result := 0;
      exit;
    end;

    result := tDur - m_tStart;
    exit;
  end;
  result := m_tStop - m_tStart;
end;

function TClipEntry.CurrentPosition: REFERENCE_TIME;
var
  tNow: REFERENCE_TIME;
  pMS: IMediaSeeking;
  hr: HRESULT;
begin
  tNow := 0;
  m_pGraph.QueryInterface(IID_IMediaSeeking, pMS);
  pMS.GetCurrentPosition(tNow);
  result := tNow + m_tStart;
end;

function TClipEntry.Graph: IUnknown;
begin
  result := self.m_pGraph;
end;

function TClipEntry.SinkFilter: IUnknown;
begin
  result := self.m_pSinkFilter;
end;

function TClipEntry.Name: string;
begin
  result := self.m_strName;
end;

procedure TClipEntry.SetStartPosition(tOffset: REFERENCE_TIME);
begin
  m_tOffset := tOffset;
end;

function TClipEntry.GetStartPosition: REFERENCE_TIME;
begin
  result := m_tOffset;
end;

function TClipEntry.SetPosition(tStart: REFERENCE_TIME): HRESULT;
var
  hr: HRESULT;
  pSeek: IMediaSeeking;
  stop: Int64;
begin
  self.m_pGraph.QueryInterface(IID_IMediaSeeking, pSeek);
  hr := E_NOINTERFACE;
  if (pSeek <> nil) then
  begin
  // input time is relative to clip start -- add on offset
  // from start of media
    tStart := tStart + m_tStart;
    if (m_tStop = 0) then
    begin
      stop := 0;
      hr := pSeek.SetPositions(
        tStart,
        AM_SEEKING_AbsolutePositioning,
        stop,
        AM_SEEKING_NoPositioning);
    end
    else
    begin
      hr := pSeek.SetPositions(
        tStart,
        AM_SEEKING_AbsolutePositioning,
        m_tStop,
        AM_SEEKING_AbsolutePositioning);
    end
  end;
  result := hr;
end;

function TClipEntry.IsPrimed: boolean;
begin
  result := self.m_bPrimed;
end;

procedure TClipEntry.InUse;
begin
  m_bPrimed := False;
end;

// set position and run

procedure TClipEntry.Prime(tStart: REFERENCE_TIME = 0);
var
  state: TFilterState;
  pMC: IMediaControl;
begin
  if (not m_bPrimed) then
  begin
    SetPosition(tStart);

    Graph.QueryInterface(IID_IMediaControl, pMC);
    pMC.GetState(0, state);
    if (state <> State_Running) then
    begin
      pMC.Run;
    end;
    m_bPrimed := true;
  end;
end;

procedure TClipEntry.Stop;
var
  state: TFilterState;
  pMC: IMediaControl;
begin
  Graph.QueryInterface(IID_IMediaControl, pMC);
  pMC.Stop;
  m_bPrimed := false;
end;

// returns whole file duration even when limits applied

function TClipEntry.NativeDuration(): REFERENCE_TIME;
var
  tDur: REFERENCE_TIME;
  pMS: IMediaSeeking;
begin
  tDur := 0;
  m_pGraph.QueryInterface(IID_IMediaSeeking, pMS);
  pMS.GetDuration(tDur);
  result := tDur;
end;

// updates the graph stop time to reflect the limits (for active clip)

function TClipEntry.SetStopTime(): HRESULT;
var
  pSeek: IMediaSeeking;
  hr: HRESULT;
  start: int64;
begin
  m_pGraph.QueryInterface(IID_IMediaSeeking, pSeek);
  hr := E_NOINTERFACE;
  if (pSeek <> nil) then
  begin
    start := 0;
    hr := pSeek.SetPositions(
      start,
      AM_SEEKING_NoPositioning,
      m_tStop,
      AM_SEEKING_AbsolutePositioning);
  end;
  result := hr;
end;

function TClipPlayer.AddClip(path: string; Clip: TClipEntry): HRESULT;
var
  hr: HResult;
  idx: integer;
//  Clip: TClipEntry;
  pME: IMediaEventEx;
begin
//	list<ClipEntry>::iterator it = m_Clips.insert(m_Clips.end(), ClipEntry());
  Clip := TClipEntry.Create;
  self.m_Clips.Add(Clip);
//	ClipEntry* pClip = &(*it);
//	*ppClip = pClip;

  hr := Clip.CreateClip(m_pController, path);

  //	HRESULT hr = pClip.Create(m_pController, path);

 // if we expect both audio and video, then all clips
 // must have both audio and video.
 // If the first clip is video only, then switch
 // to video-only automatically
  if ((hr = VFW_E_UNSUPPORTED_AUDIO) and (m_Clips.Count = 1)) then
  begin
  // new controller, different options (only one video stream)
    m_pController := TGMFBridgeController.Create(nil).DefaultInterface;
//		m_pController.CreateInstance(__uuidof(GMFBridgeController));
    m_pController.SetNotify((m_hwndApp), (m_msgSegment));
    m_pController.AddStream(1, eUncompressed, 0);
    m_pController.SetBufferMinimum(200);

  // try again
    hr := Clip.CreateClip(m_pController, path);
  end;

  if ((hr = s_OK)) then
  begin
    clip.SetStartPosition(m_tDuration);
    m_tDuration := m_tDuration + Clip.Duration;

  // if this is the first clip, create the render graph
    if (m_Clips.Count = 1) then
    begin
//      hr := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER,
//        IID_IFilterGraph, m_pRenderGraph);
      // old version
      // m_pController.CreateRenderGraph(Clip.SinkFilter(), m_pRenderGraph,m_pRenderGraphSourceFilter);
      m_pRenderGraphSourceFilter:= m_pController.CreateRenderGraph(Clip.SinkFilter(), FFilterGraph as IGraphBuilder);
      if ((hr = s_ok) and IsWindow(m_hwndApp)) then
      begin

        (FFilterGraph as IGraphBuilder).QueryInterface(IID_IMediaEventEx, pME);
        if (pME <> nil) then
          pME.SetNotifyWindow(OAHWND(m_hwndApp), m_msgEvent, 0);
      end;
    end;
  end
  else
  begin
    idx := m_Clips.IndexOf(Clip);
    if (idx > -1) then
    begin
      m_Clips.Delete(idx);
    end;
    result := hr;
  end;
  if(m_Clips.Count>0) then
    m_itCurrent:= m_Clips.items[0]
  else
    m_itCurrent:= nil;
end;

function TClipPlayer.Play: HRESULT;
var
  hr: HRESULT;
  pMC: IMediaControl;
begin
 // make all graphs active
  hr := S_OK;
  if (not m_bActive) then
  begin
    UpdateDuration();
    hr := Pause();
  end;

  if (m_itCurrent.Graph() = nil) then
    hr := E_FAIL;

  if (SUCCEEDED(hr)) then
  begin
    (FFilterGraph as IGraphBuilder).QueryInterface(IID_IMediaControl, pMC);
    hr := pMC.Run;
  end;
  result := hr;
end;

function TClipPlayer.Pause: HRESULT;
var
	hr: HRESULT;
  pMC: IMediaControl;
  i: integer;
begin
  hr:= S_OK;

    // make all graphs active

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -