调整视频的分辨率

main.cpp

cpp 复制代码
extern "C" {
    #include <libavformat/avformat.h>
    #include <libavcodec/avcodec.h>
    #include <libavutil/avutil.h>
    #include <libavutil/imgutils.h>
    #include <libswscale/swscale.h>
}

#include <iostream>
#include <string>

int resize_video(const std::string &input_filename, const std::string &output_filename, int width, int height) {
    av_register_all();

    AVFormatContext *input_format_context = nullptr;
    if (avformat_open_input(&input_format_context, input_filename.c_str(), nullptr, nullptr) < 0) {
        std::cerr << "Could not open input file." << std::endl;
        return -1;
    }

    if (avformat_find_stream_info(input_format_context, nullptr) < 0) {
        std::cerr << "Could not find stream information." << std::endl;
        return -1;
    }

    AVCodec *decoder = nullptr;
    int video_stream_index = av_find_best_stream(input_format_context, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0);
    if (video_stream_index < 0) {
        std::cerr << "Could not find video stream in the input file." << std::endl;
        return -1;
    }

    AVCodecContext *decoder_context = avcodec_alloc_context3(decoder);
    if (!decoder_context) {
        std::cerr << "Could not allocate decoder context." << std::endl;
        return -1;
    }

    if (avcodec_parameters_to_context(decoder_context, input_format_context->streams[video_stream_index]->codecpar) < 0) {
        std::cerr << "Could not copy decoder parameters to decoder context." << std::endl;
        return -1;
    }

    if (avcodec_open2(decoder_context, decoder, nullptr) < 0) {
        std::cerr << "Could not open decoder." << std::endl;
        return -1;
    }

    AVFormatContext *output_format_context = nullptr;
    if (avformat_alloc_output_context2(&output_format_context, nullptr, nullptr, output_filename.c_str()) < 0) {
        std::cerr << "Could not create output context." << std::endl;
        return -1;
    }

    AVStream *output_stream = avformat_new_stream(output_format_context, nullptr);
    if (!output_stream) {
        std::cerr << "Failed to allocate output stream." << std::endl;
        return -1;
    }

    AVCodec *encoder = avcodec_find_encoder(decoder_context->codec_id);
    if (!encoder) {
        std::cerr << "Necessary encoder not found." << std::endl;
        return -1;
    }

    AVCodecContext *encoder_context = avcodec_alloc_context3(encoder);
    if (!encoder_context) {
        std::cerr << "Could not allocate encoder context." << std::endl;
        return -1;
    }

    encoder_context->height = height;
    encoder_context->width = width;
    encoder_context->sample_aspect_ratio = decoder_context->sample_aspect_ratio;
    encoder_context->pix_fmt = encoder->pix_fmts[0];
    encoder_context->time_base = av_inv_q(decoder_context->framerate);

    if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
        encoder_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    }

    if (avcodec_open2(encoder_context, encoder, nullptr) < 0) {
        std::cerr << "Could not open encoder." << std::endl;
        return -1;
    }

    if (avcodec_parameters_from_context(output_stream->codecpar, encoder_context) < 0) {
        std::cerr << "Could not copy encoder parameters to output stream." << std::endl;
        return -1;
    }

    output_stream->time_base = encoder_context->time_base;

    if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
        if (avio_open(&output_format_context->pb, output_filename.c_str(), AVIO_FLAG_WRITE) < 0) {
            std::cerr << "Could not open output file." << std::endl;
            return -1;
        }
    }

    if (avformat_write_header(output_format_context, nullptr) < 0) {
        std::cerr << "Error occurred when opening output file." << std::endl;
        return -1;
    }

    AVFrame *frame = av_frame_alloc();
    AVFrame *sws_frame = av_frame_alloc();
    if (!frame || !sws_frame) {
        std::cerr << "Could not allocate frame." << std::endl;
        return -1;
    }

    sws_frame->format = encoder_context->pix_fmt;
    sws_frame->width = encoder_context->width;
    sws_frame->height = encoder_context->height;

    if (av_image_alloc(sws_frame->data, sws_frame->linesize, width, height, encoder_context->pix_fmt, 32) < 0) {
        std::cerr << "Could not allocate destination image." << std::endl;
        return -1;
    }

    SwsContext *sws_context = sws_getContext(
        decoder_context->width, decoder_context->height, decoder_context->pix_fmt,
        width, height, encoder_context->pix_fmt,
        SWS_BILINEAR, nullptr, nullptr, nullptr
    );

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

    while (av_read_frame(input_format_context, &packet) >= 0) {
        if (packet.stream_index == video_stream_index) {
            if (avcodec_send_packet(decoder_context, &packet) == 0) {
                while (avcodec_receive_frame(decoder_context, frame) == 0) {
                    sws_scale(sws_context, frame->data, frame->linesize, 0, frame->height, sws_frame->data, sws_frame->linesize);
                    sws_frame->pts = frame->pts;
                    if (avcodec_send_frame(encoder_context, sws_frame) == 0) {
                        AVPacket encoded_packet;
                        av_init_packet(&encoded_packet);
                        encoded_packet.data = nullptr;
                        encoded_packet.size = 0;
                        while (avcodec_receive_packet(encoder_context, &encoded_packet) == 0) {
                            av_interleaved_write_frame(output_format_context, &encoded_packet);
                            av_packet_unref(&encoded_packet);
                        }
                    }
                }
            }
        }
        av_packet_unref(&packet);
    }

    av_write_trailer(output_format_context);

    avcodec_close(decoder_context);
    avcodec_close(encoder_context);
    avformat_close_input(&input_format_context);
    if (output_format_context && !(output_format_context->oformat->flags & AVFMT_NOFILE)) {
        avio_closep(&output_format_context->pb);
    }
    avformat_free_context(output_format_context);
    av_frame_free(&frame);
    av_frame_free(&sws_frame);
    sws_freeContext(sws_context);

    return 0;
}

int main(int argc, char *argv[]) {
    if (argc < 5) {
        std::cerr << "Usage: " << argv[0] << " <input file> <output file> <width> <height>" << std::endl;
        return -1;
    }

    std::string input_filename = argv[1];
    std::string output_filename = argv[2];
    int width = std::stoi(argv[3]);
    int height = std::stoi(argv[4]);

    if (resize_video(input_filename, output_filename, width, height) == 0) {
        std::cout << "Video resized successfully." << std::endl;
    } else {
        std::cout << "Failed to resize video." << std::endl;
    }

    return 0;
}

代码解释

  1. 初始化 FFmpeg :使用 av_register_all() 初始化 FFmpeg 库。
  2. 打开输入文件 :使用 avformat_open_input() 打开输入文件,并获取输入文件的格式上下文。
  3. 查找视频流 :使用 av_find_best_stream() 查找输入文件中的视频流,并获取其解码器和解码器上下文。
  4. 打开解码器 :使用 avcodec_open2() 打开解码器。
  5. 创建输出文件上下文 :使用 avformat_alloc_output_context2() 创建输出文件的格式上下文。
  6. 创建输出流并初始化编码器:为输出文件创建一个新的流,并为其分配编码器上下文。设置编码器上下文的宽度、高度、像素格式和时间基准。
  7. 打开编码器 :使用 avcodec_open2() 打开编码器。
  8. 写入文件头 :使用 avformat_write_header() 将文件头写入输出文件。
  9. 初始化 SWS 上下文 :使用 sws_getContext() 初始化 SWS 上下文,用于缩放图像。
  10. 读取和处理帧:循环读取输入文件中的每个帧,缩放帧,并将其发送到编码器,然后将编码后的帧写入输出文件。
  11. 写入文件尾 :使用 av_write_trailer() 写入输出文件的文件尾。
  12. 清理资源:关闭解码器和编码器,关闭输入和输出文件,并释放所有分配的资源。
相关推荐
做人不要太理性10 分钟前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.19 分钟前
2、桥接模式
c++·桥接模式
chnming198723 分钟前
STL关联式容器之map
开发语言·c++
程序伍六七36 分钟前
day16
开发语言·c++
小陈phd1 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
火山口车神丶1 小时前
某车企ASW面试笔试题
c++·matlab
runing_an_min2 小时前
ffmpeg视频滤镜:替换部分帧-freezeframes
ffmpeg·音视频·freezeframes
是阿建吖!2 小时前
【优选算法】二分查找
c++·算法
ruizhenggang2 小时前
ffmpeg本地编译不容易发现的问题 — Error:xxxxx not found!
ffmpeg
Ajiang28247353044 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++