Video for Windows содержит DLL-библиотеки и драйверы, обеспечивающие интерфейс между приложениями и устройствами мультимедиа, предназначенными для работы cо звуковыми данными и видеоданными.
Приложения, проигрывающие файлы мультимедиа (в том числе avi-файлы), могут воспользоваться драйвером mciavi.drv , предоставляющим в распоряжение приложения высокоуровневый интерфейс MCI. Однако более предпочтительно использование интерфейса, который обеспечивается библиотекой msvideo.dll . Эта библиотека является надстройкой над интерфейсом MCI, значительно упрощающей его использование. Она нужна не только для проигрывания, но и для записи. В этой главе мы приведем исходные тексты приложений, работающих через интерфейс библиотеки msvideo.dll.
Вызывая функции интерфейса Video for Windows, приложения не имеют дело с внутренней структурой avi-файлов, так как библиотека avifile.dll обеспечивает им всю необходимую поддержку.
Приложения, предназначенные для записи звуковых данных и видеоданных, могут воспользоваться удобным высокоуровневым интерфейсом, предоставляемым библиотекой avicap.dll . Создавая приложения для записи видео, вам не придется заботиться о внутренней структуре avi-файлов, о компрессии (сжатии) данных при записи, об интерфейсе с драйверами устройства (или устройств) записи. При необходимости, вы, тем не менее, можете воспользоваться интерфейсом более низкого уровня, который обеспечивается библиотекой avifile.dll.
Редакторы файлов мультимедиа могут использовать библиотеки avifile.dll и msvideo.dll для доступа к данным и средствам отображения, а также системам компресии данных.
В составе Video for Windows имеются две системы компресии.
Первая из них - устанавливаемый менеджер компресии ICM (Installable Compression Manager ) предназначен для сжатия и восстановления видеоданных в реальном времени. Он может восстанавливать сжатые данные динамически во время проигрывания avi-файла. При создании новых avi-файлов можно использовать различные алгоритмы компресии. Собственно компрессия и восстановление выполняются драйверами компресии. Несколько таких драйверов поставляется в составе Video for Windows. Имеется возможность создания новых драйверов компресии при помощи Video for Windows Development Kit.
Вторая система - звуковой менеджер компресии ACM (Audio Compression Manager ). Он выполняет компрессию и восстановление звуковых данных в реальном времени. Вы можете использовать для компресии звуковых данных алгоритмы, реализуемые готовыми драйверами, или созданными вами с помощью Video for Windows Development Kit.
Перед тем как приступить к изучению программного интерфейса Video for Windows (вернее, его небольшой части, касающейся окна MCI) неплохо было бы научиться создавать и редактировать avi-файлы, пользуясь утилитами, входящими в состав Video for Windows и Video for Windows Development Kit. Существует несколько способов создания avi-файлов, и не все они связаны с использованием видеокамеры и адаптера для ввода изображения. Даже если у вас нет оборудования для ввода в компьютер видео, все равно вы можете создавать мультфильмы и демонстрационные ролики.
В этом разделе мы научимся создавать приложения для проигрывания файлов мультимедиа и дорожек компакт-дисков (а также для записи звуковых файлов) с использованием окна MCI.
Однако перед тем как приступить к описанию способов работы с этим окном, рассмотрим пример простейшего приложения, использующего окно MCI для проигрывания файлов мультимедиа.
5.1. Обзор Video for Windows
5.2. Создание и редактирование avi-файлов
5.3. Работа с окном MCI
Эта глава посвящена системе Microsoft Video for Windows версии 1.1 (рис. 5.1), которая поставляется отдельно в качестве расширения для Microsoft Windows и Microsoft Windows for Workgroups. Новые версии операционной системы Windows, например, Windows NT версии3.5, поставляются со встроенной системой Video for Windows Runtime, позволяющей проигрывать avi-файлы и другие мультимедиа-файлы.
Драйвер mciavi.drv предназначен для проигрывания файлов мультимедиа, содержащих звуковые данные и видео (как с поддержкой цветовых палитр, так и в режиме True Color). Звуковые данные могут быть моно- или стереофоническими с частотой дискретизации 44,1 Кгц, 22,05 Кгц или 11,025 Кгц. С помощью драйвера mciavi.drv можно проигрывать avi-файлы, содержащие звук и видео, только видео или только звук.
При воспроизведении видео со звуком возникает проблема синхронизации. К сожалению, производительность компьютера и особенно его видеоподсистемы не всегда оказывается достаточной для воспроизведения всех кадров, записанных в avi-файле, с нужной скоростью. В случае необходимости драйвер mciavi.drv пропускает некоторые кадры. Из-за инерционности зрения качество изображения во многих случаях остается при этом вполне удовлетворительным. Однако перерывы в воспроизведении звуковых данных или пропуски фрагментов звуковых данных недопустимы. Поэтому в процессе пропуска видеокадров драйвер mciavi.drv обеспечивает предварительную выборку звуковых данных и непрерывность воспроизведения звуковой информации.
В дополнение к командам MCI, рассмотренным нами ранее и предназначенным для управления звуковыми устройствами и устройствами чтения компакт-дисков, драйвер mciavi.drv позволяет использовать команды, имеющие отношение к воспроизведению видео. В частности, с помощью этих команд можно указать параметры окна, в котором будет выполняться просмотр видео. Однако, как мы уже говорили, самый простой способ проигрывания avi-файлов заключается в использовании интерфейса окна MCI вместо классического интерфейса MCI.
Перечислим некоторые другие полезные макрокоманды, имеющие отношение к окну MCI.
Макрокоманды MCIWndCanConfig , MCIWndCanEject , MCIWndCanPlay , MCIWndCanRecord , MCIWndCanSave , MCIWndCanWindow позволяют определить, соответственно, возможность конфигурирования, автоматической смены носителя, проигрывания, записи, сохранения и проигрывания в окне. Все эти макрокоманды имеют один параметр - идентификатор окна MCI. Если та или иная возможность поддерживается, соответствующая макрокоманда возвращает значение TRUE, в противном случае FALSE.
В любой момент времени приложение может изменить стиль окна MCI, вызвав макрокоманду MCIWndChangeStyles . Пример испльзования этой макрокоманды есть в приложении MCIWNDC (см. ниже). Для определения текущего стиля окна MCI можно воспользоваться макрокомандой MCIGetStyles .
Несколько макрокоманд предназначены для определения характеристик файла или такого носителя данных, как звуковой компакт-диск, загруженного в окно MCI. С помощью макрокоманд MCIWndGetLength , MCIWndGetStart , MCIWndGetEnd , MCIWndGetPosition , MCIWndGetPositionString приложение может определить, соотетственно, длину файла, начальную позицию, конечную позицию, текущую позицию и текущую позицию в виде текстовой строки.
Приложение может установить скорость проигрывания, громкость и размеры окна MCI, вызвав, соответственно, макрокоманды MCIWndSetSpeed , MCIWndSetVolume , MCIWndSetZoom . Есть макрокоманды, с помощью которых можно определить текущее значение для скорости проигрывания, громкости и размеров окна MCI - MCIWndGetSpeed , MCIWndGetVolume и MCIWndGetZoom .
Есть макрокоманды для изменения формата времени и определени текущего формата времени (MCIWndSetTimeFormat , MCIWndGetTimeFormat , MCIWndUseFrames , MCIWndUseTime ), для обновления информации о позиции при замене носителя данных (MCIWndValidateMedia ), для работы с таймером, палитрами и некоторые другие.
Если же этого обширного списка все же не хватит, то с помощью макрокоманды MCIWndSendString вы сможете передать окну любую команду MCI, лишь бы ее поддерживало используемое устройство. Ответ драйвера на посланную команду можно получить в виде текстовой строки при помощи макрокоманды MCIWndReturnString .
Video for Windows добавляет в Windows программный интерфейс, с помощью которого приложения могут рисовать изображения DIB на экране. Имена этих функций начинаются с DrawDib , что, очевидно, говорит об их назначении. Функция DrawDibDraw может все, что может функция StretchDIBits , однако работает быстрее. Дополнительно при отображении вызывается система ICM, выполняющая восстановление сжатых изображений непосредственно перед выводом на экран. Если исходное изображение имеет формат True Color, а устройство вывода обладает средним или низким цветовым разрешением, функции выполняют рисование с использованием смешивания (dithering) цветов.
Приложение может создать окно MCI, указав его параметры, управлять им с помощью передачи сообщений через удобный в использовании набор макрокоманд и функций, а также удалить окно MCI. Этих функций и макрокоманд так много, что мы не можем описать их все подробно из-за ограниченного объема нашей книги. Рассмотрим некоторые, самые полезные на наш взгляд, функции и макрокоманды, предназначенные для работы с окном MCI. Полную информацию вы сможете найти в документации, которая поставляется вместе с Video for Windows Development Kit.
При создании окна MCI вы можете указать (определив соответствующие стили), что в случае возникновения ошибки, замены носителя данных, изменения режима, текущей позиции или размера окна отображения родительское окно должно получать извещающие сообщения. Рассмотрим эти сообщения.
Для компресии видеоданных можно использовать один из компрессоров , поставляемых вместе с Video for Windows, или приобретенный отдельно.
Если видеоизображение содержит большие площади однотонного цвета, хорошие результаты получаются при использовании метода компресии Microsoft RLE . Этим методом имеет смысл пользоваться для сжатия видеофильмов, записанных с экрана компьютера при помощи приложения Screen Capture. Особенно хорошие результаты получаются в том случае, если изображение меняется от кадра к кадру не очень сильно.
Метод компресии Cinepak Codek дает хорошие результаты при необходимости подготовить avi-файл для записи на компакт-диск со скоростью передачи данных 150 Кбайт в секунду (одинарная скорость). Для хранения видеоданных используется формат True Color (в нем для представления цвета используются 24 бита данных). При необходимости воспроизведения в режимах более низкого цветового разрешения выполняется автоматическое преобразование цветов и, если это нужно, создание цветовых палитр. Учтите, что процесс сжатия изображения может длиться часами даже при использовании высокопроизводительного компьютера.
Более быстро, хотя и не так качественно, как Cinepak Codek, работает метод Microsoft Video 1 . При использовании этого метода вы можете выбрать 8-битовый или 16-битовый формат для храненеия цвета.
Метод Intel Indeo Video R3.1 хранит изображения в формате True Color. Формат видеоданных совместим с видеоадаптером Smart Video Recorder, позволяющим получать при записи сжатые данные в реальном времени.
Создавая avi-файл, рекомендуется попробовать несколько методов и остановиться на том, который обеспечивает хорошее качество при приемлимых размерах файла.
Приложения могут обращаться непосредственно к менеджеру ICM для сжатия и восстановления видеоданных, причем ICM по запросу приложения может вывести восстановленные данные на экран. Как правило, явное обращение к ICM требуется только для приложений, редактирующих видеоданные. Средства записи и воспроизведения видео, предоставляемые окнами AVICap и MCI, выполняют компрессию автоматически в прозрачном для приложения режиме.
Аналогично используется компрессор звуковых данных ACM. Система ACM может выполнять не только компрессию и восстановление звуковых данных, но также преобразование и фильтрацию (например, с помощью соответствующего фильтра можно добавить эхо). ACM устанавливается между приложением и библиотекой mmsystem.dll и работает с помощью механизма перехвата вызовов этой библиотеки. Для выполнения преобразований формата ACM обращается к драйверам преобразования формата, которые устанавливаются в системе вместе с Video for Windows или дополнительно.
Пользователь может управлять системой ACM при помощи приложения Sound Mapper , которое доступно из Control Panel после установки Video for Windows (рис. 5.4).
Сообщение MCIWNDM_NOTIFYERROR передается родительскому окну при возникновении ошибки. Параметр wParam содержит идентификатор окна MCI, параметр lParam - указатель на текстовую строку с описанием ошибки.
При изменении носителя данных (устройства или файла) родительское окно получает сообщение MCIWNDM_NOTIFYMEDIA . Параметр lParam содержит указатель на текстовую строку с именем файла или устройства. Если устройство или файл закрыты, этот параметр имеет значение NULL. Параметр wParam не используется.
При изменении режима работы родительское окно получает сообщение MCIWNDM_NOTIFYMODE , причем код нового режима находится в параметре lParam. Параметр wParam не используется.
Сообщение MCIWNDM_NOTIFYPOS передается родительскому окну при изменении текущей позиции. Новая позиция находится в параметре lParam. Параметр wParam не используется.
Если пользователь изменил размер окна MCI, родительское окно получает сообщение MCIWNDM_NOTIFYSIZE . Параметр wParam содержит идентификатор окна MCI, параметр lParam не используется и равен нулю.
Для создания приложений, записывающих видео, лучше всего воспользоваться классом окна AVICap , определенном в библиотеке avicap.dll . Создав окно на базе класса AVICap, приложение получит в свое распоряжение простой интерфейс для записи видео и звуковых данных в avi-файл, для предварительного просмотра видео и выполнения других операций.
В классе AVICap предусмотрены средства динамического переключения устройств записи видео и звука, что удобно в тех случаях, когда возможно поочередное использование нескольких таких устройств, установленных в компьютере. Приложение может создать avi-файл, предназначенный для записи, скопировать содержимое одного avi-файла в другой, установить частоту кадров, вывести на экран диалоговую панель, с помощью которой пользователь сможет задать формат записи. Есть средства для работы с палитрами и универсальным буфером обмена Clipboard.
Для записи звука класс окна AVICap пользуется срествами библиотеки mmsystem.dll, подробно рассмотренными нами ранее.
Библиотека msvideo.dll содержит определение класса окна MCI, на базе которого можно очень легко создавать приложения, управляющие устройствами для воспроизведения видео, воспроизведения и записи звуковых данных, воспроизведения MIDI, а также приложения, управляющие устройствами чтения компакт-дисков.
Окно MCI создать также просто, как и обычное окно. Более того, для его создания можно использовать привычную вам функцию CreateWindow , хотя есть и специальная функция MCIWndCreate . При создании окна вы можете использовать в дополнение к стандартным стилям окна некоторые другие. Например, вы можете указать, что окно MCI должно иметь набор органов управления для запуска проигрывания, записи, доступа к меню и полосу просмотра (рис.5.3).
Вы можете записать звук одновременно с записью видео, или добавить его позже при помощи приложения VidEdit. Для добавления звука в "немое" видео откройте avi-файл из приложения VidEdit и выберите из меню "File" строку "Insert...". В списке "List Files of Type" появившейся диалоговой панели "Insert File" выберите строку "Microsoft Waveform". Далее укажите wav-файл, содержащий добавляемый звук.
Все! Файл озвучен и его нужно сохранить. Полезно также перед озвучиванием сделать копию исходного файла.
В некоторых случаях вам может потребоваться выполнить синхронизацию видео и звукового сопровождения. Для выполнения синхронизации используйте диалоговую панель "Synchronize" (рис. 5.7). В этой диалоговой панели вы можете задать скорость проигрывания видео и смещение звуковых данных относительно начала фильма в миллисекундах (в поле Audio Offset).
Макрокоманда MCIWndSeek позволяет установить новую позицию для окна MCI, идентификатор которого передается ей в качестве первого параметра (здесь имеется в виду не расположение окна MCI на экране, а текущая позиция при проигрывании мультимедиа-файла). Через второй параметр передается значение новой позиции в формате двойного слова.
Макрокоманды MCIWndHome и MCIWndEnd позволяют установить текущую позицию, соотетственно, в начало и конец. Обе эти макрокоманды имеют только один параметр - идентификатор окна MCI.
С помощью макрокоманды MCIWndStep можно выполнить продвижение текущей позиции на один шаг. Величина шага задается в формате двойного слова в качестве второго параметра. Первый параметр - как всегда, идентификатор окна MCI.
Приложение MCIWND создает окно MCI (рис. 5.10) и... все!
Теперь нашей задачей будет создание такого приложения, которое выполняет управление окном MCI с помощью перечисленных выше макрокоманд.
Приложение MCIWNDC (рис. 5.18) может проигрывать avi- и wav-файлы, файлы в стандарте MIDI, а также дорожки звуковых компакт-дисков. Кроме этого, приложение может записывать wav-файлы.
Зная идентификатор окна MCI, вы можете управлять окном, используя набор макрокоманд, таких, как MCIWndRecord (включение режима записи) и MCIWndPlay (включение режима воспроизведения). Есть также средства для передачи окну обычных команд или командных строк MCI.
Вы можете создать окно MCI как перекрывающееся (overlapped) или дочернее (child), расположив его в любом месте экрана или родительского окна.
В большинстве случаев для проигрывания файлов мультимедиа возможности окна MCI более чем достаточны. Поэтому в нашей книге основное внимание мы уделим именно окну MCI.
В поле Sound Mapper Drivers отображается список установленных драйверов и их приоритет (который можно изменить, воспользовавшись кнопкой "Priority..."). Для работы будет выбран первый подходящий по своим возможностям драйвер, причем выбор будет выполняться с учетом приоритетов.
В поле Sound Device Preferences можно выбрать устройство для проигрывания или записи (если их несколько).
Систему ACM можно рассматривать как расширение библиотеки mmsystem.dll, обеспечивающее возможность работы с новыми форматами звуковых данных. Когда приложение пытается открыть устройство, поддерживающее тот или иной формат звуковых данных, ACM либо предоставляет приложению физическое устройство, либо подбирает компрессор или декомпрессор, преобразующий указанный формат в один из форматов, поддерживаемых физическим устройством.
ACM также предоставляет программный интерфейс, пользуясь которым приложения могут получать информацию об установленных драйверах, поддерживаемых форматах звуковых данных, фильтров, а также выполнять преобразования звуковых данных из одного формата в другой.
С помощью меню "File" вы можете загрузить для редактирования готовый avi-файл (строка "Open...") или создать новый (строка "New"). Для создания avi-файла из последовательности bmp-файлов выберите из этого меню строку "Insert...". В списке "List Files of Type" появившейся диалоговой панели "Insert File" выберите строку "DIB Sequence".
Замените в поле "File Name" шаблон *.dib на *.bmp и выберите первый файл из подготовленной вами последовательности. Укажите формат файла как "DIB Sequence" и нажмите кнопку "OK". Последовательность bmp-файлов будет преобразована в avi-файл.
Сохраните созданный файл, выбрав из меню "File" строку "Save As...". На экране появится диалоговая панель "Save Video File", напоминающая стандартную диалоговую панель "Save As" из библиотеки commdlg.dll. Единственное существенное отличие заключается в том, что при помощи кнопки "Compression Options..." вы можете задать алгоритм сжатия, который будет использован при сохранении avi-файла (рис. 5.6).
Для начала используйте параметры, указанные на рис. 5.6. При необходимости вы можете изменить скорость воспроизведения видео, выбрав в меню "Video" строку "Synchronize...". На экране появится диалоговая панель "Synchronize", предназначенная для выполнения синхронизации видео и звука (рис. 5.7).
Изменив значение частоты кадров в поле "Video Speed", вы измените скорость воспроизведения видео.
Последовательность bmp-файлов (а также отедльные bmp-файлы) можно вставлять в любое место видео. Кроме графических файлов в формате DIB, редактор VidEdit позволяет вставлять отдельные изображения в форматах PC Paintbrush, TIFF, TGA, GIF и других популярных графических форматов.
Выберите строку "Set Capture File..." и с помощью появившейся диалоговой панели выберите avi-файл, в который будет записан видеоролик. Затем нужно указать область экрана, содержимое которой будет записано в avi-файл. Так как производительность компьютера может оказаться недостаточной для записи крупноформатного видео, в документации рекомендуется использовать область размером не больше чем 320 х 240 пикселов.
Затем выберите строку "Preferences..." и задайте режимы работы приложения (рис. 5.9).
В поле "Frame Rate" укажите частоту кадров. Если вместе с записью видео нужно выполнять запись звуковых данных, включите переключатель "Capture Audio" и укажите нужный формат звуковых данных, нажав на кнопку "Change...". По умолчанию для остановки процесса записи используется клавиша <Esc>. Вы можете заменить ее на другую в поле "Stop Recording Key".
Для запуска процесса записи выберите строку "Capture!" в меню приложения Screen Capture. Начнется запись видео и, возможно, звуковых данных.
Это окно, когда в него ничего не загружено, имеет стандартный заголовок и три органа управления - кнопку воспроизведения, кнопку доступа к меню и полосу просмотра.
Запустите загрузочный модуль этого приложения и нажмите кнопку доступа к меню (рис.5.11).
На экране появится почти стандартная диалоговая панель "Open", с помощью которой вы сможете выбрать файл мультимедиа для просмотра или прослушивания (рис. 5.12).
Обратите внимание, что в правом нижнем углу диалоговой панели имеются органы управления (кнопка и полоса просмотра), предназначенные для предварительного просмотра или прослушивания содержимого файла. Это очень удобно, так как при поиске файла не нужно много раз открывать и закрывать диалоговую панель "Open".
После загрузки wav-файла меню приложения модифицируется (рис. 5.13).
В нем появляется строка "Close", с помощью которой можно закрыть файл, строка "Copy", позволяющая скопировать содержимое файла в Clipboard, а также строка "Command...". Последняя предназначена для передачи устройству произвольной управляющей строки MCI (соответствующая диалоговая панель показана на рис. 5.14).
При выборе avi-файлов можно посмотреть их содержимое в небольшом окне (рис. 5.15).
Для работы с avi-файлами используется расширенное меню (рис. 5.16).
Строка "View" предназначена для управления размером окна. С помощью строк "Volume" и "Speed" можно регулировать, соответственно, громкость звука и скорость воспроизведения видео. Строка "Configure..." предназначена для установки параметров проигрывателя. При ее выборе на экране появляется диалоговая панель "Video Playback Options" (рис. 5.17).
В поле "Video Mode" вы можете включить режим отображения видео в окне (переключатель "Window") или на полном экране видеомонитора (переключатель "Full Screen"). Переключатель "Zoom by 2" позволяет уменьшить размер окна в два раза.
Если включен переключатель "Skip video frames if behind", для обеспечения непрерывности звука при необходимости будут пропускаться видеокадры.
Таким образом, приложение MCIWND выполняет довольно много функций. Вы, возможно, будете удивлены тем, что исходный текст приложения занимает не более двух страниц (листинг 5.1).
Листинг 5.1. Файл mciwnd/mciwnd.c #include <windows.h> #include <vfw.h> static char szAppName[]="MCIWnd"; static HWND hwnd; // ===================================== // Функция WinMain // ===================================== int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; WORD wVersion; // Проверяем версию Video for Windows wVersion = HIWORD(VideoForWindowsVersion()); if(wVersion < 0x010a) { MessageBox(NULL, "Используйте Video for Windows" " версии 1.1 или более поздней версии", "MCIWnd Error", MB_OK | MB_ICONHAND); return FALSE; } // Создаем окно класса MCIWND hwnd = MCIWndCreate(NULL, hInstance, MCIWNDF_SHOWNAME | MCIWNDF_SHOWMODE | WS_OVERLAPPEDWINDOW | WS_VISIBLE, NULL); if(hwnd == NULL) return -1; // Устанавливаем заголовок окна SetWindowText(hwnd, szAppName); // Запускаем цикл обработки сообщений while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); if(!IsWindow(hwnd)) PostQuitMessage(0); } return msg.wParam; }
Исходный текст приложения подготовлен для трансляторов Microsoft C++ версии 7.0 или Microsoft Visual C++ версий 1.0 или 1.5, так как поставляющаяся в составе Video for Windows Development Kit библиотека vfw.lib совместима именно с этими трансляторами.
После файла windows.h в исходный текст необходимо включить файл vfw.h , который поставляется вместе с Video for Windows Development Kit. Он содержит определения всех необходимых констант, структур данных и прототипы функций.
В самом начале работы приложение вызывает функцию VideoForWindowsVersion , возвращающую в старшем слове версию Video for Windows: wVersion = HIWORD(VideoForWindowsVersion());
Версия Video for Windows должна быть не ниже 1.1.
Далее приложение создает окно MCI, вызывая для этого функцию MCIWndCreate : hwnd = MCIWndCreate(NULL, hInstance, MCIWNDF_SHOWNAME | MCIWNDF_SHOWMODE | WS_OVERLAPPEDWINDOW | WS_VISIBLE, NULL);
Функция MCIWndCreate позволяет определить обычные стили окна, такие как WS_OVERLAPPEDWINDOW и WS_VISIBLE, а также специфические для окна MCI - MCIWNDF_SHOWNAME и MCIWNDF_SHOWMODE. Позже мы рассмотрим подробнее эту функцию и дополнительные стили окна.
После создания окна запускается цикл обработки сообщений, который имеет одну особенность - в нем периодически вызывается функция IsWindow , которая определена в стандартном программном интерфейсе Windows: if(!IsWindow(hwnd)) PostQuitMessage(0);
Эта функция проверяет идентификатор окна, передаваемого ей через параметр. Если этот идентификатор правильный, возвращается TRUE. После того как пользователь уничтожит окно MCI, его идентификатор станет недействительным. В этом случае функция IsWindow вернет значение FALSE и будет вызвана функция PostQuitMessage, в результате чего работа приложения завершится.
Вот и все! По сложности исходного текста это приложение напоминает наши первые приложения из 10 тома "Библиотеки системного программиста", однако выполняемые им функции во много раз сложнее. Все дело тут, разумеется, в реализации класса окна MCI.
Файл описания ресурсов приведен в листинге 5.2.
Листинг 5.2. Файл mciwnd/mciwnd.rc AppIcon ICON mciwnd.ico
Файл определения модуля для приложения MCIWND не имеет никаких особенностей (листинг 5.3).
Листинг 5.3. Файл mciwnd/mciwnd.def NAME MCIWNDPL DESCRIPTION 'Приложение MCIWND, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 8196 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple
Теперь о том, как из исходного текста создать загрузочный модуль приложения MCIWND.
При использовании транслятора Microsoft C++ версии 7.0 вы можете воспользоваться файлом makefile , представленном в листинге 5.3.
Листинг 5.3. Файл mciwnd/makefile NAME = mciwnd OBJ = mciwnd.obj LIBS = libw slibcew vfw !if "$(DEBUG)" == "NO" DEF = CLOPT = MASMOPT = LINKOPT = !else DEF = -DDEBUG CLOPT = -Zid MASMOPT = -Zi LINKOPT = /CO/LI !endif CC = cl -c -W3 -AS -Zp -G2sw -Oxas $(DEF) $(CLOPT) -DWIN31 ASM = masm -Mx $(MASMOPT) LINK= link /NOE/NOD/LI/MAP/AL:16/ONERROR:NOEXE $(LINKOPT) RC = rc .c.obj: $(CC) $*.c .asm.obj: $(ASM) $*; goal: $(NAME).exe $(NAME).exe: $(OBJ) $(NAME).res $(NAME).def makefile $(LINK) $(OBJ), $(NAME), $(NAME),$(LIBS), $(NAME).def $(RC) -31 $(NAME).res -mapsym $(NAME).map $(NAME).res: $(NAME).rc $(NAME).ico $(RC) -r $(NAME).rc clean: del $(NAME).exe del *.res del *.obj del *.map del *.sym del *.pdb copy: copy $(NAME).exe ..\..\bin copy $(NAME).sym ..\..\bin depend: mv makefile makefile.old sed "/^# START Dependencies/,/^# END Dependencies/D" makefile.old > makefile del makefile.old echo # START Dependencies >> makefile includes -l *.c *.asm >> makefile echo # END Dependencies >> makefile
Особенностью транслятора Microsoft C++ версии 7.0 (а также версии 8.0, входящей в состав Visual C++, и трансляторов более ранних версий, запускаемых в среде MS-DOS) является использование переменных среды. Для правильной установки переменных среды подготовьте bat-файл, содежащий следующие команды (предполагается, что транслятор установлен в каталоге g:msvc, а Video for Windows Development Kit - в каталоге g:\vfwdk): @echo off set TOOLROOTDIR=G:\MSVC set PATH=G:\MSVC\BIN;%PATH% set INCLUDE=G:\MSVC\INCLUDE;g:\vfwdk\inc;%INCLUDE% set LIB=G:\MSVC\LIB;g:\vfwdk\lib;g:\windev\lib;%LIB% set INIT=G:\MSVC;%INIT%
Находясь в среде MS-DOS, сделайте текущим каталог, содержащий все файлы приложения MCIWND, и, после запуска приведенного выше пакетного файла, запустите программу nmake без параметров. В результате будет создан загрузочный модуль приложения.
Для того чтобы загрузочный модуль не содержал отладочной информации, добавьте в начало файла makefile следующую строку: DEBUG = NO
Можно также запустить программу nmake с параметром DEBUG=NO: nmake DEBUG=NO
Намного удобнее работать в среде Visual C++. Вместе с исходными текстами приложения MCIWND на дискете поставляется файл проекта mciwnd.mak, предназначенный для системы Visual C++.
Запустите Visual C++ и из меню "Project" выберите строку "Open...". С помощью появившейся диалоговой панели откройте файл проекта mciwnd.mak. Нажмите на самую левую кнопку в полосе инструментов. Появится список файлов, имеющих отношение к проекту. Выберите файл исходного текста. Возможно, что при этом вместо русских букв в окне редактирования вы увидите нечто, не поддающееся прочтению. В этом случае следует установить для редактора шрифт с русскими буквами.
Для изменения шрифта сделайте текущим окно редактирования и выберите в меню "Options" строку "Font...". На экране появится диалоговая панель "Font". Выберите в ней подходящий шрифт, имеющий русские буквы, и нажмите кнопку "Use as Default Font". При этом для всех создаваемыех вновь окон будет использоваться выбранный вами шрифт. Для завершения работы с диалоговой панелью нажмите кнопку "OK".
Не забудьте добавить пути к каталогам vfwdk\inc, wfwdk\lib и windev\lib с помощью диалоговой панели "Directories", которую можно вызвать, если в меню "Options" выбрать строку "Directories...".
После всех этих подготовительных действий выберите из меню "Project" строку "Build MCIWND.EXE". Будет запущен процесс создания загрузочного модуля (в фоновом режиме). После завершения этого процесса можно запустить приложение, выбрав из этого же меню строку "Execute MCIWND.EXE", или перейти в режим отладки, воспользовавшись меню "Debug".
Для проигрывания файлов мультимедиа их следует открыть при помощи строки "Open..." меню "File". При этом на экран будет выведена диалоговая панель "Open" с возможностью предварительного просмотра или прослушивания содержимого файла (рис. 5.19).
Меню "Movie" (рис. 5.20) и "Styles" (рис. 5.22) предназначены для управления окном MCI.
Строки "Play", "Play Reverse", "Record" и "Stop" предназначены, соответственно, для проигрывания, проигрывания в обратном направлении, записи и выполнения останова.
С помощью строк "Home" и "End" выполняется позиционирование на начало и конец файла. Строки "Step Fwrd" и "Step Back" дают возможность выполнять пошаговое перемещение вперед и назад.
Выбрав строку "Info...", вы увидите на экране диалоговую панель "Media Info" (рис.5.21), в которой будет отображено имя устройства, путь к загруженному в окно MCI файлу и размер этого файла.
С помощью строки "Play Bar" меню "Styles" (рис. 5.22) вы можете убрать или возвратить на место органы управления окном MCI.
Диалоговая панель, используемая при сохранении записанных wav-файлов, содержит средства предварительного просмотра или прослушивания (рис. 5.23).
Приложение MCIWNDC способно также проигрывать дорожки звуковых компакт-дисков. Внешний вид окна MCI, которое используется для этого, показан на рис. 5.24.
Несмотря на обилие возможностей, исходный текст приложения MCIWNDC занимает немного места (листинг 5.4).
Листинг 5.4. Файл mciwndc/mciwndc.cpp // ------------------------------------------------ // Приложение MCIWNDC // Использование класса окна MCIWnd для // проигрывания и записи файлов мультимедиа // ------------------------------------------------ #define STRICT #include <windows.h> #include <windowsx.h> #include <commdlg.h> #include <memory.h> #include <vfw.h> #include "mciwndc.h" // Прототипы функций BOOL InitApp(HINSTANCE); LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM); BOOL mciwndSelectFile(LPSTR lpszFileName); // Глобальные переменные char const szClassName[] = "MCIWNDCClass"; char const szMovieClass[] = MCIWND_WINDOW_CLASS; char const szWindowTitle[] = "MCIWnd Player & Recorder"; HINSTANCE hInst; HWND hwndMovie = NULL; // ===================================== // Функция WinMain // ===================================== int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения WORD wVersion; // версия Video for Windows if(hPrevInstance) return FALSE; // Проверяем версию Video for Windows wVersion = HIWORD(VideoForWindowsVersion()); if(wVersion < 0x010a) { MessageBox(NULL, "Используйте Video for Windows" " версии 1.1 или более поздней версии", "MCIWnd Error", MB_OK | MB_ICONHAND); return FALSE; } if(!InitApp(hInstance)) return FALSE; hInst = hInstance; hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // размеры и расположение окна CW_USEDEFAULT, 400, 350, 0, 0, hInstance, NULL); if(!hwnd) return FALSE; ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } // ===================================== // Функция InitApp // Выполняет регистрацию класса окна // ===================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации memset(&wc, 0, sizeof(wc)); wc.lpszMenuName = "APP_MENU"; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "APPICON"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszClassName = (LPSTR)szClassName; aWndClass = RegisterClass(&wc); return (aWndClass != 0); } // ===================================== // Функция WndProc // ===================================== LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { // ------------------------------------------------------------ // WM_INITMENU // Инициализация меню // ------------------------------------------------------------ case WM_INITMENU: { // Определяем стиль окна MCI WORD wStyles = MCIWndGetStyles(hwndMovie); // Если окно MCI имеет панель управления, // отмечаем строку "Play Bar" меню "Styles" CheckMenuItem(GetMenu(hwnd), CM_STPBAR, (wStyles & MCIWNDF_NOPLAYBAR) ? MF_UNCHECKED : MF_CHECKED); return 0; } // ------------------------------------------------------------ // WM_COMMAND // Обработка сообщений от меню // ------------------------------------------------------------ case WM_COMMAND: { switch (wParam) { // ------------------------------------------------- // Строка "About" меню "Help" // ------------------------------------------------- case CM_HELPABOUT: { MessageBox(hwnd, "MCIWnd Player & Recorder, v.1.0\n" "(C) Frolov A.V., 1994", "About MCIWNDC", MB_OK | MB_ICONINFORMATION); return 0; } // ------------------------------------------------- // Строка "New Waveaudio" меню "File" // ------------------------------------------------- case CM_FILENEW: { // Если окно MCI уже было создано, удаляем его if(hwndMovie) MCIWndDestroy(hwndMovie); // Создаем новое окно для записи звука, // открываем драйвер устройства waveaudio hwndMovie = MCIWndCreate( hwnd, hInst, WS_VISIBLE | WS_CHILD | WS_BORDER | MCIWNDF_RECORD, (LPSTR)"waveaudio"); // Создаем новый файл MCIWndNew(hwndMovie, "waveaudio"); return 0; } // ------------------------------------------------- // Строка "Save Waveaudio As..." меню "File" // ------------------------------------------------- case CM_FILESAVEAS: { // Создаем диалоговую панель "Save As..." для // сохранения файла MCIWndSaveDialog(hwndMovie); return 0; } // ------------------------------------------------- // Строка "CD Audio" меню "File" // ------------------------------------------------- case CM_FILECDAUDIO: { // Если окно MCI уже было создано, удаляем его if(hwndMovie) MCIWndDestroy(hwndMovie); // Создаем новое окно для проигрывания CD, // открываем драйвер устройства cdaudio hwndMovie = MCIWndCreate( hwnd, hInst, WS_VISIBLE | WS_CHILD | WS_BORDER | MCIWNDF_RECORD, (LPSTR)"cdaudio"); return 0; } // ------------------------------------------------- // Строка "Open" меню "File" // ------------------------------------------------- case CM_FILEOPEN: { char szBuff[256]; // Если окно MCI уже было создано, удаляем его if(hwndMovie) MCIWndDestroy(hwndMovie); // Выбираем файл для загрузки в окно MCI if(mciwndSelectFile(szBuff)) { // Создаем окно MCI hwndMovie = MCIWndCreate( hwnd, hInst, WS_VISIBLE | WS_CHILD | WS_BORDER | MCIWNDF_RECORD, (LPSTR)szBuff); } return 0; } // ------------------------------------------------- // Строка "Close" меню "File" // ------------------------------------------------- case CM_FILECLOSE: { // Удаляем окно MCI MCIWndDestroy(hwndMovie); hwndMovie = NULL; return 0; } // ------------------------------------------------- // Меню "Movie" // ------------------------------------------------- case CM_MVIPLAY: // "Play" { // Проигрывание MCIWndPlay(hwndMovie); return 0; } case CM_MVIRPLAY: // "Play Reverse" { // Проигрывание в обратном направлении MCIWndPlayReverse(hwndMovie); return 0; } case CM_MVISTOP: // "Stop" { // Останов MCIWndStop(hwndMovie); return 0; } case CM_MVIRECORD: // "Record" { // Запись MCIWndRecord(hwndMovie); return 0; } case CM_MVIHOME: // "Home" { // Позиционирование в начало MCIWndHome(hwndMovie); return 0; } case CM_MVIEND: // "End" { // Позиционирование в конец MCIWndEnd(hwndMovie); return 0; } case CM_MVISTEP: // "Step Fwrd" { // Шаг вперед MCIWndStep(hwndMovie, 1); return 0; } case CM_MVIRSTEP: // "Step Back" { // Шаг назад MCIWndStep(hwndMovie, -1); return 0; } case CM_MVIINFO: // "Info..." { char szBuff[512], szBuff1[256]; long dwSize; // Если окно MCI создано, выводим информацию // о загруженном в него файле if(hwndMovie) { // Имя устройства MCIWndGetDevice(hwndMovie, (LPSTR)szBuff, 512); lstrcat(szBuff, (LPSTR)"\n"); // Путь к файлу или имя устройства MCIWndGetFileName(hwndMovie, (LPSTR)szBuff1, 256); lstrcat(szBuff, (LPSTR)szBuff1); lstrcat(szBuff, (LPSTR)"\n"); // Размер файла dwSize = MCIWndGetLength(hwndMovie); wsprintf(szBuff1, "Size: %ld ", (long)dwSize); lstrcat(szBuff, (LPSTR)szBuff1); // Формат времени MCIWndGetTimeFormat(hwndMovie, (LPSTR)szBuff1, 256); lstrcat(szBuff, (LPSTR)szBuff1); MessageBox(hwnd, szBuff, "Media Info", MB_OK | MB_ICONINFORMATION); } return 0; } // ------------------------------------------------- // Меню "Styles" // ------------------------------------------------- case CM_STPBAR: // "Play Bar" { // Определяем стили окна MCI WORD wStyles = MCIWndGetStyles(hwndMovie); // Инвертируем состояние стиля MCIWNDF_NOPLAYBAR MCIWndChangeStyles(hwndMovie, MCIWNDF_NOPLAYBAR, (wStyles & MCIWNDF_NOPLAYBAR) ? 0 : MCIWNDF_NOPLAYBAR); return 0; } // ------------------------------------------------- // Строка "Exit" меню "File" // Завершение работы приложения // ------------------------------------------------- case CM_FILEEXIT: { DestroyWindow(hwnd); return 0; } default: return 0; } } // Отслеживаем изменения в системной палитре case WM_PALETTECHANGED: { SendMessage(hwndMovie, msg, wParam, lParam); break; } case WM_QUERYNEWPALETTE: { return SendMessage(hwndMovie, msg, wParam, lParam); } // ------------------------------------------------------------ // WM_DESTROY // Уничтожение главного окна приложения // ------------------------------------------------------------ case WM_DESTROY: { PostQuitMessage(0); return 0; } default: break; } return DefWindowProc(hwnd, msg, wParam, lParam); } //----------------------------------------------------- // mciwndSelectFile // Выбор файла //----------------------------------------------------- BOOL mciwndSelectFile(LPSTR lpszFileName) { OPENFILENAME ofn; char szFile[256]; char szFileTitle[256]; char szFilter[256] = "Video Files\0*.avi\0" "Waveaudio Files\0*.wav\0" "MIDI Files\0*.mid;*.rmi\0" "Any Files\0*.*\0"; szFile[0] = '\0'; memset(&ofn, 0, sizeof(OPENFILENAME)); // Инициализируем нужные нам поля ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = NULL; ofn.lpstrFilter = szFilter; ofn.nFilterIndex = 1; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = sizeof(szFileTitle); ofn.lpstrInitialDir = NULL; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; // Выбираем входной файл if (GetOpenFileNamePreview(&ofn)) { // Копируем путь к выбранному файлу lstrcpy(lpszFileName, (LPSTR)szFile); return TRUE; } else return FALSE; }
После проверки версии Video for Windows функция WinMain создает обычным образом главное окно приложения MCIWNDC и запускает цикл обработки сообщений. Эта часть приложения не имеет каких-либо особенностей.
При выборе строки "New Waveaudio" из меню "File" проверяется содержимое глобальной переменной hwndMovie, в которой хранится идентификатор окна MCI. Сразу после запуска приложения эта переменная содержит нулевое значение.
Если же окно MCI было создано ранее, оно удаляется при помощи макрокоманды MCIWndDestroy: if(hwndMovie) MCIWndDestroy(hwndMovie);
Далее создается окно MCI, причем одновременно открывается устройство waveaudio: hwndMovie = MCIWndCreate( hwnd, hInst, WS_VISIBLE | WS_CHILD | WS_BORDER | MCIWNDF_RECORD, (LPSTR)"waveaudio");
Создаваемое при этом окно MCI является видимым, дочерним и имеет рамку. Среди органов управления присутствует кнопка записи, так как указан стиль окна MCIWNDF_RECORD.
Затем создается новый файл, для чего используется макрокоманда MCIWndNew: MCIWndNew(hwndMovie, "waveaudio");
Сохранение записанных звуковых данных выполняется очень просто - с помощью макрокоманды MCIWndSaveDialog, позволяющей пользователю выбрать путь и имя файла: MCIWndSaveDialog(hwndMovie);
При выборе строки "CD Audio" в меню "File" окно MCI создается следующим образом: hwndMovie = MCIWndCreate( hwnd, hInst, WS_VISIBLE | WS_CHILD | WS_BORDER | MCIWNDF_RECORD, (LPSTR)"cdaudio");
Обратите внимание, что указан стиль MCIWNDF_RECORD. Так как драйвер устройства чтения компакт-дисков не поддерживает (увы!) операцию записи, среди органов управления окна MCI кнопка записи так и не появится. Поэтому при создании собственного приложения для проигрывания компакт-дисков средствами окна MCI вам не нужно указывать этот стиль.
Если приложение MCIWNDC используется для проигрывания файла, окно MCI создается при выборе строки "Open..." в меню "File". В этом случае приложение вызывает функцию mciwndSelectFile, которая позволяет пользователю выбрать файл и записывает путь к файлу в переменную szBuff. Далее окно MCI создается следующим образом: hwndMovie = MCIWndCreate( hwnd, hInst, WS_VISIBLE | WS_CHILD | WS_BORDER | MCIWNDF_RECORD, (LPSTR)szBuff);
При создании окна MCI указан стиль MCIWNDF_RECORD, однако кнопка записи появится только при загрузке wav-файла, так как запись средствами окна MCI возможна только для устройства "waveaudio".
При выборе из меню "File" строки "Close" окно MCI удаляется функцией MCIWndDestroy.
Обработка сообщений от меню "Movie" сводится в основном к вызову соответствующей макрокоманды. Например, при выборе из этого меню строки "Play" вызывается макрокоманда MCIWndPlay: case CM_MVIPLAY: // "Play" { MCIWndPlay(hwndMovie); return 0; }
Аналогичным образом обрабатываются остальные команды, за исключением команд позиционирования на один шаг вперед и один шаг назад: case CM_MVISTEP: // "Step Fwrd" { MCIWndStep(hwndMovie, 1); return 0; } case CM_MVIRSTEP: // "Step Back" { MCIWndStep(hwndMovie, -1); return 0; }
Второй параметр макрокоманды MCIWndStep указывает величину шага в миллисекундах или кадрах (в зависимости от текущего формата времени), причем отрицательным значениям соответствует позиционирование в обратном направлении.
При выборе из меню "Movie" строки "Info..." приложение определяет и выводит на экран информацию об используемом устройстве и загруженном файле.
Для определения имени устройства используется макрокоманда MCIWndGetDevice : MCIWndGetDevice(hwndMovie, (LPSTR)szBuff, 512);
Через первый параметр этой макрокоманде передается идентификатор окна MCI. Второй параметр - указатель на буфер, в который следует записать имя устройства. Третий параметр - размер буфера.
Путь к загруженному устройству или имя устройства (если файл не используется) определяется с помощью макрокоманды MCIWndGetFileName аналогичным образом: MCIWndGetFileName(hwndMovie, (LPSTR)szBuff1, 256);
Размер файла вычисляется макрокомандой MCIWndGetLength , возвращающей значение в формате двойного слова: dwSize = MCIWndGetLength(hwndMovie);
Единица измерения размера зависит от текущего формата времени, который определяется в виде текстовой строки при помощи макрокоманды MCIWndGetTimeFormat : MCIWndGetTimeFormat(hwndMovie, (LPSTR)szBuff1, 256);
Теперь о меню "Styles".
При выборе из этого меню строки "Play Bar" приложение определяет текущий стили окна, и затем инвертирует стиль MCIWNDF_NOPLAYBAR: case CM_STPBAR: // "Play Bar" { WORD wStyles = MCIWndGetStyles(hwndMovie); MCIWndChangeStyles(hwndMovie, MCIWNDF_NOPLAYBAR, (wStyles & MCIWNDF_NOPLAYBAR) ? 0 : MCIWNDF_NOPLAYBAR); return 0; }
Правильную отметку строки "Play Bar" в меню обеспечивает обработчик сообщения WM_INITMENU: case WM_INITMENU: { WORD wStyles = MCIWndGetStyles(hwndMovie); CheckMenuItem(GetMenu(hwnd), CM_STPBAR, (wStyles & MCIWNDF_NOPLAYBAR) ? MF_UNCHECKED : MF_CHECKED); return 0; }
Этот обработчик отмечает или нет строку "Play Bar" меню "Styles" в зависимости от того, имеет ли окно MCI стиль MCIWNDF_NOPLAYBAR, или нет.
Обработка сообщений об изменении системной палитры WM_PALETTECHANGED и о необходимости реализации палитры WM_QUERYNEWPALETTE заключается в непосредственной передаче соответствующих сообщений окну MCI, поэтому выполняется очень просто: case WM_PALETTECHANGED: { SendMessage(hwndMovie, msg, wParam, lParam); break; } case WM_QUERYNEWPALETTE: { return SendMessage(hwndMovie, msg, wParam, lParam); }
Файл mciwndc.h (листинг 5.5) содержит определения констант, используемых в приложении MCIWNDC.
Листинг 5.5. Файл mciwndc/mciwndc.h #define CM_HELPABOUT 301 #define CM_FILEEXIT 302 #define CM_FILEOPEN 303 #define CM_FILECLOSE 304 #define CM_FILENEW 305 #define CM_FILESAVEAS 306 #define CM_FILECDAUDIO 307 #define CM_MVIPLAY 401 #define CM_MVIRPLAY 402 #define CM_MVIHOME 403 #define CM_MVIEND 404 #define CM_MVISTEP 405 #define CM_MVIRSTEP 406 #define CM_MVISTOP 407 #define CM_MVIRECORD 408 #define CM_MVIINFO 409 #define CM_STPBAR 501
Файл определения ресурсов приложения представлен в листинге 5.6.
Листинг 5.6. Файл mciwndc/mciwndc.rc #include "mciwndc.h" AppIcon ICON mciwndc.ico APP_MENU MENU BEGIN POPUP "&File" BEGIN MENUITEM "&Open...", CM_FILEOPEN MENUITEM "&Close", CM_FILECLOSE MENUITEM SEPARATOR MENUITEM "&New Waveaudio", CM_FILENEW MENUITEM "Save Waveaudio &As...", CM_FILESAVEAS MENUITEM SEPARATOR MENUITEM "CD Audio", CM_FILECDAUDIO MENUITEM SEPARATOR MENUITEM "E&xit", CM_FILEEXIT END POPUP "&Movie" BEGIN MENUITEM "&Play", CM_MVIPLAY MENUITEM "Play &Reverse", CM_MVIRPLAY MENUITEM "R&ecord", CM_MVIRECORD MENUITEM "&Stop", CM_MVISTOP MENUITEM SEPARATOR MENUITEM "&Home", CM_MVIHOME MENUITEM "&End", CM_MVIEND MENUITEM SEPARATOR MENUITEM "Step &Fwrd", CM_MVISTEP MENUITEM "Step &Back", CM_MVIRSTEP MENUITEM SEPARATOR MENUITEM "&Info...", CM_MVIINFO END POPUP "St&yles" BEGIN MENUITEM "&Play Bar", CM_STPBAR END POPUP "&Help" BEGIN MENUITEM "&About...", CM_HELPABOUT END END
Файл определения модуля приложения MCIWNDC представлен в листинге 5.7.
Листинг 5.7. Файл mciwndc/mciwndc.def NAME MCIWNDC DESCRIPTION 'Приложение MCIWNDC, (C) 1994, Frolov A.V.' EXETYPE windows STUB 'winstub.exe' STACKSIZE 10240 HEAPSIZE 1024 CODE preload moveable discardable DATA preload moveable multiple
Для трансляции приложения в среде MS-DOS системой Microsoft C++ версии 7.0 или 8.0 (входящий в Visual C++ версии 1.0) вы можете использовать makefile, представленный в листинге 5.8.
Листинг 5.8. Файл mciwndc/makefile NAME = mciwndc OBJ = mciwndc.obj LIBS = libw slibcew commdlg vfw !if "$(DEBUG)" == "NO" DEF = CLOPT = MASMOPT = LINKOPT = !else DEF = -DDEBUG CLOPT = -Zid MASMOPT = -Zi LINKOPT = /CO/LI !endif CC = cl -c -W3 -AS -Zp -G2sw -Oxas $(DEF) $(CLOPT) -DWIN31 ASM = masm -Mx $(MASMOPT) LINK= link /NOE/NOD/LI/MAP/AL:16/ONERROR:NOEXE $(LINKOPT) RC = rc .c.obj: $(CC) $*.c .asm.obj: $(ASM) $*; goal: $(NAME).exe $(NAME).exe: $(OBJ) $(NAME).res $(NAME).def makefile $(LINK) $(OBJ), $(NAME), $(NAME),$(LIBS), $(NAME).def $(RC) -31 $(NAME).res -mapsym $(NAME).map $(NAME).res: $(NAME).rc $(RC) -r $(NAME).rc clean: del $(NAME).exe del *.res del *.obj del *.map del *.sym del *.pdb copy: copy $(NAME).exe ..\..\bin copy $(NAME).sym ..\..\bin depend: mv makefile makefile.old sed "/^# START Dependencies/,/^# END Dependencies/D" makefile.old > makefile del makefile.old echo # START Dependencies >> makefile includes -l *.c *.asm >> makefile echo # END Dependencies >> makefile
С помощью строки "Insert..." меню "File" вы можете вставить flc - или fli -файлы анимации в формате Autodesk Animation , подготовленные, например, с помощью таких программ, как 3D-Studio или Autodesk Animator. Для этого в списке "List Files of Type" диалоговой панели "Insert File" выберите строку "Autodesk Animation" и укажите нужный файл. Он будет преобразован в формат avi.
Для создания окна MCI проще всего воспользоваться функцией MCIWndCreate . Функция MCIWndCreate HWND MCIWndCreate( HWND hwndParent, // идентификатор родительского окна HINSTANCE hInstance, // идентификатор приложения DWORD dwStyle, // стиль окна LPSTR szFile); // имя устройства или путь к файлу
Параметры функции: hwndParent
Через этот параметр приложение передает функции идентификатор родительского окна, то есть окна, создавшего окно MCI. Если родительского окна нет, в качестве этого параметра можно указать NULL hInstance
Идентификатор приложения, полученных через параметры функции WinMain или LibMain (для DLL-библиотеки) dwStyle
Стиль создаваемого окна. Можно указывать стили, стандартные для функции CreateWindow, а также дополнительные, список которых приведен ниже. Если стандратные стили не указаны (что допустимо), то если есть родительское окно, используются стили WS_CHILD, WS_BORDER, иWS_VISIBLE. Если же параметр hwndParent указан как NULL, используются стили WS_OVERLAPPEDWINDOW и WS_VISIBLE. Для создания невидимого окна следует использовать один из стандартных стилей, например, WS_CHILD szFile
Указатель на текстовую строку, содержащую имя устройства (например, "cdaudio") или путь к файлу
Возвращаемое значение:
Идентификатор созданного окна при успешном завершении или NULL при ошибке
Привдем список дополнительных стилей, которые можно использовать при создании окна MCI.
Стиль | Описание |
MCIWNDF_NOAUTOSIZEWINDOW | Размер окна не изменяется при изменении размера изображения |
MCIWNDF_NOAUTOSIZEMOVIE | При изменении размеров окна не следует выполнять масштабирование изображения для полного заполнения внутренней области окна |
MCIWNDF_NOPLAYBAR | Если задан этот стиль, не отображается полоса просмотра |
MCIWNDF_NOMENU | Не отображается кнопка для доступа к меню |
MCIWNDF_RECORD | Отображается кнопка записи, в меню добавляется строка "New" |
MCIWNDF_NOERRORDLG | При возникновении ошибки на экран не выводится диалогоая панель с описанием этой ошибки. Приложение может получить описание самой последней возникшей ошибки при помощи функции MCIWndGetError |
MCIWNDF_NOTIFYMODE | При изменении режима родительское окно получит извещающее сообщение MCIWNDM_NOTIFYMODE |
MCIWNDF_NOTIFYPOS | При изменении текущей позиции приложение получит извещающее сообщение MCIWNDM_NOTIFYPOS |
MCIWNDF_NOTIFYMEDIA | При замене носителя данных (например, звукового компакт-диска) приложение получит извещающее сообщение MCIWNDM_NOTIFYMEDIA |
MCIWNDF_NOTIFYSIZE | Родительское окно получит извещающее сообщение MCIWNDM_NOTIFYSIZE при изменении размера окна MCI |
MCIWNDF_NOTIFYERROR | При возникновении ошибки родительское окно получит сообщение MCIWNDM_NOTIFYERROR |
MCIWNDF_NOTIFYALL | Окно MCI будет извещать родительское окно в случае возникновения любых событий |
MCIWNDF_SHOWNAME | В заголовке окна будет отображаться имя устройства или путь к файлу |
MCIWNDF_SHOWPOS | В заголовке окна будет отображаться текущая позиция |
MCIWNDF_SHOWMODE | В заголовке окна будет отображаться текущий режим работы |
MCIWNDF_SHOWALL | Будут использованы все возможности окна MCI (то есть все органы управления, отображение информации в заголовке и т. д.) |
Другой способ создания окна MCI заключается в регистрации класса окна MCIWND_WINDOW_CLASS функцией MCIWndRegisterClass , не имеющей парамеров, и создании на базе этого класса окна функцией CreateWindow . В случае успеха функция MCIWndRegisterClass возвращает значение FALSE.
Подготовьте несколько десятков или сотен (а может быть, тысяч?) bmp-файлов, содержащих отдельные кадры мультфильма. Имена файлов должны оканчиваться их порядковым номером, например, pic001.bmp, pic002.bmp, ..., pic867.bmp и т. д.. Разумеется, размеры и цветовое разрешение всех кадров должны быть одинаковые, а что же касается содержимого, тут можно полностью положиться на ваш вкус. Если кадры должны сменяться, например, десять раз в секунду, то для создания десятисекундного мультфильма вам нужно подготовить "всего" сто рисунков.
Запустите приложение VidEdit , которое поставляется в составе Video for Windows (рис.5.5).
Файлы avi имеют довольно сложную внутреннюю структуру и состоят из большого числа вложенных фрагментов. Структура avi-файла приведена в документации, которая поставляется вместе с Video for Windows Development Kit. Мы не будем ее описывать, так как в большинстве случаев вам не потребуется выполнять непосредственное чтение или запись avi-файлов. Все функции, необходимые для работы с avi-файлами, имеются в библиотеке avifile.dll.
Заметим, что в отличие от, например, wav-файла, avi-файл может содержать несколько потоков данных, обрабатываемых одновременно. Все данные хранятся в виде блоков (кадров), причем для обеспечения непрерывности воспроизведения звуковых данных последние чередуются с видеоданными. Как правило, для сокращения объема avi-файла используются различные методы компресии, поэтому звуковые данные и видеоданные обычно хранятся в сжатом виде. Таким образом, сложность внутренней структуры avi-файла сильно затрудняет работу с ним на низком уровне без использования функций библиотеки avifile.dll.
Функции, предназначенные для работы с avi- и wav-файлами, определенные в библиотеке avifile.dll, позволяют работать на уровне потоков данных и кадров. Вы можете получать информацию об avi-файле и о потоках данных, читать и писать потоки данных, получать отдельные кадры, причем при необходимости эти данные будут автоматически разжаты или сжаты. Есть средства для копирования потоков из разных файлов, позиционирования внутри потока, создания временных потоков в оперативной памяти. Вы можете скопировать весь avi-файл или любую его часть в Clipboard.
В распоряжении приложений есть функции GetOpenFileNamePreview и GetSaveFileNamePreview , аналогичные по своему назначению функциям GetOpenFileName и GetSaveFileName библиотеки commdlg.dll, но дополнительно обеспечивающие возможность предварительного просмотра avi-файлов или прослушивания wav-файлов. Мы используем функцию GetOpenFileNamePreview в приложении MCIWNDC, исходные тексты которого приведены в этой главе.
Если окно MCI больше не нужно, его можно удалить макрокомандой MCIWndDestroy . Идентификатор удаляемого окна MCI передается этой функции в качестве единственного параметра: #define MCIWndDestroy(hwnd) (VOID)MCIWndSM(hwnd, WM_CLOSE, 0, 0)
Макро MCIWndSM определяется как функция SendMessage (см. файл mciwnd.h, поставляемый вместе с Video for Windows Development Kit и включаемый в файл vfw.h).
Для того чтобы закрыть устройство, открытое ранее в окне MCI без удаления окна, используйте макрокоманду MCIWndClose, передав ей идентификатор окна.
Макрокоманда MCIWndPlay включает режим проигрывания для окна MCI, идентификатор которого передается ей в качестве единственного параметра.
Если вам нужно начать проигрывание с заданной позиции, воспользуйтесь макрокомандой MCIWndPlayFrom . Первый параметр этой макрокоманды задает идентификатор окна MCI, второй (размером в двойное слово) - позицию для начала проигрывания. Есть возможность задать конечную позицию. Макрокоманда MCIWndPlayFromTo , имеющая три параметра, аналогична макрокоманде MCIWndPlayFrom , но позволяет через третий параметр задать конечную позицию, при достижении которой проигрывание будет остановлено.
Вы даже можете запустить проигрывние в обратную сторону - от конца к началу файла (если драйвер устройства позволит вам это сделать). Достаточно вызвать макрокоманду MCIWndPlayReverse . Она имеет один параметр (идентификатор окна MCI) и запускает проигрывание от текущей позиции к началу файла.
Макрокоманда MCIWndSetRepeat позволяет включить режим циклического проигрывания. Через первый параметр этой макрокоманде передается идентификатор окна MCI, через второй для включение режима циклического проигрывания нужно передать значение TRUE.
Макрокоманды MCIWndStop и MCIWndPause предназначены для выполнения, соответственно, останова и временного останова проигрывания. Для того чтобы продолжить проигрывание после временного останова, используйте макрокоманду MCIWndResume . Все три макрокоманды имеют только один параметр - идентификатор окна MCI.
Для включения режима записи с текущей позиции предназначена макрокоманда MCIWndRecord . В качестве единственного параметра ей нужно передать идентификатор окна MCI. С помощью этой макрокоманды вы сможете организовать запись звуковых данных (как это сделано в нашем приложении MCIWNDC, которое мы рассмотрим чуть позже).
С помощью окна MCI вы не можете записывать avi-файлы, для этого предназначено окно класса AVICap.
Для сохранения записанных данных можно воспользоваться макрокомандами MCIWndSave или MCIWndSaveDialog .
Макрокоманда MCIWndSave имеет два параметра - идентификатор окна MCI и указатель на текстовую строку, в которой должен находиться путь к файлу. Записанные данные будут сохранены в этом файле.
При вызове макрокоманды MCIWndSaveDialog , имеющий один параметр (идентификатор окна MCI) на экран выводится диалоговая панель, позволяющая пользователю сохранить данные в файле. Это модифицированная диалоговая панель "Save As..." с возможностью предварительного просмотра или прослушивания содержимого файлов мультимедиа. Кстати, эту же панель вы можете вывести и отдельно с помощью функции GetSaveFileNaamePreview , аналогичной функции GetSaveFileName из библиотеки commdlg.dll.
При создании окна MCI вы можете указать имя устройства или файл мультимедиа, передав указатель на соответствующую текстовую строку через последний параметр функции MCIWndCreate. Можно использовать и другие способы.
Макрокоманда MCIWndOpen позволяет для созданного ранее окна открыть устройство или файл, например: MCIWndOpen(hwnd, "push.wav", MCIWNDOPENF_NEW);
Через первый параметр передается идентификатор окна MCI, через второй - указатель на строку, содержащую имя устройства или файла. В третьем параметре при создании нового файла нужно указать флаг MCIWNDOPENF_NEW .
Напомним, что закрыть устройство или файл можно с помощью макрокоманды MCIWndClose .
Функция MCIWndOpenDialog позволяет вывести на экран диалоговую панель, с помощью которой пользователь может выбрать файл и загрузить его в окно MCI. В качестве единственного параметра этой функции следует передать идентификатор окна MCI. Функция возвращает значение 0L (размером в двойное слово) в случае успеха или код ошибки.
Для выбора файла можно также использовать функцию GetOpenFileNamePreview , входящую в программный интерфейс Video for Windows и аналогичную функции GetOpenFileName из библиотеки commdlg.dll . Диалоговая панель, появляющаяся на экране при вызове этой функции, содержит окно для предварительного прослушивания или просмотра файла (рис. 5.15).
Новый файл создается макрокомандой MCIWndNew , которой в качестве первого параметра следует передать идентификатор окна MCI, а в качестве второго - указатель на текстовую строку, содержащей имя устройства. Пример использования этой макрокоманды ести в приложении MCIWNDC, которое мы скоро рассмотрим.
Для того чтобы создавать полноценные видеофрагменты, вам следует приобрести специальный видеоадаптер для ввода видеосигнала. В продаже есть два принципиально разных типа таких адаптеров. Простейшие видеоадаптеры, которые мы отнесем к первому типу, позволяют записывать лишь отдельные кадры. В некоторых случаях этого достаточно (например, вы сможете снять "пластилиновый" мультфильм, составив его из множества отдельных кадров). Видеоадаптеры второго типа способны записывать поток видеоинформации в реальном масштабе времени, причем одновременно выполняется компрессия данных.
Приобретая видеоадаптер поинтересуйтесь, сможете ли вы с помощью этого адаптера записывать видео в реальном масштабе времени с компрессией данных, или же вам будет доступна только запись отдельных кадров. Кроме того, очень важно, чтобы вместе с видеоадаптером поставлялся драйвер для Windows версии 3.1, способный работать вместе с Microsoft Video for Windows версии 1.1. Только тогда вы сможете без проблем записывать avi-файлы, подключив к видеоадаптеру лазерный проигрыватель видеодисков, видеокамеру или видеомагнитофон. В противном случае вам придется создавать avi-файл из отдельных кадров, что не всегда приемлимо и отнимает очень много времени.
Для создания avi-файла с помощью видеоадаптера вам следует использовать приложение VidCap , которое поставляется вместе с Video for Windows. Это приложение способно работать в трех режимах: в режиме покадровой записи, в автоматическом режиме и в автоматическом режиме с автоматическим же управлением лазерным проигрывателем видеодисков или видеомагнитофоном.
Первый режим удобен в тех случаях, когда ваш видеоадаптер не способен записывать видео в реальном масштабе времени или когда вам требуется записать только отдельные кадры видео.
Второй режим удобен для записи видеофильмов непосредственно в avi-файл. Учтите, что размер созданного файла может достигать в зависимости от продолжительности записи и метода компрессии десятков и сотен мегабайт, поэтому подготовьте быстродействующий диск соответствующего размера. Важное значение имеет также производительность процессора, поэтому компьютер с процессором i386 едва ли подойдет для записи видео в реальном масштабе времени.
Третий режим доступен в том случае, если источник видеосигнала (лазерный проигрыватель или видеомагнитофон) имеет возможность дистанционного управления от компьютера с использованием интерфейса MCI. В этом режиме приложение VidCap способно управлять устройством и позиционировать носитель данных.
Если вас по каким-либо причинам не устраивают возможности приложения VidCap, вы можете создать собственное при помощи Video for Windows Development Kit на базе окна класса AVICap . Примеры приложений, выполняющих запись видео (которые называются Cap Test и CapCPP ), поставляются с исходными текстами в составе Video for Windows Development Kit.
В состав Video for Windows входит приложение Screen Capture , с помощью которого вы можете создавать демонстрационные и рекламные ролики, записывая в avi-файл изображение любой области экрана.
Запустите приложение Screen Capture. Оно появится на экране в виде пиктограммы. Установите на эту пиктограмму курсор и сделайте щелчок левой клавишей мыши. Появится меню (рис. 5.8).