[FFmpeg] Разработка аудио и видео SDL ⑦ (SDL воспроизводит аудиоданные PCM | извлекает данные формата PCM | устанавливает параметры звука | открывает аудиоустройство | устанавливает функцию обратного вызова воспроизведения | воспроизводит аудиоданные | закрывает аудиоустройство)
[FFmpeg] Разработка аудио и видео SDL ⑦ (SDL воспроизводит аудиоданные PCM | извлекает данные формата PCM | устанавливает параметры звука | открывает аудиоустройство | устанавливает функцию обратного вызова воспроизведения | воспроизводит аудиоданные | закрывает аудиоустройство)

Загрузка исходного кода блога : https://download.csdn.net/download/han1202012/89734548

1. Знакомство с форматом PCM

1. Введение в PCM

PCM, импульсно-кодовая модуляция, импульсно-кодовая модуляция, использует числа для представления аналоговых сигналов и широко используется при оцифровке звука;

  • аналоговый сигнал изменять цифровой сигнал : PCM Воля аналоговый сигнал изменять Изменятьдля цифровой сигнал ,верноаналоговый сигналруководить Отбор проб, количественный анализ и кодирование генерировать PCM данные ;
  • Выборка: существовать特定 временной интервал 内верноаналоговый измеряется амплитуда сигнала , для звука есть Измерениевокаламплитуда ;
  • Количественное определение: Воля Измерьте значение амплитуды картографирование приезжать Дискретное числовое значение начальство ;
  • Кодировка: Воля Количественная оценканазадизценить изменять Изменятьдлядвоичный Формат , для цифровой обработки и хранения ;

Звук — это тип аналогового сигнала. Звук записывается в данные PCM через микрофон, а затем данные PCM передаются в динамик для воспроизведения звука;

Аудиоданные PCM не сжимаются и представляют собой данные высокой точности без каких-либо потерь звука. После преобразования в формат AAC/MP3 некоторая звуковая информация будет безвозвратно потеряна, например: высокочастотный сигнал/низкочастотный сигнал/информация о маскировании временной области. /частотная область. Информация о маскировании и т. д. удаляются во время сжатия звука;

ссылка [Принципы аудио и видео] Принципы кодирования и декодирования аудио ① ( звуковые характеристики | звуковая сущность | звуковая частота | звуковая Анализ сущности громкости | цифровой звук |Импульсно-кодовая модуляция PCM - Выборочное значение амплитуды | Найквист Nyguist Теорема выборки ) блог ;

2. Параметры ПКМ

Параметры данных PCM:

  • Частота выборки : Количество сигналов в секунду , Обычный из Частота выборкииметь 44.1 kHz , 48 kHz ждать , Обратите внимание на различие Частота выборки и звуковая частота ,下面иметьзвуковая частотаанализировать ;
  • Количество каналов : Аудио Сигнализ Количество каналов量 , Например : мононуклеоз ( Mono ) ,стерео ( Stereo ) или многоканальный ( 5.1 объемный звук ) ;
  • Разрядность: Каждыйиндивидуальныйобразецизразрешение , Обычно 16 Бит, 24 Кусочекждать , разрядность определяет динамический диапазон и точность Аудиоизза ;

3. Частота звука (обратите внимание на разницу в частоте дискретизации)

звуковая частотаанализировать : частота звука то есть вокал амплитуда ;

вокаламплитудадействительныйначальствода синус / косинус изгиб,синусизциклчислото естьчастота звука, например : 128 средний центр клавишного фортепиано C примечание Do Частота звуковая частотадля 262 Hz , такжето есть хозяинчастота, вибрирует каждую секунду 262 Второсортный , каждую секунду 262 индивидуальный синус / косинус изгиб цикл , ссылка [Обработка звука] Высота звука и частота сравнительная таблица ( примечаниечастота算法 ) ;

проходить Преобразование Фурье , может быть проанализирован на основе данных аудиообразца звуковая частота , Это есть информация во временной области изменять Информация о частотной области ;

4. Используйте ffmpeg для получения данных формата PCM.

Данные PCM не сжимаются и занимают много места. Одна минута аудиоданных занимает около 11 МБ. При сжатии в формат mp4 или aac их можно сжать до размера менее 1 МБ;

PCM Данные нелегко найти , Эти данные не имеют никакого Заголовок файла Описание информации , Файл из первого индивидуального байта есть 第одининдивидуальныйвыборкаизчислоценитьданные , играть PCM Данные должны быть известны для аудио Частота выборки Количество каналов Количество бит выборки и другие параметры ;

Здесь инструмент командной строки FFmpeg используется для извлечения данных PCM из видео. Следующая команда может извлечь данные PCM из видео в формате mp4;

Язык кода:javascript
копировать
ffmpeg -i input.mp4 -codec:a pcm_s16le -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm
  • -i input.mp4 : Укажите входной файл input2.mp4 , -i даиспользуется для Укажите входной файлизпараметр ;
  • -codec:a pcm_s16le : обозначение Аудиокодек для pcm_s16le , Этот вид PCM Аудио Формат,использовать 16 Маленький порядок байтов s16le , этотиндивидуальныйкодекиспользуется для Воляаудиоданные хранятся в несжатом виде ;
  • -ar 44100 : настраивать Аудио Частота выборкидля 44100 Hz , Частота выборки да Сколько индивидуальных Аудиообразцов собирается в секунду? ;
  • -ac 2 : настраивать Аудио Количество каналовдля 2 , Бинауральный стерео ;
  • -f s16le : обозначениевыход Форматдля s16le , Это да Аудиоиз оригинал PCM данные Формат ,Чтосередина s16 представлять 16 битовое целое число со знаком, le выполнение с прямым порядком байтов Little Endian ;

ссылка 【FFmpeg】ffmpeg Параметры командной строки ③ ( ffmpeg Анализ параметров звука | Установить номер аудиокадра | Установить битрейт аудио | настраивать Аудио Частота выборки | настраивать Аудио Количество каналов | Установить аудиокодек | Установить аудиофильтр ) блог ;

5. Используйте ffplay для воспроизведения данных формата PCM.

После получения выходного файла выполните

Язык кода:javascript
копировать
ffplay -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm

Заказ , Можетигратьначальствоописыватьизвлекатьиз PCM аудиоданные ;

2. Процесс воспроизведения SDL PCM

SDL играть PCM Аудио хозяин要分для Следующееиндивидуальныйшаг

  • инициализация SDL - SDL_Init функция
  • настраивать Аудиопараметр - SDL_AudioSpec Структура
  • Откройте аудиоустройство - SDL_OpenAudio функция
  • настраивать Аудиоперезвонитьфункция - SDL_AudioCallback Типфункция
  • читать PCM данные - fread функция
  • играть Аудио - SDL_PauseAudio функция
  • играть После окончания Выключите аудиоустройство - SDL_CloseAudio функция
  • покидать SDL - SDL_Quit функция

1. Инициализируйте SDL

инициализация SDL среда , то естьвызов SDL_Init функция ,Эта функция используется для инициализации управления системой SDL., SDL необходимо выполнять перед любой операцией инициализация SDL шаг ;

SDL_Init функцияпрототипследующее, входящий flags Параметры,используемые для установки SDL серединаизгдеиндивидуальный Подсистема, Эта статьяблогсерединана настройки SDL_INIT_AUDIO Аудио подсистема , используется для PCM Аудиоиграть ;

Язык кода:javascript
копировать
int SDL_Init(Uint32 flags);

специфическийизфункцияпрототипссылка 【FFmpeg】SDL Аудио и видео разработка ① ( SDL рисунок окна | SDL Видео шоуфункция | SDL_Window окно | SDL_Renderer Рендерер | SDL_Texture текстура ) блог Главасередина Содержание главы 1 ;

2. Установите параметры звука.

существовать SDL середина , использовать SDL_AudioSpec Структура Приходитьнастраивать Аудиопараметр , Вид Структура содержит индивидуальные ключевые атрибуты Audioiz. ,Создайтеиндивидуальный SDL_AudioSpec Структура,настраивать Должен Структураизкаждыйиндивидуальныйчленпараметр ;

  • выборкачастота ( freg ) : целое число , выражатьаудиоданныеизвыборкачастота , Обычный из Частота выборкииметь44100Hz、48000Hzждать , Это определяет качество Аудиоизиграть. , Частота выборки Чем больше товар, тем выше его качество. ;
  • аудиоданные Формат ( format ) : SDL_AudioFormat тип перечисления , выражать Каждыйиндивидуальныйобразециз Формат ;
    • AUDIO_S16SYS выражать Подписано 16 Кусочек целое числообразец ;
    • AUDIO_S8 выражать Подписано 8 Кусочек целое числообразец ;
    • AUDIO_F32SYS выражать 32 Кусочек число с плавающей запятой образец ;
  • Количество каналов (каналов): 1 выражатьмононуклеоз , 2 выражатьстерео ;
  • Значение тишины (тишина): без подписи 8 Кусочекцелое число , выражатьаудиоданныесередина Каждыйиндивидуальныйобразецизнемойбайтценить ;
  • Аудиобуферизобщийбайтчисло ( size ) : без подписи 32 Кусочекцелое число , Это индивидуальное значение обычно требует да 2 извласть Второсортный方 , Долженпараметр Определен объем функций обратного вызова аудио, которые необходимо обрабатывать каждому Второсортовому устройству. ;
    • Формула расчета: samples * channels * (SDL_AUDIO_BITSIZE(format) / 8) ;
  • Указатель пользовательских данных (userdata): Относится к указателю "изданныеиз", определенному разработчиком. , SDL Сам по себе этот индивидуальный указатель не будет использоваться , Разработчик может использовать его для хранения аудиоданных, связанных с пользовательской информацией. ;

SDL_AudioSpec Структурапрототипследующее :

Язык кода:javascript
копировать
/*
	SDL_AudioSpec Структура Зависит от SDL_OpenAudio() Рассчитано по функции 
	верно Вмногоканальный Аудио,По умолчанию из SDL голосовой тракткартографированиедля:
	2: Передний левый (FL) Передний правый (FR) (стерео)
	3: Передний левый (FL) Передний правый (FR) Улучшение низких частот (LFE) (2.1 объемный звук)
	4: Передний левый (FL) Передний правый (FR)左назад(BL)右назад(BR)(四голосовой тракт)
	5: Передний левый (FL) Передний правый (FR)серединанабор(FC)左назад(BL)右назад(BR)(四голосовой тракт + серединанабор)
	6: Передний левый (FL) Передний правый (FR)серединанабор(FC)Улучшение низких частот(LFE)Объемный левый(SL)правильная упаковка(SR)(5.1 объемный звук - Последние два индивидуальных также "Мандада" остались позади BL сразу назад BR)
	7: Передний левый (FL) Передний правый (FR)серединанабор(FC)Улучшение низких частот(LFE)назаднаборсерединанабор(BC)Объемный левый(SL)правильная упаковка(SR)(6.1 объемный звук)
	8: Передний левый (FL) Передний правый (FR)серединанабор(FC)Улучшение низких частот(LFE)左назад(BL)右назад(BR)Объемный левый(SL)правильная упаковка(SR)(7.1 объемный звук)
*/
typedef struct SDL_AudioSpec {  
    int freq;                 // выборкачастота(Sample Rate)  
    SDL_AudioFormat format;   // аудиоданные Формат  
    Uint8 channels;           // Количество каналов(1 = мононуклеоз, 2 = стерео, etc.)  
    Uint8 silence;            // значение отключения звука(Каждыйиндивидуальныйобразецизнемойбайтценить)  
    Uint16 samples;           // Аудиобуферсерединаизобразецчисло  
    Uint16 padding;           // Необходимо указать значение заполнения, чтобы гарантировать, что размер структуры для является четным (используется для некоторых платформ из выравнивания)  
    Uint32 size;              // Аудио буфер из общего количества байт (= samples * channels * (SDL_AUDIO_BITSIZE(format) / 8))  
    void *userdata;           // Пользовательский указатель данных (может Зависит от Разработано Зависит отиспользовать)  
    Uint8 *buffer;            // Фактические аудиоданныеиз указатель  
    unsigned int length;      // Длина аудиобуфера (в байтах для одного Кусочка) (существовать) SDL 2.0.9 середина Устарело,предположениеиспользовать size поле)  
} SDL_AudioSpec;

SDL_AudioSpec Структуранастраивать示例 :

Язык кода:javascript
копировать
#include <SDL2/SDL.h>  
  
int main() {  
    SDL_AudioSpec spec;  
  
    // настраиватьвыборка Частота 44100 Hz  
    spec.freq = 44100;  
  
    // настраивать Аудио Форматдля 16-bit знакцелое число, порядок системных байтов  
    spec.format = AUDIO_S16SYS;  
  
    // настраиватьдлястерео(2 индивидуальныйголосовой тракт)  
    spec.channels = 2;  
  
    // настраиватьзначение отключения звукадля 0 (для 16-bit знакцелое число,в целомиспользовать 0)  
    spec.silence = 0;  
  
    // настраивать Каждыйиндивидуальныйбуферизобразецчислодля 1024  
    spec.samples = 1024;  
  
    // Вычислить общее количество байт в аудиобуфере из  
    spec.size = spec.samples * spec.channels * (SDL_AUDIO_BITSIZE(spec.format) / 8);  
  
    // Набор указателей данных пользователя для NULL (без настройки)  
    spec.userdata = NULL;  
  
    // Выделить буфер аудио (требуется выделение памяти вручную)  
    spec.buffer = (Uint8 *)SDL_malloc(spec.size);  
  
    // Убедитесь, что выделение памяти прошло успешно  
    if (spec.buffer == NULL) {  
        SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "Failed to allocate audio buffer");  
        return -1;  
    }  
  
    // создание буфера для отключения звука (опционально)  
    SDL_memset(spec.buffer, spec.silence, spec.size);  
  
    // ... использовать spec Сделать аудиоиграть или захватить ...  
  
    // выделить из буфера  
    SDL_free(spec.buffer);  
  
    return 0;  
}

3. Откройте аудиоустройство.

SDL_OpenAudio функция используется для настраивать Аудиопараметр и Откройте аудиоустройство , для последующей подготовки к аудиоиграм ;

SDL_OpenAudio функцияпрототипследующее :

Язык кода:javascript
копировать
int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained);
  • SDL_AudioSpec *desired параметр : настройки ожиданий пользователей из конфигурации Audio ;
  • SDL_AudioSpec *obtained параметр : Фактический параметр аудиооборудования ,существовать Эта статьяблогсерединавременныйнастраиватьдля NULL ;

4. Установите функцию обратного вызова воспроизведения.

SDL_AudioCallback да SDL ( Simple DirectMedia Layer ) Библиотекасерединаиз PCM Аудиоиграть Тип обратного вызова ,когда SDL игратьнадкогдавперед Аудиобуферсерединаизданныеназад, Автоматически перезвонит функции , для Аудио оборудование обеспечивает последующее сопровождение Аудиоигратьданные , Основная роль функцииследующее :

  • поставлятьаудиоданные : Когда вам нужно больше изданий на каждое аудиоустройство ,SDL встречавызовэтотиндивидуальныйперезвонитьфункция, К stream параметр Относится к Кизаудиоданные буферная зона. заполнить аудиоданные ;
  • Обработка аудиоданных : существовать в середине функции , Может в соответствии с заявкой из необходимости оценить обработку аудиоданных , Например : Применяйте звуковые эффекты ожидания из серединачитанных файлов, синтезируйте Аудио или ;

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

SDL_AudioCallback функцияпрототип :

Язык кода:javascript
копировать
/**
 *  Когда аудиооборудование вам нужно больше данных, волявызов эту функцию.
 *
 *  \param userdata  保存существовать SDL_AudioSpec Структура серединаиз конкретного параметра приложения
 *  \param stream    Каудиодированный буфер из указателя
 *  \param len       Длина буфера (в байтах)
 *
 *  Как только функция обратного вызова возвращается, буфер Воля больше не действителен.
 *  стерео Аудиообразец с LRLRLR из Последовательное хранение.
 *
 *  Если вы предпочитаете нравиться, вы можете отказаться от использования функции обратного вызова и использовать вместо нее SDL_QueueAudio()。
 *  Толькоиспользовать NULL Просто перезвоните и откройте свое аудиоустройство.
 */
typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,
                                            int len);
  • void *userdata параметр : Относится к указателю определяемых пользователем данных. , существовать в середине функции Этот указатель можно использовать Доступ для хранения дополнительной информации ;
  • Uint8 * stream параметр : Каудиодированный буфер из указателя ,Воляаудиоданные写入этотиндивидуальныйбуфер,Сразу Можетодеяло Аудиооборудованиеиграть ;
  • int len параметр : Длина буфера в байтах , использовать Необходимо убедиться, что длина изданных записей в буфер К не превышает это индивидуальное значение. ;

существовать Этот примерсередина , осуществленный SDL_AudioCallback перезвонитьфункция следующее :

Язык кода:javascript
копировать
// один кадр PCM данныеиметь 1024 индивидуальныйвыборкаточка
// Каждыйиндивидуальныйвыборка Да 2 ряд стерео ( о канале ) , Каждыйиндивидуальныйрядизвыборка Да 16 Кусочек (bit) такжето есть 2 байт (Byte)
// Каждый Второсортныйчитать 2 рамка PCM данные
// 1024 ( выборкачисло ) * 2 ( Количество каналов ) * 2 ( 2 байт / 16 Кусочек ) * 2 ( рамкачислодля 2 рамка )
#define PCM_BUFFER_SIZE (1024 * 2 * 2 * 2)

// АудиоPCMданные указатель кэша
static Uint8 *s_audio_buf = NULL;
// когдавпередчитатьиз Кусочекнабор
static Uint8 *s_audio_pos = NULL;
// Настройка конца кеша Кусочек
static Uint8 *s_audio_end = NULL;

// Функция обратного вызова аудиоустройства
void fill_audio_pcm(void *udata, Uint8 *stream, int len)
{
    SDL_memset(stream, 0, len); // Воля Инициализация буфера потоковой передачи для 0

    if(s_audio_pos >= s_audio_end) // нравитьсяфруктыданныеужечитатьнад毕    {
        return; // покидатьперезвонитьфункция    }

    // Когда данных достаточно, прочитайте длину по умолчанию. Если данных недостаточно, остается только чтение.
    int remain_buffer_len = s_audio_end - s_audio_pos;
    len = (len < remain_buffer_len) ? len : remain_buffer_len;
    // Воляданные копии приезжатьстримы отрегулировать громкость
    SDL_MixAudio(stream, s_audio_pos, len, SDL_MIX_MAXVOLUME/8);
    printf("len = %d\n", len); // Длина предварительно считанных данных при выводе
    s_audio_pos += len;  // Переместите указатель кэша на следующий индивидуальный Кусочек
}

5. Воспроизведение аудиоданных

вызов SDL_PauseAudio функция Может восстанавливаться / пауза игратьаудиоданные ;

SDL_PauseAudio функцияпрототипследующее :

Язык кода:javascript
копировать
void SDL_PauseAudio(int pause_on);

int pause_on параметр даодининдивидуальныйцелое числоценить , Определяет состояние аудиооборудования ;

  • 0 : восстанавливаться Аудиоиграть , нравиться фрукты Аудиотехника перед дапаузом , вызовэтотфункция Волявстречавосстанавливаться Аудиоиграть ;
  • 1 : пауза Аудиоиграть , нравитьсяфрукты Аудиооборудование正существоватьиграть Аудио , вызовэтотфункция Волявстречапауза Аудиоиграть ;

Некоторые примеры кода:

Язык кода:javascript
копировать
#include <SDL2/SDL.h>

int main() {
    // инициализация SDL
    if (SDL_Init(SDL_INIT_AUDIO) < 0) {
        // Обработка ошибок
        return -1;
    }

    // Откройте аудиоустройство、настраивать Аудиоперезвонитьждать(немного)

    // начать воспроизводить аудио
    SDL_PauseAudio(0);  // передача 0 выражатьвосстанавливаться Аудиоиграть

    // существоватьподходящийкогдаизкогдапауза Аудио
    SDL_PauseAudio(1);  // передача 1 выражатьпауза Аудиоиграть

    // Завершить аудиоиграть, очистить ресурсы ожидания (опущено)

    // убирать SDL
    SDL_Quit();

    return 0;
}

6. Выключите аудиоустройство.

играть После окончания вызов SDL_CloseAudio функция , Выключите аудиоустройство , выпускать PCM Подайте заявку на системные ресурсы, когда играете ;

SDL_CloseAudio функцияпрототипследующее, Долженфункцияиспользуется для Выключите аудиоустройство ;

Язык кода:javascript
копировать
void SDL_CloseAudio(void);

Некоторые примеры кода:

Язык кода:javascript
копировать
#include <SDL/SDL.h>

int main() {
    // инициализация SDL
    if (SDL_Init(SDL_INIT_AUDIO) < 0) {
        // Обработка ошибок
        return -1;
    }

    // настраивать Аудиопараметри Откройте аудиоустройство(немного)

    // Выключите аудиоустройство
    SDL_CloseAudio();

    // убирать SDL
    SDL_Quit();

    return 0;
}

7. Ключевые шаги и примеры кода для воспроизведения аудиоданных PCM в SDL.

Пример кода:

Язык кода:javascript
копировать
#include <SDL2/SDL.h>  
#include <stdio.h>  
  
// Аудиоперезвонитьфункция  
void audio_callback(void *userdata, Uint8 *stream, int len) {  
    // этот里заполнить аудиоданныеприезжать stream середина  
    // len данужно заполнитьизбайтчисло  
    SDL_memset(stream, 0, len); // Просто Воля буфер приглушен  
}  
  
int main(int argc, char *argv[]) {  
    // инициализация SDL Аудио подсистема  
    if (SDL_Init(SDL_INIT_AUDIO) < 0) {  
        printf("SDL Не могущийинициализация! SDL_Error: %s\n", SDL_GetError());  
        return -1;  
    }  
  
    // Настройка параметров аудиооборудования  
    SDL_AudioSpec desired;  
    desired.freq = 44100;           // выборкачастота 44.1kHz  
    desired.format = SDL_AUDIO_S16SYS; // Аудио Формат:16 Короткая последовательность системных байтов  
    desired.channels = 2;          // стерео  
    desired.samples = 4096;        // Каждый Второсортныйперезвонитьизобразецчисло  
    desired.callback = audio_callback; // Аудиоперезвонитьфункция  
    desired.userdata = NULL;       // Данные пользователя (здесь не использовать)  
  
    SDL_AudioSpec obtained;  
    // Откройте аудиоустройство  
    if (SDL_OpenAudio(&desired, &obtained) < 0) {  
        printf("Не могущий Откройте аудиоустройство! SDL_Error: %s\n", SDL_GetError());  
        SDL_Quit();  
        return -1;  
    }  
  
    // существоватьэтот里,Вы можетеначать воспроизводить аудио Понятно  
    // Например,ты Можетвызов SDL_PauseAudio(0) Давайте начнем  

    // начать воспроизводить аудио  
    SDL_PauseAudio(0);  
    
    // ПРИМЕЧАНИЕ. Чтобы действительно применить середину, вам нужен цикл или какой-то способ сохранить функцию обратного вызова вызова.  
    // Здесь мы лишь показываем примеры и упрощаем код.  
  
    // когдатынад成Аудиоигратьназад,Помнить Выключите аудиоустройство  
    SDL_CloseAudio();  
    SDL_Quit();  
  
    return 0;  
}

3. Полный пример кода


1. Полный пример кода

Язык кода:javascript
копировать
// Импортные стандарты IO Библиотека
#include <stdio.h>
// импортировать SDL Заголовочный файл библиотеки
#include <SDL.h>

// один кадр PCM данныеиметь 1024 индивидуальныйвыборкаточка
// Каждыйиндивидуальныйвыборка Да 2 ряд стерео ( о канале ) , Каждыйиндивидуальныйрядизвыборка Да 16 Кусочек (bit) такжето есть 2 байт (Byte)
// Каждый Второсортныйчитать 2 рамка PCM данные
// 1024 ( выборкачисло ) * 2 ( Количество каналов ) * 2 ( 2 байт / 16 Кусочек ) * 2 ( рамкачислодля 2 рамка )
// Каждый Второсортныйот местный PCM данныедокументсерединачитать 1024 * 2 * 2 * 2 байтиз Аудио данные
#define PCM_BUFFER_SIZE (1024 * 2 * 2 * 2)

// Аудио PCM указатель кэша данных , Этот указатель ссылается на кучу памяти Киз, содержащую полную информацию. PCM документданные
static Uint8 *s_audio_buf = NULL;
// когдавпередчитатьиз Кусочекнабор , К используется при начале игры s_audio_buf Указатель указывает на первый адрес Кданныеиз.
static Uint8 *s_audio_pos = NULL;
// Настройка конца кеша Кусочек , Обратитесь к s_audio_buf 指针Обратитесь кданныеиз хвостовой адрес , Предотвратить выход данных за пределы границ неизвестная ошибка
static Uint8 *s_audio_end = NULL;

// Функция обратного вызова аудиоустройства
void fill_audio_pcm(void *udata, Uint8 *stream, int len)
{
    // Очистить буфер ,Воля流буферинициализациядля 0, Данные о предотвращении помех
    SDL_memset(stream, 0, len);

    // Убедитесь, что при чтении не происходит выхода за пределы , читатьприезжать Что它未知данные    if(s_audio_pos >= s_audio_end) // нравитьсяфруктыданныеужечитатьнад毕    {
        return; // покидатьперезвонитьфункция    }

    // Рассчитать оставшиеся данные : данных достаточно, чтобы прочитать длину по умолчанию , Когда данных недостаточно, остается только чтение.
    // 之впередчитатьизданные Да len байт
    // последней части недостаточно len время байта , читать remain_buffer_len байтданные
    int remain_buffer_len = s_audio_end - s_audio_pos;
    len = (len < remain_buffer_len) ? len : remain_buffer_len;

    // Воляданные копии приезжатьстримы отрегулировать громкость
    SDL_MixAudio(stream, s_audio_pos, len, SDL_MIX_MAXVOLUME/8);
    printf("len = %d\n", len); // Длина предварительно считанных данных при выводе
    s_audio_pos += len;  // Переместите указатель кэша на следующий индивидуальный Кусочек
}

// использовать ffmpeg Заказ извлекать PCM данные :
// ffmpeg -i input.mp4 -codec:a pcm_s16le -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm
// использовать ffplay Заказ играть PCM данные ,играть PCM данныедолженобозначение Частота выборки / Количество каналов / Количество бит выборки
// ffplay -ar 44100 -ac 2 -f s16le 44100_16bit_2ch.pcm
#undef main
int main(int argc, char *argv[])
{
    int ret = -1; // Возвращаемое значение инициализациядля-1
    FILE *audio_fd = NULL; // Указатель файла: организациядля пустого
    SDL_AudioSpec spec; // SDLАудио Технические характеристики
    const char *path = "44100_16bit_2ch.pcm"; // Путь к файлу PCM
    // Длина кэша на Второсортный
    size_t read_buffer_len = 0;

    // инициализацияSDLАудио
    if(SDL_Init(SDL_INIT_AUDIO))    // инициализацияSDLАудиоподдерживать    {
        fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); // Выходное сообщение об ошибке
        return ret; // Возврат кода ошибки
    }

    // Открыть файл ПКМ
    audio_fd = fopen(path, "rb"); // Открыть в режиме только для чтения файл ПКМ
    if(!audio_fd)
    {
        fprintf(stderr, "Failed to open pcm file!\n"); // Не удалось открыть файл
        goto _FAIL; // Перейти внесены измененияпризаезезз обработка сбоев
    }

    s_audio_buf = (uint8_t *)malloc(PCM_BUFFER_SIZE); // для Аудио буфер выделяет память

    // настраивать АудиопараметрSDL_AudioSpec
    spec.freq = 44100;          // выборка Частота44100Hz
    spec.format = AUDIO_S16SYS; // выборкаточка Форматдля16Кусочексистема Формат    spec.channels = 2;          // 2ряд
    spec.silence = 0;           // значение отключения звукадля0
    spec.samples = 1024;        // Каждый Второсортныйчитать1024индивидуальныйвыборкаточка    spec.callback = fill_audio_pcm; // настраивать Аудиоперезвонитьфункция
    spec.userdata = NULL;       // пользовательданныедлянулевой    // Откройте аудиоустройство
    if(SDL_OpenAudio(&spec, NULL))
    {
        fprintf(stderr, "Failed to open audio device, %s\n", SDL_GetError()); // Откройте аудиоустройство не удалось
        goto _FAIL; // Перейти внесены измененияпризаезезз обработка сбоев
    }

    // начать воспроизводить аудио
    SDL_PauseAudio(0); // Отменить статус Аудиопаузы

    int data_count = 0; // данные计число器инициализациядля0    while(1)
    {
        // Из файлачитатьPCMданные
        read_buffer_len = fread(s_audio_buf, 1, PCM_BUFFER_SIZE, audio_fd); // читатьPCMданныеприезжать缓存        if(read_buffer_len == 0)
        {
            break; // нравиться Если данных больше нет, то выйти из цикла
        }
        data_count += read_buffer_len; // 累加читатьизданныеобщийбайтчисло
        printf("now playing %10d bytes data.\n",data_count); // выходкогдавпередигратьизданныебайтчисло
        s_audio_end = s_audio_buf + read_buffer_len;    // Обновить кеш из настроек Конец Кусочек
        s_audio_pos = s_audio_buf;  // Обновить кэш из настройки Кусочек
        // Главный поток ожидания ожидает использования данных PCM.
        while(s_audio_pos < s_audio_end)
        {
            SDL_Delay(10);  // подожди подожди 10 миллисекунд
        }
    }
    printf("play PCM finish\n"); // играть Полные советы
    // Выключите аудиоустройство
    SDL_CloseAudio(); // Выключите аудиоустройство

_FAIL:
    // выпускатьресурс    if(s_audio_buf)
        free(s_audio_buf); // выпускать аудиокэш-память

    if(audio_fd)
        fclose(audio_fd); // закрыть файл

    // покидатьSDL
    SDL_Quit(); // покидатьSDLБиблиотека

    return 0; // Возврат кода успеха
}

2. Результаты выполнения

Зависит от Вигратьизда Аудио , При использовании игры нет оконного интерфейса. ;

от视频серединаизвлекатьиз из PCM аудиоданные, Копия прибыла Скомпилируйте вывод из файла, находящегося в корневом каталоге середина. ;

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода