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

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

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

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

Статистика

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


















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

Урок 6.1. Воспроизведение видео из файла ресурсов (exe, памяти, потока) средствами DirectShow.
Урок 6.1. 
Воспроизведение видео из файла ресурсов (exe, памяти) средствами DirectShow.

видео из файла ресурсов        В этой статье мы рассмотрим как создать файл с ресурсами содержащий, несколько видео файлов в формате avi и научимся воспроизводить их прямо из файла ресурсов (точнее мы создадим поток и будем воспроизводить видео из потока). К сожалению DirectShow не позволяет обычными средствами воспроизводить видео прямо из файла ресурсов. Самый простой способ воспроизвести такое видео – это создать временный файл и сохранить видео в нем, воспроизвести файл, а затем его уничтожить. Но бывают случаи, когда видео нужно воспроизводить прямо из памяти без промежуточного создания файла на диске. В этом случае на помощь может придти фильтр из Demo примеров пакета DSPack для работы с потоками памяти (DSPack\Demos\D6-D7\Filters\Async\).
Пример в этой статье будет как раз посвящен воспроизведению видео из памяти с помощью этого фильтра и средств DirectShow.
Но в начале научимся создавать файл с ресурсами.

Создание файла сценария ресурсов (.RC)

        Файл сценария ресурсов представляет собой простой текстовый файл с расширением .RС, в котором  перечисляются ресурсы. Файл сценария имеет следующий формат:

Имя_ресурса1 Тип_ресурса1 Путь_к_файлу1
Имя_ресурса2 Тип_ресурса2 Путь_к_файлу2
…………
Имя_ресурсаХ Тип_ресурсаХ Путь_к_файлуХ


Каждый ресурс описывается с новой строки.

Имя_ресурса - определяет или уникальное имя или целое число (ID), который обозначает ресурс.
Тип_ресурса - описывает тип ресурса.
Путь_к_файлу - полный путь и имя файла, который будет включен в ресурс. (Примечание: Если файлы расположены внутри каталога проектов, то Вы не должны включать полный путь к файлам, а только имя и расширение.)

Коротенькие видео файлы для нашего проекта можно скачать здесь.

Для создания файла сценария ресурсов для нашего проекта проделайте следующее:

Создайте новый текстовый файл в каталоге проектов со следующим содержанием:

video1 AVI video1.avi
video2 AVI video2.avi


Текстовый файл можно создать, например с помощью блокнота.
Сохраните его с именем MyRes.RC

Где video1 и video2 имена наших ресурсов,а video1.avi и video2.avi имена видео файлов для включения в файл ресурсов. AVI – тип ресурса. Сами видео файлы должны находиться в каталоге с вашим будущим проектом.
После создания файла ресурсов, видео файлы можно будет удалить.

Все инструкции в .RC файле связывают имя ресурса, тип и имя файла для данного ресурса. Есть около десятка предопределенных типов ресурсов. Они включают иконки, точечные рисунки, курсоры, анимацию и т.д. RCDATA определяет пользовательский тип данных. Пользовательские ресурсы данных разрешают включение двоичных данных непосредственно в исполняемом файле.


Создание файла ресурсов (.RES)

       Чтобы использовать ресурсы, определенные в файле сценария ресурсов, мы должны скомпилировать его в .RES файл при помощи Borland Resource Compiler.
Компилятор ресурсов создает новый файл, основанный на содержании файла сценария ресурсов. Этот файл имеет обычно расширение .RES. Компоновщик позже будет повторно форматировать .RES файл в файл объекта ресурсов, а затем связывать его с исполнимым файлом приложения. Bopland Resource Compiler находится в каталоге Delphi/Bin. Имя - BRCC32.exe . Подготовьте файл MyRes.RC и выполните команду BRCC32.exe MyRes.RC в каталоге проектов (для этого можно использовать например TotalCommander).

По умолчанию, при компилировании ресурсов, BRCC32.exe называет скомпилированный файл с расширением .RES с именем .RC файла и помещает его в тот же каталог, что и .RC. Поэтому если вы все сделали правильно в каталоге с проектом у вас должен появиться файл с именем MyRes.RES.

Подключение файла ресурсов к исполнимому файлу.

       Для подключения файла ресурсов мы должны добавить следующую директиву компилятора в модуле нашего проекта сразу после директивы формы (ниже ключевого слова implementation) нужно прописать {$R MyRes.RES}
Не удаляйте директиву {$R *.DFM}, так как эта строка кода сообщает о подключении визуальной части формы. Более подробно почитать о ресурсных файлах можно здесь.

Приступим к созданию нашего проекта. Запустим Delphi и создадим новый проект.
На форму разместим компоненты TPanel и TListBox как показано на рисунке:



Для ListBox1 свойство Items -> TStrings -> String List Editor в первой строке пишем video1, а во второй строке video2. Это имена ресурсов которые мы задали в файле ресурсов. Сохраняем проект.

Далее для работы нашего проекта нам понадобятся следующие файлы UMemFile.pas, UAsyncIO.pas, UAsyncRdr.pas из пакета DSPack (DSPack\Demos\D6-D7\Filters\Async\), и BaseClass.pas, Jedi.inc, DSUtils.pas, (в старых версиях DSPack назывался DSUtil.pas)  (DSPack\src\DSPack\). Скачать эти файлы можно здесь. Скачать сам пакет DSPack для Delphi 2009 - XE можно здесь (там же есть версия DSPack для более ранних версий Delphi). Если вы установите DSPack то в папку с проектом нужно поместить только файлы UMemFile.pas, UAsyncIO.pas, UAsyncRdr.pas иначе необходимо поместить в папку с проектом все выше перечисленные файлы. Кроме этого для работы с DirectShow Вам понадобится скачать заголовочные файлы DirectShow API c сайта http://www.clootie.ru/ или здесь и  поместить их в каталог Delphi\Lib, либо добавить путь к каталогу, в котором они находятся в установках Delphi Library Path. Хотя если вы установите пакет DSPack, то эти файлы туда уже входят и скачивать их не надо.

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

В разделе Uses подключаем следующие модули:

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

В разделе Var:
var
  Form1: TForm1;
  KBPerSec: DWord = 0;
  mt: TAMMediaType;
  pmt: PAMMediaType;
  Mem: PByte;
  hr: HResult;
  Stream: TBCMemFileStream;
  Reader: TBCMemFileReader;
  ResHandle: THandle; //идентификатор ресурса
  MemHandle: THandle; //идентификатор ресурса в памяти
  ResSize: Longint; //размер ресурса
  _FG: IGraphBuilder = nil;  // интерфейс построения графа
  _Pin: IPin = nil; //выходной Pin нашего фильтра
  _MC: IMediaControl = nil; //интерфейс управления графом
  _VW: IVideoWindow = nil; //интерфейс управления окном видео

После implementation:

implementation

{$R *.dfm}
//подключаем файл с ресурсами
{$R MyRes.RES}


Далее для события OnCreate формы пишем:

procedure TForm1.FormCreate(Sender: TObject);
begin
//Инициализация COM
   CoInitialize(nil);
end;

Для события OnClose формы:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
//освобождаем подключенные интерфейсы
  if Assigned(_VW) then _VW := nil;
  if Assigned(_MC) then _MC := nil;
  if Assigned(_FG) then _FG := nil;

//Деинициализация СOM
  CoUninitialize;
end;

Для события OnDblClick Listbox1 пишем:

procedure TForm1.ListBox1DblClick(Sender: TObject);
begin
  // Настраеваем тип медиа потока
  pmt := @mt;
  TBCMediaType(pmt).InitMediaType;
  mt.majortype := MEDIATYPE_Stream;
  mt.subtype := MEDIASUBTYPE_Avi;

{При использовании видео файлов в формате не AVI необходимо задать другой subtype:
'.MPG' - mt.subtype := MEDIASUBTYPE_MPEG1System
'.MPA' - mt.subtype := MEDIASUBTYPE_MPEG1Audio
'.MPV' - mt.subtype := MEDIASUBTYPE_MPEG1Video
'.DAT' - mt.subtype := MEDIASUBTYPE_MPEG1VideoCD
'.AVI' - mt.subtype := MEDIASUBTYPE_Avi
'.MOV' - mt.subtype := MEDIASUBTYPE_QTMovie
'.WAV' - mt.subtype := MEDIASUBTYPE_WAVE}

  // Находим ресурс и получаем его Handle
  ResHandle := FindResource(hInstance, PChar(listbox1.Items.Strings[listbox1.ItemIndex]), PChar('AVI'));
  // Загружаем ресурс в память и получаем его Handle
  MemHandle := LoadResource(hInstance, ResHandle);
  // Блокируем ресурс в памяти и считываем его адpес
  mem := LockResource(MemHandle);
  // Получаем размер ресурса
  ResSize := SizeOfResource(hInstance, ResHandle);

  // Создаем поток для нашего source фильтра
  Stream := TBCMemFileStream.Create(Mem, ResSize, KBPerSec);
  hr := S_OK;
  Reader := TBCMemFileReader.Create(Stream, pmt, hr);

  //  Make sure we don't accidentally go away!
  Reader._AddRef;

(*Начало инициализации графа фильтров. Можно вынести в отдельную процедуру*)
 //освобождаем подключенные интерфейсы

  if Assigned(_VW) then _VW := nil;
  if Assigned(_MC) then _MC := nil;
  if Assigned(_FG) then _FG := nil;

  //Получаем интерфейс построения графа
  hr := CoCreateInstance(CLSID_FilterGraph, nil, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, _FG);
  if Failed(hr) then
  begin
    showmessage('Ошибка создания графа фильтров');
    Exit;
  end;

  // Добавляем наш фильтр
  hr := _FG.AddFilter(Reader, nil);
  if Failed(hr) then
  begin
    showmessage('Ошибка добавления фильтра');
    Exit;
  end;

  // Получаем выходной Pin
  _Pin := Reader.GetPin(0);

  //строим цепочку фильтров от выходного Pin
  hr := _FG.Render(_Pin);
  if Failed(hr) then
   begin
    showmessage('Ошибка получения выходного Pin');
    Exit;
  end;

   // Получаем интерфейс MediaControl от графа фильтров
  hr := _FG.QueryInterface(IID_IMediaControl, _MC);
  if Failed(hr) then
  begin
    showmessage('Ошибка получения интерфейса MediaControl');
    Exit;
  end;

   //получаем интерфейс VideoWindow от графа фильтров
   hr :=_FG.QueryInterface(IID_IVideoWindow, _VW);
   if Failed(hr) then
   begin
    showmessage('Ошибка получения интерфейса VideoWindow');
    Exit;
   end;

   //распологаем окно вывода на Panel1
   _VW.put_Owner(form1.Panel1.Handle);
   //задаем стиль окна
   _VW.put_WindowStyle(WS_CHILD or WS_CLIPSIBLINGS);
   //растягиваем видео на всю панель
   _VW.SetWindowPosition(0, 0, form1.Panel1.ClientRect.Right,form1.Panel1.ClientRect.Bottom);
   //запускаем воспроизведение видео
   hr := _MC.Run;
   if Failed(hr) then
   begin
      showmessage('Ошибка воспроизведения');
      Exit;
   end;
(*Конец инициализации графа фильтров.*)

  // don't use Reader.Free !!!
  // The Reader will destroy itself if the Reference Count is 0

  Reader._Release;

  // Разблокируем ресурс в памяти
  UnLockResource(MemHandle);

  // Освобождаем память занятую ресурсом
  FreeResource(MemHandle);
  FreeResource(ResHandle);
end;

Сохраняем и запускаем проект. Если выскочит ошибка в модуле DsPack на строчку  Result.FrameRateCode := (x and $00000003) shr 00; то просто за комментируйте ее и все должно работать.)))



Скачать исходник проекта можно здесь.
Исходник написан на Delphi 2010.
Автор статьи xaramamburu, сайт автора http://basicsprog.ucoz.ru .


Категория: Работа с библиотеками BASS и DirectShow | Добавил: xaramamburu (16.09.2012)
Просмотров: 6315 | Комментарии: 6 | Теги: ресурсы, Video, память, DirectShow | Рейтинг: 0.0/0
Всего комментариев: 6
3  
Подскажите, пожалуйста, как с помощью DirectShow воспроизвести видео с TFileStream?

4  
Можно так.
В место этого:

// Находим ресурс и получаем его Handle
ResHandle := FindResource(hInstance, PChar(listbox1.Items.Strings[listbox1.ItemIndex]), PChar('AVI'));
// Загружаем ресурс в память и получаем его Handle
MemHandle := LoadResource(hInstance, ResHandle);
// Блокируем ресурс в памяти и считываем его адpес
mem := LockResource(MemHandle);
// Получаем размер ресурса
ResSize := SizeOfResource(hInstance, ResHandle);

Пишем такой код:

//создаем поток из файла для чтения
FileStream := TFileStream.Create('video1.avi', fmOpenRead); - вместо video1.avi укажите ваш файл.
//получаем дескриптор потока
FileStreamHandle := FileStream.Handle;
//получаем размер
ResSize := FileStream.Size;
//выделяем память
GetMem(Mem, ResSize);
//читаем данные в память
ReadFile(FileStreamHandle, Mem^, ResSize, BytesRead, nil);
//освобождаем поток
CloseHandle(FileStreamHandle);

В разделе Var добавим переменные:

FileStreamHandle: THandle;
FileStream: TFileStream;
BytesRead: DWord;

Я в этом не большой спец, возможно что то и не так, но у меня работает.))))

5  
Спасибо, очень помогли! =)

1  
Есть вопрос, как сюда добавить перемотку?

2  
Смотрите статью по созданию видеоплеера урок 2.1. и 2.2. Там перемотка реализована. Здесь должно быть все аналогично.))))

6  
Привет, что-то не получается поставить перемотку, может пример скинешь? Заранее спасибо!

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



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