Skip to content

Instantly share code, notes, and snippets.

@elejke
Created February 20, 2025 12:52
Show Gist options
  • Save elejke/d9457acf45601bbb0fcc05c3ae7de1ef to your computer and use it in GitHub Desktop.
Save elejke/d9457acf45601bbb0fcc05c3ae7de1ef to your computer and use it in GitHub Desktop.

Для извлечения аудио из видео на C++ с использованием библиотеки FFmpeg, вот пример кода:

#include <iostream>
#include <fstream>

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
}

struct WAVHeader {
    uint8_t RIFF[4] = {'R','I','F','F'};
    uint32_t chunkSize;
    uint8_t WAVE[4] = {'W','A','V','E'};
    uint8_t fmt[4] = {'f','m','t',' '};
    uint32_t fmtSize = 16;
    uint16_t audioFormat = 1; // PCM
    uint16_t numChannels;
    uint32_t sampleRate;
    uint32_t byteRate;
    uint16_t blockAlign;
    uint16_t bitsPerSample;
    uint8_t data[4] = {'d','a','t','a'};
    uint32_t dataSize;
};

int main() {
    av_log_set_level(AV_LOG_ERROR);
    const char* inputFile = "input.mp4";
    const char* outputFile = "output.wav";

    // Инициализация FFmpeg
    AVFormatContext* formatContext = nullptr;
    if (avformat_open_input(&formatContext, inputFile, nullptr, nullptr) != 0) {
        std::cerr << "Ошибка открытия файла" << std::endl;
        return -1;
    }

    if (avformat_find_stream_info(formatContext, nullptr) < 0) {
        std::cerr << "Ошибка получения информации о потоке" << std::endl;
        return -1;
    }

    // Поиск аудио потока
    int audioStreamIndex = -1;
    AVCodecParameters* codecParams = nullptr;
    const AVCodec* codec = nullptr;
    for (int i = 0; i < formatContext->nb_streams; i++) {
        if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            audioStreamIndex = i;
            codecParams = formatContext->streams[i]->codecpar;
            break;
        }
    }

    if (audioStreamIndex == -1) {
        std::cerr << "Аудио поток не найден" << std::endl;
        return -1;
    }

    // Инициализация декодера
    codec = avcodec_find_decoder(codecParams->codec_id);
    if (!codec) {
        std::cerr << "Декодер не найден" << std::endl;
        return -1;
    }

    AVCodecContext* codecContext = avcodec_alloc_context3(codec);
    avcodec_parameters_to_context(codecContext, codecParams);
    if (avcodec_open2(codecContext, codec, nullptr) < 0) {
        std::cerr << "Ошибка открытия декодера" << std::endl;
        return -1;
    }

    // Настройка ресемплера
    SwrContext* swr = swr_alloc_set_opts(nullptr,
                                        AV_CH_LAYOUT_STEREO,
                                        AV_SAMPLE_FMT_S16,
                                        44100,
                                        codecContext->channel_layout,
                                        codecContext->sample_fmt,
                                        codecContext->sample_rate,
                                        0,
                                        nullptr);
    swr_init(swr);

    // Подготовка WAV заголовка
    WAVHeader wavHeader;
    wavHeader.numChannels = 2;
    wavHeader.sampleRate = 44100;
    wavHeader.bitsPerSample = 16;
    wavHeader.blockAlign = wavHeader.numChannels * wavHeader.bitsPerSample / 8;
    wavHeader.byteRate = wavHeader.sampleRate * wavHeader.blockAlign;

    std::ofstream outFile(outputFile, std::ios::binary);
    outFile.write(reinterpret_cast<char*>(&wavHeader), sizeof(WAVHeader));

    // Декодирование аудио
    AVPacket* packet = av_packet_alloc();
    AVFrame* frame = av_frame_alloc();
    uint32_t dataSize = 0;

    while (av_read_frame(formatContext, packet) >= 0) {
        if (packet->stream_index == audioStreamIndex) {
            avcodec_send_packet(codecContext, packet);
            while (avcodec_receive_frame(codecContext, frame) == 0) {
                // Ресемплинг аудио
                uint8_t* outputBuffer;
                av_samples_alloc(&outputBuffer, nullptr,
                                 wavHeader.numChannels,
                                 frame->nb_samples,
                                 AV_SAMPLE_FMT_S16, 0);
                int sampleCount = swr_convert(swr, &outputBuffer, frame->nb_samples,
                                             (const uint8_t**)frame->data, frame->nb_samples);

                // Запись аудио данных
                int dataLength = sampleCount * wavHeader.blockAlign;
                outFile.write(reinterpret_cast<char*>(outputBuffer), dataLength);
                dataSize += dataLength;
                av_freep(&outputBuffer);
            }
        }
        av_packet_unref(packet);
    }

    // Обновление WAV заголовка
    wavHeader.dataSize = dataSize;
    wavHeader.chunkSize = dataSize + sizeof(WAVHeader) - 8;
    outFile.seekp(0);
    outFile.write(reinterpret_cast<char*>(&wavHeader), sizeof(WAVHeader));
    outFile.close();

    // Очистка ресурсов
    av_frame_free(&frame);
    av_packet_free(&packet);
    avcodec_free_context(&codecContext);
    avformat_close_input(&formatContext);
    swr_free(&swr);

    std::cout << "Аудио успешно извлечено!" << std::endl;
    return 0;
}

Для компиляции и запуска:

  1. Установите FFmpeg (для Linux: sudo apt-get install libavformat-dev libavcodec-dev libswresample-dev)
  2. Скомпилируйте с флагами:
g++ -o extract_audio extract.cpp -lavformat -lavcodec -lswresample -lavutil
  1. Запустите с входным видеофайлом:
./extract_audio

Особенности:

  • Конвертирует аудио в стандартный WAV (16-bit, 44100 Hz, Stereo)
  • Использует аппаратный ресемплинг FFmpeg
  • Автоматически определяет аудио поток
  • Генерирует корректный WAV заголовок

Ограничения:

  • Работает только с поддерживаемыми FFmpeg кодеками
  • Для сложных случаев может потребоваться дополнительная обработка ошибок
  • Для MP3/других форматов потребуется изменение логики кодирования
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment