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

📄 upushsource.pas

📁 delphi源码
💻 PAS
📖 第 1 页 / 共 4 页
字号:
  end;

  FileSize := GetFileSize(FFileHandle, nil);
  if (FileSize = INVALID_FILE_SIZE) then
  begin
{$IFDEF DEBUG}
    DbgLog(Self, 'Invalid file size');
{$ENDIF}
    hr := HRESULTFROMWIN32(GetLastError());
    Exit;
  end;

  FFileBuffer := CoTaskMemAlloc(FileSize);
  if (FFileBuffer = nil) then
  begin
    OutputDebugString('Could not allocate FImage');
    hr := E_OUTOFMEMORY;
    Exit;
  end;

  BytesRead := 0;
  if not (ReadFile(FFileHandle, FFileBuffer^, FileSize, BytesRead, nil)) then
  begin
    hr := HRESULTFROMWIN32(GetLastError());
    OutputDebugString('ReadFile failed');
    Exit;
  end;

  // WARNING - This code does not verify that the file is a valid bitmap file.
  // In your own filter, you would check this or else generate the bitmaps
  // yourself in memory.

  FileHeaderSize := SizeOf(BITMAPFILEHEADER);

  // Store the size of the BITMAPINFO
  BmpFileHeader := PBITMAPFILEHEADER(FFileBuffer);
  FBitmapInfo := Integer(BmpFileHeader.bfOffBits) - FileHeaderSize;

  // Store a pointer to the BITMAPINFO
  pb := PByte(FFileBuffer);
  Inc(pb, FileHeaderSize);
  FBmi := PBITMAPINFO(pb);

  // Store a pointer to the starting address of the pixel bits
  Inc(pb, FBitmapInfo);
  FImage := pb;

  // Close and invalidate the file handle, since we have copied its bitmap data
  CloseHandle(FFileHandle);
  FFileHandle := INVALID_HANDLE_VALUE;
end;

destructor TBCPushPinBitmap.Destroy;
begin
{$IFDEF DEBUG}
  DbgLog(self, Format('Frames written %d', [FFrameNumber]));
{$ENDIF}

  if Assigned(FFileBuffer) then
  begin
    //FreeMem(FFileBuffer);
    CoTaskMemFree(FFileBuffer);
    FFileBuffer := nil;
  end;

  // The constructor might quit early on error and not close the file...
  if (FFileHandle <> INVALID_HANDLE_VALUE) then
    CloseHandle(FFileHandle);
  if (FSharedState <> nil) then
    FreeAndNil(FSharedState);

  inherited;
end;

// GetMediaType: This method tells the downstream pin what types we support.

// Here is how CSourceStream deals with media types:
//
// If you support exactly one type, override GetMediaType(MediaType : PAMMediaType).
// It will then be called when (a) our filter proposes a media type,
// (b) the other filter proposes a type and we have to check that type.
//
// If you support > 1 type, override GetMediaType(iPosition : Integer;
//  out MediaType : PAMMediaType) AND CheckMediaType.
//
// In this case we support only one type, which we obtain from the bitmap file.

function TBCPushPinBitmap.GetMediaType(MediaType: PAMMediaType): HResult;
var
  pvi: PVIDEOINFOHEADER;

begin
  FFilter.StateLock.Lock;
  try
    if (MediaType = nil) then
    begin
      Result := E_POINTER;
      Exit;
    end;

    // If the bitmap file was not loaded, just fail here.
    if (FImage = nil) then
    begin
      Result := E_FAIL;
      Exit;
    end;

    // Allocate enough room for the VIDEOINFOHEADER and the color tables
    MediaType.cbFormat := SIZE_PREHEADER + FBitmapInfo;
    pvi := CoTaskMemAlloc(MediaType.cbFormat);
    if (pvi = nil) then
    begin
      Result := E_OUTOFMEMORY;
      Exit;
    end;

    ZeroMemory(pvi, MediaType.cbFormat);
    pvi.AvgTimePerFrame := FFrameLength;

    // Copy the header info
    CopyMemory(@pvi.bmiHeader, FBmi, FBitmapInfo);

    // Set image size for use in FillBuffer
    pvi.bmiHeader.biSizeImage := GetBitmapSize(@pvi.bmiHeader);

    // Clear source and target rectangles
    // we want the whole image area rendered
    SetRectEmpty(pvi.rcSource);
    // no particular destination rectangle
    SetRectEmpty(pvi.rcTarget);

    MediaType.majortype := MEDIATYPE_Video;
    MediaType.formattype := FORMAT_VideoInfo;
    // Work out the GUID for the subtype from the header info.
    MediaType.subtype := GetBitmapSubtype(@pvi.bmiHeader);
    MediaType.bTemporalCompression := False;
    MediaType.bFixedSizeSamples := True;
    MediaType.pbFormat := pvi;
    MediaType.lSampleSize := pvi.bmiHeader.biSizeImage;

    Result := S_OK;

  finally
    FFilter.StateLock.UnLock;
  end;
end;

function TBCPushPinBitmap.DecideBufferSize(Allocator: IMemAllocator;
  Properties: PAllocatorProperties): HRESULT;
var
  pvi: PVIDEOINFOHEADER;
  Actual: ALLOCATOR_PROPERTIES;

begin
  if (Allocator = nil) or (Properties = nil) then
  begin
    Result := E_POINTER;
    Exit;
  end;

  FFilter.StateLock.Lock;
  try
    // If the bitmap file was not loaded, just fail here.
    if (FImage = nil) then
    begin
      Result := E_FAIL;
      Exit;
    end;

    pvi := AMMediaType.pbFormat;

    // Ensure a minimum number of buffers
    if (Properties.cBuffers = 0) then
      Properties.cBuffers := 2;
    Properties.cbBuffer := pvi.bmiHeader.biSizeImage;

    Result := Allocator.SetProperties(Properties^, Actual);
    if Failed(Result) then
      Exit;

    // Is this allocator unsuitable?
    if (Actual.cbBuffer < Properties.cbBuffer) then
      Result := E_FAIL
    else
      Result := S_OK;

  finally
    FFilter.StateLock.UnLock;
  end;
end;

// This is where we insert the DIB bits into the video stream.
// FillBuffer is called once for every sample in the stream.

function TBCPushPinBitmap.FillBuffer(Sample: IMediaSample): HResult;
var
  pData: PByte;
  cbData: Longint;
  pvi: PVIDEOINFOHEADER;
  Start, Stop: REFERENCE_TIME;

  function min(v1, v2: DWord): DWord;
  begin
    if v1 <= v2 then
      Result := v1
    else
      Result := v2;
  end;

begin
  if (Sample = nil) then
  begin
    Result := E_POINTER;
    Exit;
  end;

  // If the bitmap file was not loaded, just fail here.
  if (FImage = nil) then
  begin
    Result := E_FAIL;
    Exit;
  end;

  FSharedState.Lock;
  try
    // Access the sample's data buffer
    Sample.GetPointer(pData);
    cbData := Sample.GetSize;

    // Check that we're still using video
    Assert(IsEqualGUID(AMMediaType.formattype, FORMAT_VideoInfo));

    pvi := AMMediaType.pbFormat;

    // If we want to change the contents of our source buffer (FImage)
    // at some interval or based on some condition, this is where to do it.
    // Remember that the new data has the same format that we specified in GetMediaType.
    // For example:
    // if(FFrameNumber > SomeValue)
    //    LoadNewBitsIntoBuffer(FImage)

    // Copy the DIB bits over into our filter's output buffer.
    // Since sample size may be larger than the image size, bound the copy size.
    CopyMemory(pData, FImage, min(pvi.bmiHeader.biSizeImage, cbData));

    // Set the timestamps that will govern playback frame rate.
    // If this file is getting written out as an AVI,
    // then you'll also need to configure the AVI Mux filter to
    // set the Average Time Per Frame for the AVI Header.
    // The current time is the sample's start
    Start := FFrameNumber * FFrameLength;
    Stop := Start + FFrameLength;

    Sample.SetTime(@Start, @Stop);
    Inc(FFrameNumber);

    // Set TRUE on every sample for uncompressed frames
    Sample.SetSyncPoint(True);

    Result := S_OK;

  finally
    FSharedState.UnLock;
  end;
end;

function TBCPushPinBitmap.Notify(Filter: IBaseFilter; q: TQuality): HRESULT;
begin
  Result := E_FAIL;
end;

// --- TBCPushSourceBitmap ------------

constructor TBCPushSourceBitmap.Create(ObjName: string; Unk: IUnKnown;
  out hr: HRESULT);
begin
  inherited Create(ObjName, Unk, CLSID_PushSourceBitmap);

  // The pin magically adds itself to our pin array.
  FPin := TBCPushPinBitmap.Create(hr, Self);

  if (hr <> S_OK) then
    if (FPin = nil) then
      hr := E_OUTOFMEMORY;
end;

constructor TBCPushSourceBitmap.CreateFromFactory(Factory: TBCClassFactory;
  const Controller: IUnknown);
var
  hr: HRESULT;
begin
  Create(Factory.Name, Controller, hr);
end;

destructor TBCPushSourceBitmap.Destroy;
begin
  FreeAndNil(FPin);
  inherited;
end;

// --- TBCPushPinBitmapSet ------------

constructor TBCPushPinBitmapSet.Create(out hr: HResult; Filter: TBCSource);
var
  CurrentDir: array[0..MAX_PATH - 1] of Char;
  CurrentFileName, MediaFileName: AnsiString;
  MsgText: AnsiString;
  FileSize, BytesRead: DWord;
  FilesLoaded, FileHeaderSize: Integer;
  BmpFileHeader: PBITMAPFILEHEADER;
  pb: PByte;
  i: Integer;

begin
  inherited Create('_ Push Source Bitmap Set', hr, Filter, 'Out');

  FFramesWritten := 0;
  FZeroMemory := False;
  FFrameNumber := 0;

  // Display 5 bitmap frames per second
  FFrameLength := FPS_2;
  FSharedState := TBCCritSec.Create;
  FCurrentBitmap := 0;
  FFilesLoaded := False;

  FilesLoaded := 0;
  // Initialize member data arrays
  ZeroMemory(@FBitmapInfo, NUM_FILES * sizeof(DWord));
  ZeroMemory(@FBmi, NUM_FILES * sizeof(PBitmapInfo));
  ZeroMemory(@FFileHandle, NUM_FILES * sizeof(THandle));
  ZeroMemory(@FFileBuffer, NUM_FILES * sizeof(Byte));
  ZeroMemory(@FImage, NUM_FILES * sizeof(Byte));

  // The main point of this sample is to demonstrate how to take a DIB
  // in host memory and insert it into a video stream.
  // We read a set of bitmaps from files and copy one bitmap
  // into every frame that we send downstream.

  // In the filter graph, we connect this filter to the AVI Mux, which creates
  // the AVI file with the video frames we pass to it. In this case,
  // the end result is a rotating set of images rendered as a video stream.

  // First look for the bitmap in the current directory
  GetCurrentDirectory(MAX_PATH - 1, CurrentDir);

  for i := 0 to NUM_FILES - 1 do
  begin
    // Assume that the bitmap in the application's directory
    CurrentFileName := Format('%s\BitmapSet%d.bmp', [CurrentDir, i]);
    FFileHandle[i] := CreateFile(PChar(CurrentFileName), GENERIC_READ, 0, nil,
      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

    if (FFileHandle[i] = INVALID_HANDLE_VALUE) then
    begin
      // File was not in the application's current directory,
      // so look in the DirectX SDK media path instead.  The path contained
      // in szMediaDir will already have a trailing backslash '\'.
      MediaFileName := Format('%sBitmapSet%d.bmp', [GetDXSDKMediaPath, i]);

      FFileHandle[i] := CreateFile(PChar(MediaFileName), GENERIC_READ, 0, nil,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

      if (FFileHandle[i] = INVALID_HANDLE_VALUE) then
      begin
        MsgText := Format('Could not open bitmap source file (#%d of %d) ' +
          'in the application directory:'#13#10 + '%s'#13#10 +
          'or in the DirectX SDK Media folder:'#13#10 + '%s'#13#10 +
          'Please copy this file either to the application''s folder'#13#10 +
          'or to the DirectX SDK Media folder, then recreate this filter'#13#10 +
          'Otherwise, you will not be able to render the output pin',
          [i + 1, NUM_FILES, CurrentFileName, MediaFileName]);

        OutputDebugString(PChar(MsgText));
        MessageBox(0, PChar(MsgText), 'PushSource filter error',
          MB_ICONERROR or MB_OK);
        hr := HRESULTFROMWIN32(GetLastError());
        Exit;
      end;
    end;

    FileSize := GetFileSize(FFileHandle[i], nil);
    if (FileSize = INVALID_FILE_SIZE) then
    begin
{$IFDEF DEBUG}
      DbgLog(Self, 'Invalid file size');
{$ENDIF}
      hr := HRESULTFROMWIN32(GetLastError());
      Exit;
    end;

    FFileBuffer[i] := CoTaskMemAlloc(FileSize);
    if (FFileBuffer[i] = nil) then
    begin

⌨️ 快捷键说明

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