Как настроить громкость аудио с помощью API AVFilter из FFmpeg в Linux?

Вопрос или проблема

Я работаю над встроенной системой Linux (ядро-5.10.24) и разрабатываю аудиоплеер, используя библиотеки FFmpeg и ALSA.

Теперь основные функции выполнены, и я могу воспроизводить MP3 файл, используя интерфейсы AVCodec и SWresample FFmpeg.

int decode_play(void)
{
    .....
    while (1) {
        if (av_read_frame(pfmtctx, packet) < 0) {
            avcodec_flush_buffers(pcodectx);
            printf("Получен конец медиа, выходим\n");
            break;
        }
        if (packet->stream_index != stream) {
            continue;
        }
        int res = avcodec_send_packet(pcodectx, packet);
        if (res < 0) {
            printf("Ошибка при декодировании аудиокадра.\n");
            break;
        }

        while (res >= 0) {
            res = avcodec_receive_frame(pcodectx, pframe);
            if (res == AVERROR(EAGAIN)) {
                break;
            } else if (res == AVERROR_EOF) {
                break;
            } else if (res >= 0) {
                int outsamples = swr_convert(swrctx, &buf, pcodectx->frame_size, (const uint8_t **)pframe->data, pframe->nb_samples);
                snd_pcm_write(pcm_handle, buf, outsamples);
            }
        }
    }
}

Теперь я хочу добавить изменение громкости в этот аудиоплеер.
Я обнаружил, что в FFmpeg есть функции AVfilter, которые можно использовать для настройки громкости аудио. Как я могу использовать это в текущем дизайне (где следует добавить фильтры в текущий код)?

Ответ или решение

Для того, чтобы добавить управление громкостью в ваш аудиоплеер на базе FFmpeg и ALSA, вам необходимо использовать API AVFilter. Это позволяет вам интегрировать фильтры, такие как volume, в процесс обработки аудио. Ниже приведены шаги, которые помогут вам этот процесс реализовать.

Подготовка к использованию AVFilter

  1. Инициализация библиотеки фильтров: Перед использованием AVFilter, необходимо инициализировать библиотеку и создать необходимые компоненты, такие как граф фильтров.

    avfilter_register_all();
  2. Создание графа фильтров: Вы создадите граф фильтров с использованием структуры AVFilterGraph.

    AVFilterGraph *filter_graph = avfilter_graph_alloc();
  3. Создание фильтров: Добавьте фильтры в граф. Для изменения громкости вам понадобится фильтр volume.

    AVFilterContext *src = NULL;
    AVFilterContext *sink = NULL;
    
    // Создание фильтра источника
    avfilter_graph_create_filter(&src, avfilter_get_by_name("abuffer"),
                                  "in", "sample_rate=44100:channels=2:sample_fmt=s16", NULL, filter_graph);
    
    // Создание фильтра волюма
    avfilter_graph_create_filter(&volume_filter, avfilter_get_by_name("volume"),
                                 "volume", "2", NULL, filter_graph);
    
    // Создание фильтра приёмника
    avfilter_graph_create_filter(&sink, avfilter_get_by_name("abuffersink"),
                                  "out", NULL, NULL, filter_graph);
  4. Соединение фильтров: Вам нужно установить соединения между созданными фильтрами.

    avfilter_link(src, 0, volume_filter, 0);
    avfilter_link(volume_filter, 0, sink, 0);
  5. Настройка графа фильтров: После создания и соединения фильтров вы должны настроить граф.

    avfilter_graph_config(filter_graph, NULL);

Интеграция в цикл воспроизведения

Теперь вам нужно интегрировать созданный граф фильтров в ваш существующий цикл decode_play. В этом коде вы будете передавать декодированные аудиофреймы через граф фильтров.

while (1) {
    // Чтение аудиофрейма
    if (av_read_frame(pfmtctx, packet) < 0) {
        avcodec_flush_buffers(pcodectx);
        printf("Got end of media, breaking\n");
        break;
    }
    if (packet->stream_index != stream) {
        continue;
    }

    int res = avcodec_send_packet(pcodectx, packet);
    if (res < 0) {
        printf("Error in decoding audio frame.\n");
        break;
    }

    while (res >= 0) {
        res = avcodec_receive_frame(pcodectx, pframe);
        if (res == AVERROR(EAGAIN)) {
            break;
        } else if (res == AVERROR_EOF) {
            break;
        } else if (res >= 0) {
            // Подготовка буфера
            int outsamples = swr_convert(swrctx, &buf, pcodectx->frame_size, (const uint8_t **)pframe->data, pframe->nb_samples);

            // Передача пакета звука в граф фильтров
            av_buffersrc_add_frame(src, pframe);
            AVFrame *filtered_frame = av_frame_alloc();
            av_buffersink_get_frame(sink, filtered_frame);

            // Запись отсчитанных кадров в PCM
            snd_pcm_write(pcm_handle, filtered_frame->data[0], outsamples);

            av_frame_free(&filtered_frame);
        }
    }
}

Заключение

Этот подход позволит вам добавить возможность управления громкостью в ваш аудиоплеер на базе FFmpeg и ALSA, используя AVFilter API. Убедитесь в том, что вы корректно обрабатываете все ошибки и освобождаете выделенную память, чтобы предотвратить утечки. Надеюсь, это руководство поможет вам в интеграции фильтра громкости в ваше приложение. Не стесняйтесь задавать вопросы по ходу реализации!

Оцените материал
Добавить комментарий

Капча загружается...