📜  ffmpeg 结合音频和视频 (1)

📅  最后修改于: 2023-12-03 15:30:45.346000             🧑  作者: Mango

FFMPEG结合音频和视频

FFMPEG是一个免费的开源跨平台音视频处理工具,它可以处理各种各样的音频或视频文件。在本文中,我们将介绍如何使用FFMPEG结合音频和视频。

如何安装FFMPEG

FFMPEG可以在Windows、Linux和Mac OS X等多平台运行。安装步骤如下:

Windows
  1. 下载Windows版本的FFMPEG:https://ffmpeg.org/download.html#build-windows
  2. 将下载的文件解压到任意文件夹中
  3. 把解压后的文件夹的路径加入到系统的PATH变量中
Linux

在终端中输入以下命令:

sudo apt-get install ffmpeg
Mac OS X

在终端中输入以下命令:

brew install ffmpeg
如何使用FFMPEG结合音频和视频

使用FFMPEG结合音频和视频有以下两种方式:

方式一:使用命令行

在命令行中输入以下命令:

ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -c:a copy output.mp4

这将从“video.mp4”和“audio.mp3”中提取视频和音频流并将它们结合在一起。最后的文件名为“output.mp4”(你可以将其替换为你想要的任何文件名),该文件将包含合并的音频和视频流。

方式二:使用FFMPEG库

如果你在使用FFMPEG的应用程序中结合音频和视频,你可以使用FFMPEG库。以下是一个用C ++示例:

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>

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

int main()
{
    const char* videoFilePath = "video.mp4";
    const char* audioFilePath = "audio.mp3";
    const char* outputFilePath = "output.mp4";
    std::string error;

    av_register_all();

    AVFormatContext* videoFormatCtx = NULL;
    if (avformat_open_input(&videoFormatCtx, videoFilePath, NULL, NULL) != 0)
    {
        error = "Could not open video input file";
        goto bail;
    }

    if (avformat_find_stream_info(videoFormatCtx, NULL) < 0)
    {
        error = "Could not find video stream info";
        goto bail;
    }

    int videoStreamIndex = -1;
    AVStream* videoStream = NULL;
    for (unsigned int i = 0; i < videoFormatCtx->nb_streams; i++)
    {
        auto stream = videoFormatCtx->streams[i];
        if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStreamIndex = i;
            videoStream = stream;
            break;
        }
    }

    if (videoStreamIndex == -1 || videoStream == NULL)
    {
        error = "Could not find video stream";
        goto bail;
    }

    AVFormatContext* audioFormatCtx = NULL;
    if (avformat_open_input(&audioFormatCtx, audioFilePath, NULL, NULL) != 0)
    {
        error = "Could not open audio input file";
        goto bail;
    }

    if (avformat_find_stream_info(audioFormatCtx, NULL) < 0)
    {
        error = "Could not find audio stream info";
        goto bail;
    }

    int audioStreamIndex = -1;
    AVStream* audioStream = NULL;
    for (unsigned int i = 0; i < audioFormatCtx->nb_streams; i++)
    {
        auto stream = audioFormatCtx->streams[i];
        if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audioStreamIndex = i;
            audioStream = stream;
            break;
        }
    }

    if (audioStreamIndex == -1 || audioStream == NULL)
    {
        error = "Could not find audio stream";
        goto bail;
    }

    AVFormatContext* outputFormatCtx = NULL;
    int outputWidth = videoStream->codecpar->width;
    int outputHeight = videoStream->codecpar->height;
    AVRational outputTimeBase = videoStream->time_base;

    std::remove(outputFilePath);
    if (avformat_alloc_output_context2(&outputFormatCtx, NULL, NULL, outputFilePath) < 0)
    {
        error = "Could not allocate output format context";
        goto bail;
    }

    AVOutputFormat* outputFormat = outputFormatCtx->oformat;

    AVCodecContext* videoCodecCtx = avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(videoCodecCtx, videoStream->codecpar);
    videoCodecCtx->codec_tag = 0;
    videoCodecCtx->codec_id = outputFormat->video_codec;
    videoCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    videoCodecCtx->bit_rate = videoStream->codecpar->bit_rate;
    videoCodecCtx->width = outputWidth;
    videoCodecCtx->height = outputHeight;
    videoCodecCtx->time_base = outputTimeBase;

    AVCodecContext* audioCodecCtx = avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(audioCodecCtx, audioStream->codecpar);
    audioCodecCtx->codec_tag = 0;
    audioCodecCtx->codec_id = outputFormat->audio_codec;
    audioCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO;

    if (avformat_new_stream(outputFormatCtx, NULL) == NULL)
    {
        error = "Could not create output stream";
        goto bail;
    }

    AVStream* outputStream = outputFormatCtx->streams[0];
    if (avcodec_parameters_from_context(outputStream->codecpar, videoCodecCtx) < 0)
    {
        error = "Could not set stream parameters for video codec";
        goto bail;
    }

    if (avcodec_parameters_from_context(outputStream->codecpar, audioCodecCtx) < 0)
    {
        error = "Could not set stream parameters for audio codec";
        goto bail;
    }

    if (avio_open2(&outputFormatCtx->pb, outputFilePath, AVIO_FLAG_WRITE, NULL, NULL) < 0)
    {
        error = "Could not open output file";
        goto bail;
    }

    if (avformat_write_header(outputFormatCtx, NULL) < 0)
    {
        error = "Could not write output file header";
        goto bail;
    }

    AVPacket pkt;
    while (true)
    {
        if (av_read_frame(videoFormatCtx, &pkt) < 0)
        {
            break;
        }

        if (pkt.stream_index == videoStreamIndex)
        {
            av_packet_rescale_ts(&pkt, videoStream->time_base, outputTimeBase);

            if (av_interleaved_write_frame(outputFormatCtx, &pkt) < 0)
            {
                error = "Could not write video frame to output file";
                goto bail;
            }
        }

        av_packet_unref(&pkt);
    }

    while (true)
    {
        if (av_read_frame(audioFormatCtx, &pkt) < 0)
        {
            break;
        }

        if (pkt.stream_index == audioStreamIndex)
        {
            av_packet_rescale_ts(&pkt, audioStream->time_base, outputTimeBase);

            if (av_interleaved_write_frame(outputFormatCtx, &pkt) < 0)
            {
                error = "Could not write audio frame to output file";
                goto bail;
            }
        }

        av_packet_unref(&pkt);
    }

    if (av_write_trailer(outputFormatCtx) < 0)
    {
        error = "Could not write output file trailer";
    }

bail:
    if (!error.empty())
    {
        std::cerr << error << std::endl;
        return -1;
    }

    return 0;
}

这个程序将从“video.mp4”和“audio.mp3”中提取视频和音频流并将它们结合在一起。最后的文件名为“output.mp4”(你可以将其替换为你想要的任何文件名),该文件将包含合并的音频和视频流。

结论

FFMPEG是一个功能强大的音视频处理工具,它支持各种各样的格式,可以应用于多种场景。本文介绍了如何使用FFMPEG结合音频和视频以及如何安装FFMPEG。如果你对FFMPEG感兴趣,你可以深入研究相关的文档、教程和示例程序。