说明:

该代码只是一个简单的示例,仅演示了在 C++ 中如何使用FFmpeg库进行音视频编解码,实现了一个简单的视频解码器,用于将视频文件解码为原始视频帧数据。它打开一个输入文件(input.mp4),查找视频流并获取相关的流信息。然后找到对应的视频解码器并打开解码器。代码通过循环读取视频帧,并将每个视频帧解码后写入输出文件(output.yuv)。在处理解码后的帧数据时,代码只是简单地将原始视频帧写入输出文件。
需要注意的是,该示例只处理视频流,而没有处理音频流。如果你需要处理音频流,你需要根据具体需求进行相应的修改。

源码展示


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

int main() {
    // 注册所有的FFmpeg组件
    av_register_all();

    std::string inputFilePath = "input.mp4";
    std::string outputFilePath = "output.yuv";

    // 打开输入文件
    AVFormatContext* formatContext = nullptr;
    if (avformat_open_input(&formatContext, inputFilePath.c_str(), nullptr, nullptr) != 0) {
        std::cerr << "无法打开输入文件" << std::endl;
        return -1;
    }

    // 获取流信息
    if (avformat_find_stream_info(formatContext, nullptr) < 0) {
        std::cerr << "无法获取流信息" << std::endl;
        avformat_close_input(&formatContext);
        return -1;
    }

    int videoStreamIndex = -1;
    AVCodecContext* videoCodecContext = nullptr;

    // 查找视频流索引和解码器
    for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
        if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            AVCodec* codec = avcodec_find_decoder(formatContext->streams[i]->codecpar->codec_id);
            if (!codec) {
                std::cerr << "无法找到视频解码器" << std::endl;
                avformat_close_input(&formatContext);
                return -1;
            }
            videoCodecContext = avcodec_alloc_context3(codec);
            avcodec_parameters_to_context(videoCodecContext, formatContext->streams[i]->codecpar);
            if (avcodec_open2(videoCodecContext, codec, nullptr) < 0) {
                std::cerr << "无法打开视频解码器" << std::endl;
                avcodec_free_context(&videoCodecContext);
                avformat_close_input(&formatContext);
                return -1;
            }
            break;
        }
    }

    // 创建输出文件
    FILE* outputFile = fopen(outputFilePath.c_str(), "wb");
    if (!outputFile) {
        std::cerr << "无法创建输出文件" << std::endl;
        avcodec_free_context(&videoCodecContext);
        avformat_close_input(&formatContext);
        return -1;
    }

    AVPacket packet;
    av_init_packet(&packet);
    packet.data = nullptr;
    packet.size = 0;

    // 读取视频帧并进行解码
    while (av_read_frame(formatContext, &packet) >= 0) {
        if (packet.stream_index == videoStreamIndex) {
            AVFrame* frame = av_frame_alloc();
            int response = avcodec_send_packet(videoCodecContext, &packet);
            if (response < 0) {
                std::cerr << "视频解码错误" << std::endl;
                av_frame_free(&frame);
                break;
            }
            while (response >= 0) {
                response = avcodec_receive_frame(videoCodecContext, frame);
                if (response == AVERROR(EAGAIN) || response == AVERROR_EOF)
                    break;
                else if (response < 0) {
                    std::cerr << "视频解码错误" << std::endl;
                    av_frame_free(&frame);
                    break;
                }

                // 处理解码后的帧数据
                fwrite(frame->data[0], 1, videoCodecContext->width * videoCodecContext->height, outputFile);

                av_frame_unref(frame);
            }
            av_frame_free(&frame);
        }
        av_packet_unref(&packet);
    }

    // 清理资源
    fclose(outputFile);
    avcodec_free_context(&videoCodecContext);
    avformat_close_input(&formatContext);

    return 0;
}

编译执行:
g++ -o test test.cpp -lavformat -lavcodec -lavutil
./test

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐