调整视频的分辨率

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. 清理资源:关闭解码器和编码器,关闭输入和输出文件,并释放所有分配的资源。
相关推荐
WG_173 分钟前
C++多态
开发语言·c++·面试
Charles Ray2 小时前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
重生之我在20年代敲代码2 小时前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
华清远见IT开放实验室4 小时前
【项目案例】物联网比较好的10+练手项目推荐,附项目文档/源码/视频
物联网·音视频
迷迭所归处7 小时前
C++ —— 关于vector
开发语言·c++·算法
CV工程师小林8 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
white__ice9 小时前
2024.9.19
c++
天玑y9 小时前
算法设计与分析(背包问题
c++·经验分享·笔记·学习·算法·leetcode·蓝桥杯
姜太公钓鲸2339 小时前
c++ static(详解)
开发语言·c++
菜菜想进步9 小时前
内存管理(C++版)
c语言·开发语言·c++