Среда, 22.11.2017, 01:55
Приветствую Вас Гость

Не ошибается тот, кто ничего не делает.
Но и ничего не делать - ошибка.

Эмиль Кроткий

Меню сайта
Категории раздела
Работа с библиотеками BASS и DirectShow [14]
Статьи по написанию mp3 плеера, видеоплеера, работе с WEB камерой и т.д.
Форма входа

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0


















Тиц
Главная » Статьи » Мультимедиа » Работа с библиотеками BASS и DirectShow

Урок 5.1. Накладываем текст на видео с использованием архитектуры DirectShow.
Содержание

Урок 5.1.
Накладываем текст на видео с использованием архитектуры DirectShow.

     На этом уроке мы научимся накладывать текст на видео в реальном режиме времени. Для этого будем использовать фильтр VideoMixingRenderer (VMR), он позволяет смешивать на экране несколько потоков видео, и самое главное позволяет накладывать на видео различные изображения. Для этого у него есть специальный интерфейс IVMRMixerBitmap. Работать мой тестовый пример будет следующим образом: на memo поле я буду писать текст сообщения, которое хочу наложить на видео, затем текст из memo поля будем формировать на Bitmap и через интерфейс  IVMRMixerBitmap смешивать на экране с потоком  видео.
    Существует несколько способов построения графа фильтров, почитать о них можно на сайте DirectShow по-русски  http://directshow.wonderu.com  или посмотреть в моих уроках по созданию видеоплеера, OnLine TV  плеера, в уроках по работе с web камерой. На мой взгляд, наиболее простым способом построения графа фильтров, является способ с использованием вспомогательного интерфейса ICaptureGraphBuilder2 и метода RenderStream. В отличие от метода  RenderFile интерфейса IGraphBuilder, метод RenderStream позволяет указать опорные фильтры и построить между ними ветвь графа  в интеллектуальном режиме. Построение идет от фильтра источника (SouceFilter). Поэтому используя данный способ построения, необходимо добавить в граф необходимые фильтры, а затем используя метод RenderStream построить между фильтрами ветви графа. Но, к  сожалению, у любого интеллектуального метода построения графа есть один недостаток, это медленная скорость построения графа т.к. системе приходится искать нужные фильтры, а на это уходит время. Хотите, что бы граф строился быстро нужно в ручную добавлять и соединять все фильтры, но это уже другая история.

  И так, приступим к созданию нашего тестового проекта. Запускаем Delphi и создаем новый проект.
Размещаем на форме следующие компоненты:



Компонент  TMemo из вкладки Standard;
Два компонента TTrackBar из вкладки Win32 один из них делаем вертикальным свойство Orientation-> trVertical ;
Компонент TTimer  из вкладки System;
Компонент TOpenDialog из вкладки Dialogs;
Компонент TCheckBox из вкладки Standard;
Компонент TButton из вкладки Standard.
Размещаем их как показано на рисунке.

Далее переходим к написанию кода.

В модуле Uses добавляем directshow9, ActiveX.

Для работы с DirectShow Вам понадобится скачать заголовочные файлы DirectShow API c сайта http://www.clootie.ru/ или  здесь и  поместить их в каталог Delphi\Lib либо добавить путь к каталогу, в котором они находятся в установках Delphi Library Path. Хотя DirectShow скорее всего уже установлен на Вашем компьютере т.к. он входит в стандартную поставку Windows.

Ниже привожу полный код проекта с подробными комментариями.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, directshow9, ActiveX,  ExtCtrls, ComCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    Memo1: TMemo;
    TrackBar1: TTrackBar;
    TrackBar2: TTrackBar;
    Timer1: TTimer;
    CheckBox1: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Timer1Timer(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);


  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  //описываем будущие интерфейсы
  FGraphBuilder: IGraphBuilder = Nil; //интерфейс графа
  FCaptureGraphBuilder: ICaptureGraphBuilder2 = nil; //вспомагательный интерфейс
  FMediaControl: IMediaControl = Nil; //интерфейс управления воспроизведением в графе
  FVideoWindow: IVideoWindow   = Nil; // интерфейс управления окном вывода видео
  FAudioRender : IBaseFilter = nil; //интерфейс фильтра вывода звука
  FVideoRender : IBaseFilter = nil; //интерфейс фильтра вывода видео
  fl_SrcFile   : IBaseFilter = nil; //интерфейс фильтра источника

   //имя файла для записи
  FileName:String;
   //описываем интерфейсы фильтра VMR (VideoMixingRenderer)
  FConfig      : IVMRFilterConfig; // Интерфейс IVMRFilterConfig используется, чтобы сконфигурировать режим смешивания
  FBitmap      : IVMRMixerBitmap; //Интерфейс IVMRMixerBitmap дает возможность приложению смешать статическое изображение
  VMRBitmap    : VMRALPHABITMAP;  //Структура, используемая для управления смешиванием
  Bitmap: TBitmap; // объект BitMap
  w,h: integer;//ширина и высота буквы
   x,y:integer;//координаты положения окна текста
   a,b:integer;//ширина и высота окна вывода видео

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
//освобождаем подключенные интерфейсы
 if Assigned(FMediaControl) then FMediaControl:= NIL;
 if Assigned(FVideoWindow)  then FVideoWindow := NIL;
 if Assigned(FAudioRender)  then FAudioRender := nil;
 if Assigned(FVideoRender)  then  FVideoRender:= nil;
 if Assigned(FCaptureGraphBuilder) then FCaptureGraphBuilder   := NIL;
 if Assigned(FGraphBuilder) then FGraphBuilder:= NIL;
 if Assigned(FBitmap) then  FBitmap:= NIL;

//создаем объект для построения графа фильтров FGraphBuilder
CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, FGraphBuilder);
//создаем объект для построения графа захвата FCaptureGraphBuilder
CoCreateInstance(CLSID_CaptureGraphBuilder2, NIL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, FCaptureGraphBuilder);
//указываем графу захвата граф фильтров
FCaptureGraphBuilder.SetFiltergraph(FGraphBuilder);
//вызываем диалог открытия файла видео
if not(OpenDialog1.Execute) then exit;
filename:=OpenDialog1.FileName;

//добавляем в граф фильтр источника видео и загружаем в него видео файл
FGraphBuilder.AddSourceFilter(StringToOleStr(FileName),'',fl_SrcFile);
//создаем объект для фильтра вывода звука FAudioRender
CoCreateInstance(CLSID_AudioRender, nil, CLSCTX_INPROC, IID_IBaseFilter, FAudioRender);
//добавляем его в граф
FGraphBuilder.AddFilter(FAudioRender, 'DirectSound Audio Renderer');
//создаем объект для фильтра вывода видео FVideoRender он же будет микшировать наше видео с изображением текста
CoCreateInstance(CLSID_VideoMixingRenderer, nil, CLSCTX_INPROC, IID_IBaseFilter, FVideoRender);
//добавляем его в граф
FGraphBuilder.AddFilter(FVideoRender, 'Video Renderer');
//получаем интерфейс конфигурации смешивания
if failed(FVideoRender.QueryInterface(IID_IVMRFilterConfig, FConfig)) then exit;
//задаем поток для смешивания
FConfig.SetNumberOfStreams(1);
//получаем интерфейс для смешивания изображения
if failed(FVideoRender.QueryInterface(IID_IVMRMixerBitmap,  FBitmap)) then exit;

//строим ветвь графа в зависимости от расширения файла видео

with FCaptureGraphBuilder do
begin
//проверяем, если это wmv
if lowercase(ExtractFileExt(filename))='.wmv' then  begin
   //то строим такой граф
   if FAILED(RenderStream(nil,  @MEDIATYPE_Video, fl_SrcFile, nil , FVideoRender)) then
   Begin
      ShowMessage('Внимание! Произошла ошибка при инициализации видео');
      Exit;
    End;
//иначе строим такой граф
end  else   begin
         if FAILED(RenderStream(nil, @MEDIATYPE_Stream, fl_SrcFile, nil , FVideoRender)) then
             Begin
                ShowMessage('Внимание! Произошла ошибка при инициализации видео');
                Exit;
              End;
            end;

//строим ветвь графа для вывода звука
   if FAILED(RenderStream(nil, nil, fl_SrcFile, nil, FAudioRender)) then
   Begin
      ShowMessage('Внимание! Произошла ошибка при инициализации аудио');
      Exit;
    End;
end;

//получаем интерфейс управления воспроизведением ImediaControl
 FGraphBuilder.QueryInterface(IID_IMediaControl, FMediaControl);
 //получаем интерфейс управления окном видео IVideoWindow
 FGraphBuilder.QueryInterface(IID_IVideoWindow, FVideoWindow);
 //запускаем на воспроизведение
 FMediaControl.Run;
end;

//установка чебокса для наложения текста
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
//проверяем, если воспроизведение идет
if Assigned(FVideoWindow)then begin
//то получаем размеры окна воспроизведения
  FVideoWindow.get_Width(a) ;
  FVideoWindow.get_Height(b);
//и задаем размеры bitmap для наложения текста
  Bitmap.Width:= a;
  Bitmap.Height:= b;
//задаем максимальное значение для трекбаров,
//которые будут регулировать положение текста на экране

  TrackBar1.Max:=a;
  TrackBar2.Max:=b;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//освобождаем созданные интерфейсы
  FMediaControl:= Nil; //интерфейс управления воспроизведением в графе
  FVideoWindow:= Nil; // интерфейс управления окном вывода видео
  FAudioRender := nil; //интерфейс фильтра вывода звука
  FVideoRender := nil; //интерфейс фильтра вывода видео
  fl_SrcFile   := nil; //интерфейс фильтра источника
  FBitmap:= NIL; // Интерфейс IVMRMixerBitmap
  FCaptureGraphBuilder:= nil; //вспомагательный интерфейс
  FGraphBuilder:= Nil; //интерфейс графа
  CoUninitialize;
  Bitmap.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
//инициализируем com интерфейс
CoInitialize(nil);
// Создаем BitMap и задаем настройки для текста, который будем накладывать на видео
 Bitmap:= TBitmap.Create;
 //цвет кисти
 Bitmap.Canvas.Brush.Color:= clBlack;
 //Шрифт
 Bitmap.Canvas.Font.Name:= 'arial';
 //размер шрифта
 Bitmap.Canvas.Font.Size:= 16;
 //Начертание
 Bitmap.Canvas.Font.Style:= [fsBold];
 //цвет шрифта
 Bitmap.Canvas.Font.Color:= clRed;
 //размер буквы
 W:= Bitmap.Canvas.TextWidth('W');
 H:= Bitmap.Canvas.TextHeight('W');
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
 alpha: single;  //прозрачность
 i:integer;
 s:string;  //текст для микширования
begin
//если чебокс установлен
if CheckBox1.Checked=false then exit;
//то очищаем bitmap, путем рисования на нем прямоугольника во весь его размер
 Bitmap.Canvas.Rectangle(0,0,a,b);
//задаем координаты для вывода текста
 x:=TrackBar1.Position;
 y:=TrackBar2.Position;
//формируем текст на битмапе из строк мемо поля
  for i := 0 to memo1.Lines.Count-1 do
 begin
//читаем строку в мемо

  s:=memo1.Lines.Strings[i];
//выводим на битмап
  Bitmap.Canvas.TextOut(x,i*20+y,s);
 end;
//проверяем если интерфейс управления видео получен
 if Assigned(FVideoWindow)then begin
 //то задаем прозрачность 0 до 1
 alpha:= 1;
//обнуляем память
  ZeroMemory(@VMRBitmap, sizeof(VMRBitmap));
//устанавливаем флаги смесителя
  VMRBitmap.dwFlags  := VMRBITMAP_HDC or VMRBITMAP_SRCCOLORKEY;
//устанавливаем ключевой цвет для смешивания
  VMRBitmap.clrSrcKey:= 0;
  //задаем контекст устройства Bitmap.Canvas
  VMRBitmap.hdc      := Bitmap.Canvas.Handle;
  //задаем область источника в данном контексте устройства

  VMRBitmap.rSrc     := Bitmap.Canvas.ClipRect;
 //задаем область вывода окна
//здесь можно изменять область вывода,
//если взять числа больше 1 то изображение будет масштабироваться.
//если left  взять больше чем right то изображение зеркально отразится и т.д.

  VMRBitmap.rDest.left  := 0.0;
  VMRBitmap.rDest.right := 1.0;
  VMRBitmap.rDest.top   := 0.0;
  VMRBitmap.rDest.bottom:= 1.0;
  //задаем прозрачноссть
  VMRBitmap.fAlpha      := alpha;
  //смешиаем
  FBitmap.SetAlphaBitmap(VMRBitmap);
end

end;

end.

Сохраняем проект и тестируем.
Кроме изменения позиции текста можно аналогично добавить изменение размера шрифта, расстояния между строками, цвет текста и т.д.





На этом урок закончен.

Скачать исходники можно здесь.

Автор статьи xaramamburu, сайт автора http://basicsprog.ucoz.ru .
В статье использованы материалы с сайта http://raxp.radioliga.com
Онлайн-ТВ плеер своими руками [опубликовано] .



Категория: Работа с библиотеками BASS и DirectShow | Добавил: xaramamburu (01.02.2012)
Просмотров: 5324 | Комментарии: 4 | Теги: VideoMixingRenderer, титры, DirectShow, телетекст | Рейтинг: 5.0/3
Всего комментариев: 4
4  
К сожалению в этих режимах не проверял, поэтому особо сказать ничего не могу. (((

3  
Не совсем понял вопрос. При смешивании BitMap выводиться всегда, просто когда нет текста или изображения мы его не видим из-за включенной прозрачности.)))

2  
у вас тут ошибка закралась smile
вместо так

Код
[b]//строим ветвь графа для вывода звука[/b]
    if FAILED(RenderStream(nil, nil, fl_SrcFile, nil, FAudioRender)) then


надо так:

Код
[b]//строим ветвь графа для вывода звука[/b]
    if FAILED(RenderStream(nil, @MEDIATYPE_AUDIO, fl_SrcFile, nil, FAudioRender)) then


иначе, звуковые фильтры могут не загрузиться.
а для видео лучше использовать ffdshow (если установлен):

Код
const
   CLSID_ffdshowAudioDecoder : TGUID = '{0F40E1E5-4F79-4988-B1A9-CC98794E6B55}';
var
   ffdshow : IBaseFilter = nil;

CoCreateInstance(CLSID_FfdshowVideoDecoder,nil,CLSCTX_INPROC,IID_IBaseFilter,ffds how);
FGraphBuilder.AddFilter(ffdshow,'ffdshow video decoder');


p.s. Пример просит файл BASECLASS.PAS/.DCU, которого нет в архиве.

1  
Столкнулся с проблемой
при выводе видео подсвечивалось красным или лиловым цветом
решение:

FConfig : IVMRFilterConfig9;
FBitmap : IVMRMixerBitmap9;
VMRBitmap : VMR9ALPHABITMAP;
///////////////////////-----///////////////////
CoCreateInstance(CLSID_VideoMixingRenderer9, nil, CLSCTX_INPROC, IID_IBaseFilter, FVideoRender);
FGraphBuilder.AddFilter(FVideoRender, 'Video Renderer');
if failed(FVideoRender.QueryInterface(IID_IVMRFilterConfig9, FConfig)) then exit;
FConfig.SetNumberOfStreams(1);
if failed(FVideoRender.QueryInterface(IID_IVMRMixerBitmap9, FBitmap)) then exit;
///////////////////////-----///////////////////
FBitmap.SetAlphaBitmap(@VMRBitmap);

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Наш опрос
Оцените мой сайт
Всего ответов: 532
Уголок общения



Copyright MyCorp © 2017Конструктор сайтов - uCoz