Подсистема сжатия звука в Windows

Евгений Музыченко

Введение

Основные принципы работы подсистемы сжатия

     Драйверы, преобразователи, кодеки, фильтры

     Постоянные и временные драйверы

     Глобальные и локальные драйверы

     Приоритет поиска драйвера

     Аппаратная поддержка драйверов

     Синхронные и асинхронные драйверы

     Уведомление приложений о выполнении операций

     Типы фильтров и форматов

     Стандартные фильтры и форматы

     Порции и буферы преобразуемых данных

     Потоки преобразования

     Независимые участки в потоках

     Ключи объектов

     Версии ACM и драйверов

     Пресеты

Программирование ACM

     Типовые схемы применения средств ACM

          Запрос сведений о заданном фильтре или формате

          Перебор доступных типов и стандартных фильтров/форматов

          Выбор фильтра/формата при помощи стандартного диалога

          Выбор наиболее подходящего формата

          Обработка потока данных

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

     Типы и структуры, используемые в ACM

          Структура WAVEFORMATEX

          Структура WAVEFILTER

          Структура ACMDRIVERDETAILS

          Структуры ACMFILTERTAGDETAILS / ACMFORMATTAGDETAILS

          Структуры ACMFILTERDETAILS/ACMFORMATDETAILS

          Структуры ACMFILTERCHOOSE и ACMFORMATCHOOSE

          Структура ACMSTREAMHEADER

    Функции ACM

          Классы функций интерфейса ACM

          Информационные функции

          Функции работы с драйверами

          Функции работы с фильтрами

          Функции работы с форматами

          Функции работы с потоками

          Функции, определяемые приложением

          Возвращаемые значения

     Информационные функции

          acmGetVersion — запрос версии ACM

          acmMetrics — запрос параметров компонентов ACM

     Функции работы с драйверами

          acmDriverAdd — добавление нового драйвера

          acmDriverRemove — удаление установленного драйвера

          acmDriverEnum — перебор установленных драйверов

          acmDriverID — запрос идентификатора драйвера

          acmDriverOpen — открывание драйвера

          acmDriverClose — закрывание открытого драйвера

          acmDriverMessage — передача сообщения драйверу

          acmDriverPriority — изменение приоритета драйвера

          acmDriverDetails — запрос описания драйвера

     Функции работы с фильтрами и форматами

          acmFilterTagDetails / acmFormatTagDetails — запрос описания типа

          acmFilterDetails / acmFormatDetails — запрос параметров фильтра/формата

     Функции перебора типов и стандартных фильтров/форматов

          acmFilterChoose/acmFormatChoose — вывод диалога выбора фильтра/формата

          acmFormatSuggest — запрос рекомендуемого для преобразования формата

     Функции работы с потоками преобразования

          acmStreamOpen — открывание потока преобразования

          acmStreamClose — закрытие потока

          acmStreamSize — запрос рекомендуемого размера порции преобразования

          acmStreamPrepareHeader — подготовка заголовка к преобразованию

          acmStreamUnprepareHeader — отмена действий по подготовке заголовка

          acmStreamConvert — запрос преобразования очередной порции звуковых данных

          acmStreamReset — прерывание обработки потока

          acmStreamMessage — посылка сообщения драйверу потока

     Функции, определяемые приложением

          DriverEnumCallback — функция поддержки перебора драйверов

     Функции поддержки перебора типов и стандартных фильтров/форматов

     Функция перехвата сообщений диалога выбора фильтра/формата

     Функция уведомления приложения о завершении операции с потоком

     DriverProc — функция пользовательского драйвера ACM

Существующие драйверы подсистемы сжатия

Установка и удаление постоянных драйверов ACM

Использование драйвера фильтров MSFilter

     Фильтр Volume

     Фильтр Echo

Недостатки подсистемы сжатия

Пример программы, использующей ACM

Введение

Подсистема сжатия звука (Audio Compression Manager — ACM, диспетчер сжатия звука) первоначально была введена в расширении Video For Windows (VFW) для Windows 3.x, вместе с подсистемой сжатия изображения (Video Compression Manager — VCM). Целью введения этих подсистем было создание удобного, универсального и гибкого интерфейса для работы со звуковыми и видеопотоками. Позднее ACM и VCM были включены в состав стандартной звуковой подсистемы для платформ Win32. Таким образом, для работы с ACM необходима либо платформа Windows 3.x с расширением VFW, либо платформа Win32.

Подсистема сжатия звука предоставляет приложениям набор сервисных средств для преобразования звуковых форматов и других видов обработки звуковых данных. Она реализована в виде самого диспетчера ACM и набора так называемых драйверов ACM — независимо подключаемых программ, обеспечивающих собственно обработку звука. Приложения непосредственно взаимодействуют только с диспетчером, который выбирает нужные драйверы, передает информацию между приложением и драйверами и выполняет прочие функции по координации работы подсистемы.

В отличие от базовой звуковой подсистемы (MME/Wave), подсистема сжатия в Win32 выполнена полностью 32-разрядной и не содержит внутренних переходов между 32- и 16-разрядным кодом. Некоторые драйверы существуют и в 16-разрядных вариантах, обеспечивая сервис ACM для приложений Win16.

Подсистема сжатия тесно связана со службой переназначения (Wave Mapper) звуковой подсистемы. При открывании Wave–устройства может быть задан режим прозрачного преобразования форматов, при котором Wave Mapper при помощи ACM находит подходящее сочетание звукового устройства и кодека, обеспечивающее ввод или вывод звука в запрошенном формате. При этом приложение может считать, что запрошенный формат поддерживается непосредственно звуковым адаптером.

В начало

В начало

Основные принципы работы подсистемы сжатия

По структуре и принципу работы подсистема ACM очень похожа на базовую звуковую подсистему MME/Wave, описанную в статье «Низкоуровневое программирование звука в Windows». Остановимся лишь на основных особенностях и отличиях подсистемы сжатия.

Драйверы, преобразователи, кодеки, фильтры

В ACM существует два вида обработки звука:

  • Преобразование формата — изменение способа представления звуковых данных, перекодировка их из одного представления в другое без изменения общих свойств самого звука.
  • Фильтрование — обработка звука в потоке (усиление/ослабление, изменение АЧХ, наложение звуковых эффектов и т.п.) без изменения формата.

Модули драйверов ACM, реализующие функции преобразования форматов, называют преобразователями формата (format convertors). Модули, реализующие функции фильтрования, называются фильтрами (filters). Один и тот же подключаемый драйвер может совмещать в себе различные функции, а также содержать более одного преобразователя или фильтра.

Преобразование форматов, при котором меняется тип (tag) формата, обычно сопровождается изменением объема звуковых данных. Такие виды преобразования называются сжатием (compression) или восстановлением (decompression). Сжатию обычно подвергаются данные в формате PCM, а при восстановлении формат PCM обычно имеет результат операции. Преобразователи формата, реализующие сжатие/восстановление, называются кодеками (codec — coder/decoder или compressor/decompressor).

В начало

В начало

Постоянные и временные драйверы

Драйверы ACM делятся на постоянные и временные. Постоянные драйверы устанавливаются один раз, присутствуют в системе вплоть до явного удаления, и доступны всем приложениям системы. Временные драйверы устанавливаются приложениями для своих собственных целей, существуют до завершения работы приложения и доступны только установившим их приложениям.

Разрешенные и запрещенные драйверы

По умолчанию все драйверы ACM разрешены для использования. Однако служба ACM по требованию пользователя или приложения может запретить включение в работу отдельных драйверов. Например, таким образом можно предотвратить автоматическое подключение неэффективного драйвера, когда имеется более подходящий, или временно исключить из работы драйвер, содержащий ошибки. Для запрещенного драйвера можно только узнать его параметры; все остальные операции с драйвером невозможны до тех пор, пока он не будет снова разрешен для работы.

В начало

В начало

Глобальные и локальные драйверы

Первоначально, на платформе Windows 3.x, драйверы подразделялись на глобальные и локальные. Глобальный драйвер был доступен всем приложениям Windows, локальный — только установившему его приложению. Соответственно все постоянные драйверы являлись глобальными.

В Win32 поведение системы было изменено — теперь всем приложениям доступны только постоянные драйверы, а атрибут «локальный» или «глобальный» используется для определения приоритета при автоматическом поиске драйвера.

В начало

В начало

Приоритет поиска драйвера

Приложение может обратиться к драйверу не только прямо, указывая его уникальный идентификатор в службе ACM, но и косвенно, указывая лишь требуемые параметры фильтра или формата. В последнем случае ACM самостоятельно пытается подобрать подходящий драйвер, просматривая список всех разрешенных драйверов в порядке убывания приоритета. Локальные драйверы имеют наивысший приоритет; глобальные и постоянные драйверы имеют более низкие приоритеты, которые могут быть явно изменены пользователем или приложением.

В начало

В начало

Аппаратная поддержка драйверов

Большинство драйверов ACM являются программными — они используют для своей работы только ресурсы центрального процессора и не нуждаются в каких-либо дополнительных аппаратных средствах. Для успешной работы программного драйвера необходим лишь достаточно мощный центральный процессор и необходимое количество основной памяти.

При наличии в системе DSP (Digital Signal Processor — цифровой сигнальный процессор), который может обрабатывать звук практически без участия центрального процессора, для него может быть разработан драйвер ACM, выполняющий обработку звука средствами этого DSP. Сам DSP при этом может быть встроен в системную плату или находиться на одной из плат расширения. В этом случае говорят, что драйвер ACM имеет аппаратную поддержку.

Некоторые звуковые устройства поддерживают аппаратное преобразование форматов в реальном времени при вводе-выводе звука — например, они могут выдавать записываемый звук сразу в формате ADPCM, сжимая его «на ходу» при помощи встроенного DSP. Несмотря на то что такие устройства бесполезны для полнофункционального драйвера ACM и полностью поддерживаются базовой звуковой подсистемой MME/Wave, ACM предоставляет некоторые удобства в отношении и таких устройств. ACM содержит средства поиска и выбора форматов по различным критериям, и одним из таких критериев является аппаратная поддержка формата одним из звуковых адаптеров — при вводе-выводе.

Поскольку формально подсистемы MME/Wave и ACM никак не связаны между собой, для определения аппаратно поддерживаемых форматов такой звуковой адаптер должен быть снабжен упрощенным драйвером ACM, который и будет выделять поддерживаемые адаптером форматы из общего списка, а также возвращать приложению идентификатор звукового устройства, к которому следует обратиться. А если звуковой адаптер поддерживает обработку звука независимо от его записи/воспроизведения, то драйвер ACM может быть и полнофункциональным. В последнем случае ресурсы аппаратуры разделяются между подсистемами MME/Wave и ACM.

В начало

В начало

Синхронные и асинхронные драйверы

Как и драйверы звуковых адаптеров, драйверы ACM также могут быть синхронными и асинхронными. Практически все программные драйверы являются синхронными; драйверы с аппаратной поддержкой обычно делаются асинхронными. Для асинхронных драйверов предусмотрена очередь входных заданий и механизм уведомления приложения о завершении ранее запрошенных операций; синхронные драйверы не возвращают приложению управления до тех пор, пока не будет завершена запрошенная операция.

В начало

В начало

Уведомление приложений о выполнении операций

ACM поддерживает два вида уведомления приложения: о выполнении запрошенных операций над потоком преобразования и об изменении приоритетов и состояний глобальных драйверов ACM.

Механизм уведомления о выполнении операций над потоками полностью аналогичен базовой звуковой подсистеме MME/Wave, за одним исключением: по непонятной причине не поддерживаются сообщения задаче (thread). Таким образом, для уведомления может быть либо активизирован объект события (event), либо вызвана функция приложения, либо отправлено сообщение одному из окон приложения. Приложение уведомляется о наступлении каждого из трех событий потока: успешное завершение функций открывания и закрывания потока, завершение операции преобразования. Вид уведомления задается при открывании потока функцией acmStreamOpen.

Для уведомления об изменении приоритетов и состояний драйверов заданному окну приложения посылается заданное сообщение Windows. Окно и сообщение задаются подобно установке нового драйвера — функцией acmDriverAdd. Окно, получающее такие сообщения, называется окном уведомления (notification window).

В начало

В начало

Типы фильтров и форматов

Основной характеристикой фильтра или формата является его тип — способ обработки данных в фильтре (эхо, усиление/ослабление) или способ представления данных в формате (PCM, ADPCM, MPEG и т.п.).

Конкретные форматы и фильтры внутри каждого типа отличаются только параметрами: частотой дискретизации, разрядностью отсчета, тонкостями кодирования — для форматов, степенью усиления/ослабления сигнала, величиной задержки — для фильтров. Основные же характеристики — способ представления и вид обработки — в пределах одного типа остаются неизменными.

Каждому типу фильтров и форматов присвоен свой уникальный код (tag), который однозначно идентифицирует его в подсистеме сжатия. Коды типов имеют неизменные числовые значения и для обеспечения уникальности должны быть зарегистрированы в Microsoft. Наряду с кодами типов ACM использует также индексы (внутренние номера) типов фильтров/форматов, поддерживаемых каждым из драйверов. Индексы не имеют с кодами ничего общего: они отражают лишь порядковые номера фильтров/форматов различного типа в служебных списках драйвера. При помощи индексов удобно последовательно перебирать все типы фильтров/форматов, поддерживаемые заданным драйвером.

В начало

В начало

Стандартные фильтры и форматы

Внутри каждого типа фильтров/форматов драйвером выбирается несколько стандартных, наиболее употребительных вариантов, которым также присвоены индексы. Сочетание кода типа и индекса стандартного фильтра/формата является однозначным и определяет конкретный фильтр или формат ACM в пределах хотя бы одной версии соответствующего драйвера.

Однако количество допустимых фильтров или форматов любого типа не ограничивается списком стандартных; остальные могут быть получены изменением второстепенных параметров (частоты дискретизации, разрядности отсчета, количества каналов, громкости, задержки и т.п.). Стандартные фильтры/форматы являются всего лишь фиксированными сочетаниями различных параметров фильтра/формата внутри каждого типа.

В начало

В начало

Порции и буферы преобразуемых данных

Преобразование данных в ACM производится порциями. Порция потока преобразования обычно имеет размер от нескольких десятков байт до сотен килобайт, в зависимости от структуры звукового формата и динамики преобразования. За каждую операцию преобразования обрабатывается одна порция данных.

Для каждого потока преобразования создаются два буфера: входной — для порции исходных данных, и выходной — для порции данных результата. Размер преобразуемой порции не может превышать выбранного размера буфера.

В начало

В начало

Потоки преобразования

Как и основная звуковая подсистема MME/Wave, ACM обрабатывает звуковые данные потоками. Это означает, что приложение не может обрабатывать звуковые данные в произвольной последовательности, а делает это только последовательно, от начала к концу потока. Такое ограничение связано с тем, что как преобразование форматов, так и фильтрование может потребовать информации о предшествовании — например, относительное кодирование амплитуд в формате ADPCM или формирование эффекта эха в фильтре Echo. Поэтому обработка звукового потока в ACM включает в себя три стадии:

  • Создание, или открытие потока (acmStreamOpen). При этом приложение сообщает ACM параметры потока форматы, режимы обработки, способы уведомления) и получает от ACM ключ открытого потока.
  • Обработка потока (acmStreamConvert). На этом этапе приложение последовательно передает ACM буферы обмена, содержащие порции преобразуемых звуковых данных. ACM передает буферы выбранному драйверу для обработки, а после завершения обработки каждый буфер возвращается приложению. Обработка потока может происходить в реальном времени, если аппаратура компьютера успевает выполнять ее достаточно быстро.
  • Уничтожение, или закрытие потока (acmStreamClose). Последняя операция с потоком, после которой поток перестает существовать.

Поток преобразования ACM фактически состоит из двух звуковых потоков — исходного (source) и результирующего (destination). Данные исходного потока существуют до начала обработки и не изменяются после ее завершения; данные результирующего потока создаются в процессе обработки.

В начало

В начало

Независимые участки в потоках

Поток преобразования может состоять из нескольких независимых участков. Это означает, что нет необходимости создавать несколько потоков преобразования для однотипной обработки нескольких различных звуковых фрагментов одного формата, не связанных между собой. Вместо этого можно сообщить ACM, где начинается и кончается каждый независимый участок, чтобы драйвер мог корректно инициализировать внутренние переменные в начале участка и вернуть приложению накопленные или задержанные по какой-либо причине выходные данные в конце участка.

В начало

В начало

Ключи объектов

Как и в остальных подсистемах Windows, объекты ACM, с которыми работает приложение, идентифицируются специальными ключами, которые ACM возвращает приложению в ответ на запрос доступа к объекту. В ACM имеется три вида объектов:

  • Идентификатор драйвера (driver id). Используется для указания установленного драйвера в ACM, например при запросе параметров драйвера. Каких-либо специальных операций перед использованием идентификатора не требуется.
  • Выбранный для работы драйвер (driver). Возвращается ACM при открытии драйвера и используется для ссылок к подмножеству открытых для работы драйверов.
  • Поток (stream). Возвращается ACM при открытии потока и используется для операций с потоком.

Каждый из объектов имеет свой тип ключа — HACMDRIVERID, HACMDRIVER, HACMSTREAM. Кроме того, имеется универсальный тип HACMOBJ, предназначенный для использования в функциях, работающих с объектами различного типа.

В начало

В начало

Версии ACM и драйверов

Номера версий, используемые в ACM, имеют тип DWORD и состоят из трех компонентов:

  • старший (major) номер — в старшем байте старшего слова;
  • младший (minor) номер — в младшем байте старшего слова;
  • номер выпуска (build) — в младшем слове.

Для разбора полученного двойного слова удобно использовать стандартные макросы Windows:

DWORD x = acmGetVersion ();
Major = HIBYTE (HIWORD (x));
Minor = LOBYTE (HIWORD (x));
Build = LOWORD (x);

Пресеты

ACM позволяет присваивать отдельным стандартным фильтрам/форматам произвольные пользовательские названия (пресеты), которые затем сохраняются в базе данных ACM в виде отдельного списка. Диалог выбора фильтра/формата, выводимый функциями выбора, в верхней своей части содержит список пресетов, из которого можно быстро выбрать требуемый.

В начало

В начало

Программирование ACM

Для программирования ACM необходим любой стандартный Win32 SDK, содержащий файлы заголовков MMSYSTEM.H, MSACM.H, MMREG.H и библиотек WINMM.LIB, MSACM32.LIB. Такой SDK имеется в составе всех известных компиляторов, поддерживающих платформу Win32.

Типовые схемы применения средств ACM

Запрос сведений о заданном фильтре или формате

Для имеющегося описателя фильтра или описателя формата выполняются функции acmFilterTagDetails, acmFilterDetails или acmFormatTagDetails, acmFormatDetails, возвращающие сведения либо о типе, к которому принадлежит указанный фильтр/формат, либо о самом фильтре/формате. В частности, полученные сведения могут использоваться для вывода информации пользователю.

В начало

В начало

Перебор доступных типов и стандартных фильтров/форматов

Для имеющегося набора условий, которым должен удовлетворять искомый тип или стандартный фильтр/формат, выполняются функции перебора фильтров/форматов — acmFilterTagEnum, acmFilterEnum, acmFormatTagEnum, acmFormatEnum. В результате для каждого подходящего типа или для каждого подходящего стандартного фильтра/формата вызывается соответствующая функция поддержки перебора. В результате поиск может быть прерван при обнаружении подходящего объекта или может быть составлен список объектов, который затем предлагается пользователю для ручного выбора.

В начало

В начало

Выбор фильтра/формата при помощи стандартного диалога

Для имеющегося набора условий, которым должен удовлетворять искомый тип или стандартный фильтр/формат, формируется структура ACMFILTERCHOOSE / ACMFORMATCHOOSE и выполняется функция выбора acmFilterChoose / acmFormatChoose. В результате ACM выводит пользователю стандартный диалог, содержащий списки подходящих типов и стандартных фильтров/форматов. После выбора пользователем нужного фильтра/формата ACM возвращает его описатель и дополнительные сведения.

В начало

В начало

Выбор наиболее подходящего формата

В том случае, когда имеется сжатый формат, который должен быть восстановлен в формат PCM, приложение может воспользоваться функцией acmFormatSuggest. Эта функция подберет наиболее подходящий формат типа PCM, в который следует восстановить исходный сжатый формат.

В начало

В начало

Обработка потока данных

Для выполнения необходимой обработки исходного потока данных приложение создает поток преобразования при помощи функции acmStreamOpen. При создании потока преобразования указываются исходный и результирующий форматы либо фильтр, которым должен быть обработан исходный поток. Затем приложение выполняет серию операций преобразования, вызывая функцию acmStreamConvert, каждый вызов которой преобразует очередную порцию исходных данных, порождая в результате порцию результирующих данных.

Исходный звуковой поток может быть взят из файла или получен в реальном времени — от любого звукового устройства, по сети или другим путем. Результирующий поток также может быть записан в файл, выведен в реальном времени на звуковое устройство, передан по сети и т.п.

В начало

В начало

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

При наличии звукового потока в заданном сжатом формате приложение может выполнить поиск звукового устройства, аппаратно поддерживающего ввод-вывод в таком формате. Для этого вначале при помощи функции acmFormatEnum выполняется перебор форматов, эквивалентных заданному, а в слове флагов перебора устанавливается HARDWARE. В результате, при успешном поиске, будет обнаружен драйвер «знающий» о существовании звукового устройства с аппаратной поддержкой заданного формата, в слове режимов и возможностей которого будет установлен флаг HARDWARE. Опросив этот драйвер функцией acmMetrics с параметрами HARDWARE_WAVE_INPUT или HARDWARE_WAVE_OUTPUT, можно получить идентификатор звукового устройства, по которому оно может быть открыто функциями waveInOpen или waveOutOpen.

В начало

В начало

Типы и структуры, используемые в ACM

Большинство структур имеет в своем составе поле cbStruct, в которое приложение должно занести размер области памяти, где размещена структура. Интерфейсные функции используют это поле двояким образом. Когда информация из структуры является исходной, поле показывает, какой ее объем реально присутствует в указанной области памяти; когда функция заполняет поля структуры возвращаемой информацией поле cbStruct ограничивает размер заполняемой области. В зависимости от выбранной функции и режимов ее работы существуют различные ограничения размера области памяти: она может включать либо только часть полей описанной структуры, либо всю структуру целиком, либо иметь резервную область непосредственно за концом структуры. В последнем случае резервная область может использоваться для дополнительных данных, не вошедших в основные поля описанной структуры.

Когда ACM заполняет структуру, содержащую поле cbStruct, в него заносится реальный размер возвращенной информации. Если какие-то поля структуры являются необязательными, приложение может определить, какая часть структуры была заполнена ACM.

При обращении к ACM вместе со структурой часто передается сопровождающий набор флагов, показывающих, какие из полей структуры несут осмысленную информацию. Несмотря на то что такие поля анализируются лишь при наличии соответствующих флагов, многие функции являются «привередливыми» и требуют, чтобы неиспользуемые входные поля имели нулевые значения. Чтобы гарантировать успешную работу функций, необходимо перед обращением к ним либо обнулить все неиспользуемые входные поля, либо обнулить всю структуру до заполнения ее полей осмысленной информацией.

Тип FOURCC

Описывает коды, используемые в формате RIFF (Resource Interchange File Format — формат файлов обмена ресурсами). Файлы формата RIFF широко используются для представления звуковых и видеоданных (расширения WAV, AVI, ANI, RMI, SBK и т.п.) и Windows предоставляет для работы с ними специальный интерфейс MMIO (MultiMedia Input/Output — мультимедийный ввод-вывод). В MMIO определены стандартные коды RIFF, которые используются для идентификации драйверов ACM.

Тип FOURCC (Four-Character Code — четырехсимвольный код) представляет собой двойное слово (DWORD), содержащее слово из 1..4 ASCII–символов — «RIFF», «wave», «fmt» и т.п. Слова короче четырех символов дополняются пробелами справа.

Порядок символов в двоичном представлении типа FOURCC тот же, что и в файле: первый символ представляется младшим байтом, а последний — старшим. Поэтому простое присваивание символьной константы (например, 'fmt ') даст обратное расположение байтов в двойном слове. Для корректного формирования значения можно использовать макросы MAKEFOURCC и mmioFOURCC.

В начало

В начало

Структура WAVEFORMATEX

Полностью описывает параметры формата. Описание структуры приведено в предыдущей статье 1 — «Низкоуровневое программирование звука в Windows».

В начало

В начало

Структура WAVEFILTER

Полностью описывает параметры фильтра.

DWORD  cbStruct;
DWORD  dwFilterTag;
DWORD  fdwFilter;
DWORD  dwReserved [5];
  • cbStruct — размер области памяти, занимаемой структурой.
  • dwFilterTag — код типа фильтра.
  • fdwFilter — флаги параметров и режимов работы фильтра. На данный момент флаги для этого поля пока не определены.
  • dwReserved — служебные поля ACM и драйвера.
В начало

В начало

Структура ACMDRIVERDETAILS

Описывает параметры и свойства драйвера ACM. Кроме cbStruct, поля структуры заполняются ACM.

DWORD  cbStruct;
FOURCC  fccType;
FOURCC  fccComp;
WORD  wMid;
WORD  wPid;
DWORD  vdwACM;
DWORD  vdwDriver;
DWORD  fdwSupport;
DWORD  cFormatTags;
DWORD  cFilterTags;
HICON  hicon;
char  szShortName [ACMDRIVERDETAILS_SHORTNAME_CHARS];
char  szLongName [ACMDRIVERDETAILS_LONGNAME_CHARS];
char  szCopyright [ACMDRIVERDETAILS_COPYRIGHT_CHARS];
char  szLicensing [ACMDRIVERDETAILS_LICENSING_CHARS];
char  szFeatures [ACMDRIVERDETAILS_FEATURES_CHARS];
  • cbStruct — размер области памяти, занимаемой структурой.
  • fccType — тип драйвера в формате FOURCC. Для драйверов ACM это поле имеет значение ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC (строка "audc").
  • fccComp — подтип драйвера в формате FOURCC. Это поле обычно имеет значение ACMDRIVERDETAILS_FCCCOMP_UNDEFINED (нуль).
  • wMid, wPid — идентификаторы производителя (Manufacturer) и продукта (Product). Константы, представляющие коды известных производителей и продуктов, определены в файле MMREG.H.
  • vdwACM, vdwDriver — версии службы ACM, для которой создан драйвер, и самого драйвера.
  • fdwSupport — флаги поддерживаемых драйвером возможностей и режимов. Имена констант для флагов имеют префикс ACMDRIVERDETAILS_SUPPORTF_:

CONVERTER

Драйвер содержит преобразователи формата

CODEC

Драйвер содержит кодеки

FILTER

Драйвер содержит фильтры

DISABLED

Драйвер запрещен

ASYNC

Драйвер является асинхронным

HARDWARE

Драйвер связан со звуковым адаптером, аппаратно поддерживающим ввод-вывод звука в сжатом формате. Для получения идентификатора звукового устройства необходимо использовать функцию acmMetrics

LOCAL

Драйвер является локальным

  • cFormatTags — количество различных типов форматов (способов представления данных), поддерживаемых драйвером
  • cFilterTags — количество различных типов фильтров (способов обработки звука), поддерживаемых драйвером
  • hicon — ключ иконки (пиктограммы) драйвера либо NULL при отсутствии пиктограммы
  • szShortName — короткое (сокращенное) название драйвера
  • szLongName — длинное (полное) название драйвера
  • szCopyright — строка информации об авторских правах
  • szLicensing — строка информации об условиях использования драйвера
  • szFeatures — строка информации о возможностях драйвера.
В начало

В начало

Структуры ACMFILTERTAGDETAILS / ACMFORMATTAGDETAILS

Описывают параметры типа фильтров/форматов и различаются только именами полей. Поля структур заполняются ACM, если не оговорено иное.

Структура ACMFILTERTAGDETAILS:

DWORD  cbStruct; 
DWORD  dwFilterTagIndex; 
DWORD  dwFilterTag; 
DWORD  cbFilterSize; 
DWORD  fdwSupport; 
DWORD  cStandardFilters; 
char  szFilterTag [ACMFILTERTAGDETAILS_FILTERTAG_CHARS]; 

Структура ACMFFORMATTAGDETAILS:

DWORD  cbStruct;
DWORD  dwFormatTagIndex;
DWORD  dwFormatTag;
DWORD  cbFormatSize;
DWORD  fdwSupport;
DWORD  cStandardFormats;
char  szFormatTag [ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
  • cbStruct — размер области памяти, занимаемой структурой.
  • dwFilterTagIndex / dwFormatTagIndex — индекс (внутренний номер) данного типа внутри драйвера. Кроме случаев запроса описания по индексу, поле должно быть нулевым; ACM всегда возвращает в этом поле нулевое значение.
  • dwFilterTag / dwFormatTag — уникальный код типа. Устанавливается приложением для тех случаев, когда запрос делается по коду типа. После успешного выполнения запроса всегда устанавливается ACM.
  • cbFilterSize / cbFormatSize — размер области памяти, достаточный для размещения расширенной структуры WAVEFILTER / WAVEFORMATEX, описывающей любой из фильтров/форматов данного типа.
  • fdwSupport — флаги поддерживаемых возможностей и режимов драйвера этого типа фильтров/форматов.
  • cStandardFilters / cStandardFormats — количество стандартных фильтров/форматов данного типа, поддерживаемых драйвером.
  • szFilterTag / szFormatTag — текстовое название типа.
В начало

В начало

Структуры ACMFILTERDETAILS/ACMFORMATDETAILS

Описывают параметры конкретного фильтра/формата и различаются только именами полей:

Структура ACMFILTERDETAILS:

DWORD  cbStruct; 
DWORD  dwFilterIndex; 
DWORD  dwFilterTag; 
DWORD  fdwSupport; 
LPWAVEFILTER  pwfltr; 
DWORD  cbwfltr; 
char  szFilter [ACMFILTERDETAILS_FILTER_CHARS]; 

Структура ACMFORMATDETAILS:

DWORD  cbStruct;
DWORD  dwFormatIndex;
DWORD  dwFormatTag;
DWORD  fdwSupport;
LPWAVEFORMATEX  pwfx;
DWORD  cbwfx;
char  szFormat [ACMFORMATDETAILS_FORMAT_CHARS];
  • cbStruct — размер области памяти, занимаемой структурой.
  • dwFilterIndex / dwFormatIndex — индекс (внутренний номер) стандартного фильтра/формата внутри драйвера. В отличие от индексов типов, индексы стандартных фильтров/форматов однозначно определяют конкретные стандартные фильтры и форматы в пределах хотя бы одной версии драйвера. Кроме случаев запроса описания по индексу, поле должно быть нулевым; ACM всегда возвращает в этом поле нулевое значение.
  • dwFilterTag / dwFormatTag — код типа, которому принадлежит фильтр/формат. Устанавливается приложением для тех случаев, когда запрос делается по коду типа. После успешного выполнения запроса всегда устанавливается ACM.
  • fdwSupport — флаги поддерживаемых возможностей и режимов драйвера этого типа форматов.
  • pwfltr / pwfx — указатель структуры WAVEFILTER / WAVEFORMATEX, которую при запросе описания фильтра/формата ACM заполняет его параметрами.
  • cbwfltr / cbwfx — размер области памяти, в которой размещена структура WAVEFILTER / WAVEFORMATEX.
  • szFilter / szFormat — текстовое название стандартного фильтра/формата внутри его типа. Вместе с полем szFilterTag / szFormatTag структуры ACMFILTERTAGDETAILS / ACMFORMATTAGDETAILS образует уникальное текстовое название фильтра/формата внутри всей подсистемы ACM.
В начало

В начало

Структуры ACMFILTERCHOOSE и ACMFORMATCHOOSE

Эти две очень похожие структуры описывают наборы данных, необходимые для вывода пользователю диалога, содержащего меню всех доступных или подходящих стандартных фильтров/форматов. Используются функциями acmFilterChoose и acmFormatChoose.

Структура ACMFILTERCHOOSE:

DWORD  cbStruct;
DWORD  fdwStyle;
HWND  hwndOwner;
LPWAVEFILTER  pwfltr;
DWORD  cbwfltr;
LPCSTR  pszTitle;
char  szFilterTag [ACMFILTERTAGDETAILS_FILTERTAG_CHARS];
char  szFilter [ACMFILTERDETAILS_FILTER_CHARS];
LPSTR  pszName;
DWORD  cchName;
DWORD  fdwEnum;
LPWAVEFILTER  pwfltrEnum;
HINSTANCE  hInstance;
LPCSTR  pszTemplateName;
LPARAM  lCustData;
ACMFILTERCHOOSEHOOKPROC  pfnHook;

Структура ACMFORMATCHOOSE:

DWORD  cbStruct;
DWORD  fdwStyle;
HWND  hwndOwner;
LPWAVEFORMATEX  pwfx;
DWORD  cbwfx;
LPCSTR  pszTitle;
char  szFormatTag [ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
char  szFormat [ACMFORMATDETAILS_FORMAT_CHARS];
LPSTR  pszName;
DWORD  cchName;
DWORD  fdwEnum;
LPWAVEFORMATEX  pwfxEnum;
HINSTANCE  hInstance;
LPCSTR  pszTemplateName;
LPARAM  lCustData;
ACMFORMATCHOOSEHOOKPROC  pfnHook;
  • cbStruct — размер области памяти, занимаемой структурой.
  • fdwStyle — флаги стилей построения диалога. Имена констант флагов выбора фильтра имеют префикс ACMFILTERCHOOSE_STYLEF_, имена констант флагов выбора формата — ACMFORMATCHOOSE_STYLEF_:

CONTEXTHELP

В диалоге будет доступна контекстно-зависимая помощь. При запросе пользователем помощи ACM будет посылать окну-владельцу сообщения с кодами ACMHELPMSGCONTEXTMENU и ACMHELPMSGCONTEXTHELP, параметры wParam и lParam которых будут скопированы из исходных сообщений WM_CONTEXTMENU или WM_CONTEXTHELP. Коды сообщений ACM предварительно должны быть зарегистрированы в Windows посредством функции RegisterWindowMessage

ENABLEHOOK

Разрешает использование функции перехвата сообщений Windows, заданной полем pfnHook

ENABLETEMPLATE

Диалог будет создан из шаблона (template), описываемого полями hInstance и pszTemplateName

ENABLETEMPLATEHANDLE

Поле hInstance содержит ключ уже загруженного в память шаблона диалога. В этом случае поле pszTemplateName игнорируется

INITTOFILTERSTRUCT

INITTOWFXSTRUCT

Начальные значения для типа и стандартного фильтра/формата в диалоге будут выбраны на основе описателя, указатель которого задан полем pwfltr / pwfx. В этом случае поле pwfltr/pwfx должно ссылаться на правильно заполненную структуру типа WAVEFILTER / WAVEFORMATEX.

SHOWHELP

Диалог будет снабжен кнопкой запроса помощи (Help), при нажатии которой окну-владельцу будет посылаться сообщение ACM с кодом ACMHELPMSGSTRING. Это сообщение необходимо предварительно зарегистрировать в Windows посредством функции RegisterWindowMessage.

  • hwndOwner — ключ окна-владельца (owner window) создаваемого диалога. Может быть нулевым, если окно-владелец не требуется.
  • pwfltr / pwfx — указатель области памяти для структуры типа WAVEFILTER / WAVEFORMATEX, в которую заносится описание выбранного фильтра/формата при успешном завершении выбора. Из этой же структуры берутся начальные значения полей диалога, если присутствует соответствующий флаг стиля.
  • cbwfltr / cbwfx — размер области памяти для структуры описания фильтра/формата. Если указанного размера недостаточно для записи требуемой структуры, ACM возвращает код ошибки NOTPOSSIBLE, одновременно занося в это поле требуемый размер области.
  • pszTitle — указатель строки заголовка диалога. Если это поле имеет нулевое значение, ACM использует заголовок по умолчанию.
  • szFilterTag / szFormatTag — область для строки названия типа фильтров/форматов. При успешном завершении выбора ACM заносит в это поле название выбранного типа.
  • szFilter / szFormat — область для строки названия стандартного фильтра/формата. При успешном завершении выбора ACM заносит в это поле название выбранного стандартного фильтра или формата.
  • pszName — указатель строки названия пресета для фильтра/формата. Если поля pszName и cchName описывают корректную символьную строку и флагами стилей не задана установка начальных значений, ACM пытается найти соответствующий пресет и установить по нему начальные значения списков диалога. Поиск пресетов происходит путем посимвольного сравнения строк с игнорированием регистра. После успешного завершения выбора, если поля pszName и cchName описывают буфер достаточного размера, ACM заносит в него название выбранного пресета. Если выбранный фильтр/формат не имеет пресета (Untitled), в буфер заносится пустая строка.
  • cchName — размер буфера, указываемого полем pszName, в байтах. Если pszName равно нулю, значение этого поля игнорируется.
  • fdwEnum — флаги режимов перебора фильтров/форматов. Вместе с полем pwfltrEnum / pwfxEnum задают условия, которым должны удовлетворять фильтры/форматы, включаемые в списки выводимого диалога. Поскольку для построения списков ACM пользуется собственными же функциями перебора, в этом поле используются те же флаги, что и в функциях acmFilterEnum / acmFormatEnum. Если поле pwfltrEnum / pwfxEnum имеет нулевое значение, поле флагов перебора тоже должно быть нулевым.
  • pwfltrEnum / pwfxEnum — указатель описателя фильтра/формата — структуры типа WAVEFILTER / WAVEFORMATEX, отдельные поля которой либо вся структура целиком задают условия для отбора фильтров/форматов, включаемых в списки выводимого диалога.
  • hInstance — ключ области данных, содержащей шаблон для создания диалога. Имя ресурса задается полем pszTemplateName. Поле используется только при наличии в стиле диалога флагов ENABLETEMPLATE или ENABLETEMPLATEHANDLE; в противном случае значение поля должно быть нулевым.
  • pszTemplateName — имя ресурса, содержащего шаблон для создания диалога. Для нумерованных ресурсов может использоваться стандартный макрос Windows MAKEINTRESOURCE. Поле используется только при наличии в стиле диалога флага ENABLETEMPLATE; в противном случае значение поля должно быть нулевым.
  • lCustData — произвольное значение, определяемое приложением, которое будет передаваться в функцию перехвата сообщений — в параметре lParam сообщения WM_INITDIALOG.
  • pfnHook — указатель функции перехвата, которая будет получать сообщения Windows, адресованные диалогу выбора.
В начало

В начало

Структура ACMSTREAMHEADER

Описывает фрагмент преобразуемого звукового потока и называется заголовком потока.

DWORD  cbStruct; 
DWORD  fdwStatus; 
DWORD  dwUser; 
LPBYTE  pbSrc; 
DWORD  cbSrcLength; 
DWORD  cbSrcLengthUsed; 
DWORD  dwSrcUser; 
LPBYTE  pbDst; 
DWORD  cbDstLength; 
DWORD  cbDstLengthUsed; 
DWORD  dwDstUser; 
DWORD  dwReservedDriver [10]; 
  • cbStruct — размер области памяти, занимаемой структурой.
  • fdwStatus — флаги состояния буфера. Устанавливаются приложением в нуль, далее управляются ACM. Имена констант имеют префикс ACMSTREAMHEADER_STATUSF_:

DONE

Преобразование завершено

INQUEUE

Заголовок находится в очереди драйвера

PREPARED

Заголовок подготовлен для передачи драйверу

  • dwUser — вспомогательное информационное значение, общее для обоих потоков, передаваемое обратно в приложение при уведомлении. Устанавливается приложением.
  • pbSrc — указатель буфера, содержащего порцию данных исходного звукового потока. Устанавливается приложением.
  • cbSrcLength — размер порции данных в буфере исходного потока (в байтах). Устанавливается приложением.
  • cbSrcLengthUsed — количество байтов порции данных исходного потока, использованных в последней операции преобразования. Устанавливается драйвером.
  • dwSrcUser — вспомогательное информационное значение для исходного потока, передаваемое обратно в приложение при уведомлении. Устанавливается приложением.
  • pbDst — указатель буфера для порции данных результирующего звукового потока. Устанавливается приложением.
  • cbDstLength — размер буфера выходного потока (в байтах). Устанавливается приложением.
  • cbDstLengthUsed — размер порции данных, записанных в буфер результирующего потока последней операцией преобразования. Устанавливается драйвером.
  • dwDstUser — вспомогательное информационное значение для результирующего потока, передаваемое обратно в приложение при уведомлении. Устанавливается приложением.
  • dwReservedDriver — служебные поля для ACM и драйвера.
В начало

В начало

Функции ACM

Классы функций интерфейса ACM

ACM имеет в своем составе четыре основных класса интерфейсных функций. Принадлежность функции к определенному классу обозначается префиксом в ее имени:

  • Функции работы с драйверами (acmDriver). Служат для установки, удаления, настройки, опроса и перебора доступных драйверов ACM.
  • Функции работы с фильтрами (acmFilter). Служат для опроса, перебора и выбора доступных фильтров.
  • Функции работы с форматами (acmFormat). Служат для опроса, перебора и выбора доступных форматов (кодеков).
  • Функции работы с потоками (acmStream). Служат для создания потоков преобразования и обработки порций данных в них.

Кроме того, ACM сам может вызывать (callback) три типа функций приложения:

  • Функции поддержки перебора — вызываются в процессе перебора (enumeration) драйверов, типов форматов/фильтров или стандартных форматов/фильтров и служат для формирования списка перебираемых объектов или остановки процесса перебора при нахождении нужного объекта.
  • Функции перехвата — вызываются при поступлении сообщений Windows в стандартные диалоги ACM, выводимые пользователю функциями выбора фильтра или формата, и служат для перехвата (hook) этих сообщений до обработки их средствами ACM. Позволяют изменить принятое по умолчанию поведение стандартных диалогов ACM.
  • Функции уведомления — вызываются после завершения запрошенной операции. Уведомление также может происходить в виде установки объекта события (event) либо в виде посылки сообщения — задаче (thread) или окну.
В начало

В начало

Информационные функции

acmGetVersion

Запрос версии ACM

acmMetrics

Запрос различных параметров ACM

В начало

В начало

Функции работы с драйверами

acmDriverAdd

Установка собственного драйвера приложения или задание окна уведомления

acmDriverRemove

Удаление собственного драйвера приложения

acmDriverOpen

Открывание драйвера

acmDriverClose

Закрывание драйвера

acmDriverDetails

Запрос сведений о драйвере

acmDriverEnum

Перебор доступных драйверов

acmDriverID

Запрос идентификатора драйвера

acmDriverPriority

Установка приоритета драйвера

acmDriverMessage

Передача сообщения драйверу

В начало

В начало

Функции работы с фильтрами

acmFilterTagDetails

Запрос сведений о типе фильтра

acmFilterDetails

Запрос сведений о фильтре

acmFilterTagEnum

Перебор доступных типов фильтров

acmFilterEnum

Перебор доступных стандартных фильтров

acmFilterChoose

Выбор фильтра при помощи стандартного диалога ACM

В начало

В начало

Функции работы с форматами

acmFormatTagDetails

Запрос сведений о типе формата

acmFormatDetails

Запрос сведений о формате

acmFormatTagEnum

Перебор доступных типов форматов

acmFormatEnum

Перебор доступных стандартных форматов

acmFormatChoose

Выбор формата при помощи стандартного диалога ACM

acmFormatSuggest

Запрос наиболее подходящего для преобразования формата

В начало

В начало

Функции работы с потоками

acmStreamOpen

Открывание потока преобразования

acmStreamClose

Закрывание потока

acmStreamSize

Запрос размеров буферов потока

acmStreamPrepareHeader

Подготовка буфера потока

acmStreamUnprepareHeader

Отмена подготовки буфера потока

acmStreamConvert

Преобразование очередной порции данных в потоке

acmStreamReset

Сброс (уничтожение) потока

acmStreamMessage

Передача сообщения драйверу потока

В начало

В начало

Функции, определяемые приложением

В отличие от стандартных функций интерфейса, все функции этой группы определяются приложением. Имена, приведенные в таблице, являются условными; реальные функции приложения могут иметь любые имена. Приложение передает эти функции ACM при помощи указателей, а ACM вызывает их в заранее оговоренных случаях.

DriverProc

Основная функция драйвера

ChooseHook

Перехват сообщений диалога выбора фильтра/формата

DriverEnumCallback

Поддержка перебора драйверов

FilterTagEnumCallback

Поддержка перебора типов фильтров

FilterEnumCallback

Поддержка перебора стандартных фильтров

FormatTagEnumCallback

Поддержка перебора типов форматов

FormatEnumCallback

Поддержка перебора стандартных форматов

StreamCallback

Уведомление о завершении операции с потоком

В начало

В начало

Возвращаемые значения

Большинство функций ACM возвращает значения типа MMRESULT — универсальный код результата звуковой подсистемы Windows. В дополнение к стандартным кодам, константы для которых имеют префикс MMSYSERR_, для ACM определены константы с префиксами ACMERR_:

NOTPOSSIBLE

Невозможно выполнить запрошенную операцию. Обычно эта ошибка возникает при невозможности использовать требуемое сочетание форматов или когда объема заданного буфера недостаточно для записи всех затребованных данных

BUSY

Запрошенный драйвер используется в настоящее время; попытка закрыть поток с незавершенной асинхронной операцией и т.п.

UNPREPARED

Буфер преобразования не был подготовлен функцией acmStreamPrepareHeader

CANCELED

Пользователь закрыл кнопкой Cancel диалог, выведенный функцией выбора фильтра/формата.

Информационные функции

acmGetVersion — запрос версии ACM

DWORD acmGetVersion (void);

Возвращает версию ACM.

acmMetrics — запрос параметров компонентов ACM

MMRESULT acmMetrics (
   HACMOBJ  Obj,
   UINT  MetricCode,
   void  *ForMetric
);
  • Obj — ключ объекта, по отношению к которому запрашивается параметр. Для запросов, не относящихся к определенному объекту ACM, этот параметр может иметь значение NULL.
  • MetricCode — код запрашиваемого параметра. Для кодов параметров определены константы с префиксом ACM_METRIC_:

COUNT_DRIVERS, COUNT_LOCAL_DRIVERS

Запрос количества разрешенных для работы драйверов ACM

COUNT_DISABLED, COUNT_LOCAL_DISABLED

Запрос количества запрещенных для работы драйверов ACM

COUNT_CONVERTERS, COUNT_LOCAL_CONVERTERS

Запрос количества установленных преобразователей формата

COUNT_CODECS, COUNT_LOCAL_CODECS

Запрос количества установленных кодеков

COUNT_FILTERS, COUNT_LOCAL_FILTERS

Запрос количества установленных фильтров

COUNT_HARDWARE

Запрос количества драйверов ACM, введенных для поддержки звуковых устройств с аппаратным преобразованием формата при вводе-выводе звука

DRIVER_PRIORITY

Запрос приоритета заданного драйвера

DRIVER_SUPPORT

Запрос флагов возможностей и режимов заданного драйвера

HARDWARE_WAVE_INPUT

Запрос идентификатора звукового устройства, аппаратно поддерживающего ввод (запись) звука в сжатом формате

HARDWARE_WAVE_OUTPUT

Запрос идентификатора звукового устройства, аппаратно поддерживающего вывод (воспроизведение) звука в сжатом формате

MAX_SIZE_FILTER

Запрос максимального размера структуры WAVEFILTER, необходимой для описания любого из фильтров, поддерживаемых заданным драйвером

MAX_SIZE_FORMAT

Запрос максимального размера структуры WAVEFORMATEX, необходимой для описания любого из форматов, поддерживаемых заданным драйвером

Константы для кодов количества драйверов, содержащие в своих именах слово LOCAL, относятся к локальным драйверам ACM; варианты этих констант без слова LOCAL относятся к глобальным драйверам. Для определения общего количества установленных глобальных или локальных драйверов необходимо определить сумму возвращенных разрешенных и запрещенных для работы драйверов соответствующего типа.

В запросах количества драйверов параметр Obj должен быть нулевым. В запросах приоритета, флагов и связанного звукового устройства параметр Obj задает идентификатор опрашиваемого драйвера. В запросах максимальных размеров структур параметр Obj либо задает ключ или идентификатор драйвера, фильтры/форматы которого опрашиваются, либо равен NULL — в этом случае возвращается максимальное значение запрошенного параметра среди всех установленных драйверов.

ForMetric — указатель переменной, в которую возвращается запрашиваемый параметр. В описанной реализации все возвращаемые параметры имеют тип DWORD.

В начало

В начало

Следующая страница


Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует