【FFMPEG应用篇】基于FFmpeg的Windows摄像头采集到编码H264

发布时间:2024年01月09日
// 引入FFmpeg头文件
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <libavutil/opt.h>
}

int main() {
    av_register_all();  // 注册所有的格式和编解码器
    avformat_network_init();  // 初始化网络模块
    avdevice_register_all();
    // 使用FFmpeg采集摄像头视频
    AVFormatContext* pFormatCtx = avformat_alloc_context();
    AVInputFormat* pInputFmt = av_find_input_format("dshow");

    AVDictionary* options = nullptr;
    av_dict_set(&options, "video_size", "1280*720", 0);

    avformat_open_input(&pFormatCtx, "video=Integrated Camera", pInputFmt, &options);
    avformat_find_stream_info(pFormatCtx, nullptr);


    // 查找视频流
    int videoStreamIndex = -1;
    for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }

    // 初始化视频解码器
    AVCodecParameters* pCodecParams = pFormatCtx->streams[videoStreamIndex]->codecpar;
    AVCodec* pCodec = avcodec_find_decoder(pCodecParams->codec_id);
    AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
    avcodec_parameters_to_context(pCodecCtx, pCodecParams);
    avcodec_open2(pCodecCtx, pCodec, nullptr);

    // 初始化YUV转换
    struct SwsContext* pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
        pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P,
        SWS_BICUBIC, nullptr, nullptr, nullptr);

    // 初始化H264编码器
    AVCodec* pEncodec = avcodec_find_encoder_by_name("libx264");
    AVCodecContext* pEncodecCtx = avcodec_alloc_context3(pEncodec);
    pEncodecCtx->width = pCodecCtx->width;
    pEncodecCtx->height = pCodecCtx->height;
    pEncodecCtx->time_base = { 1, 25 };
    pEncodecCtx->rc_buffer_size = 4000000;
    pEncodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    av_opt_set(pEncodecCtx->priv_data, "preset", "ultrafast", 0);
    av_opt_set(pEncodecCtx->priv_data, "tune", "zerolatency", 0);
    avcodec_open2(pEncodecCtx, pEncodec, nullptr);

    // 初始化输出文件
    AVFormatContext* pOutFormatCtx = avformat_alloc_context();
    avformat_alloc_output_context2(&pOutFormatCtx, nullptr, nullptr, "output.h264");
    AVStream* pOutStream = avformat_new_stream(pOutFormatCtx, nullptr);
    avcodec_parameters_copy(pOutStream->codecpar, pCodecParams);
    avio_open(&pOutFormatCtx->pb, "output.h264", AVIO_FLAG_WRITE);
    avformat_write_header(pOutFormatCtx, nullptr);

    // 采集、解码、转换格式、编码、保存文件
    AVPacket packet;
    while (av_read_frame(pFormatCtx, &packet) >= 0) {
        if (packet.stream_index == videoStreamIndex) {
            avcodec_send_packet(pCodecCtx, &packet);
            AVFrame* pDecodedFrame = av_frame_alloc();
            int ret = avcodec_receive_frame(pCodecCtx, pDecodedFrame);
            if (ret >= 0) {
                AVFrame* pConvertedFrame = av_frame_alloc();
                pConvertedFrame->format = AV_PIX_FMT_YUV420P;
                pConvertedFrame->width = pCodecCtx->width;
                pConvertedFrame->height = pCodecCtx->height;
                av_frame_get_buffer(pConvertedFrame, 32);
                sws_scale(pSwsCtx, pDecodedFrame->data, pDecodedFrame->linesize, 0, pCodecCtx->height, pConvertedFrame->data, pConvertedFrame->linesize);
                av_packet_unref(&packet);
                av_init_packet(&packet);
                avcodec_send_frame(pEncodecCtx, pConvertedFrame);
                avcodec_receive_packet(pEncodecCtx, &packet);
                packet.stream_index = pOutStream->index;
                av_write_frame(pOutFormatCtx, &packet);
                av_frame_free(&pConvertedFrame);
            }
            av_frame_free(&pDecodedFrame);
        }
        av_packet_unref(&packet);
    }

    // 释放所占资源
    av_write_trailer(pOutFormatCtx);
    avformat_free_context(pOutFormatCtx);
    avcodec_close(pEncodecCtx);
    avcodec_free_context(&pEncodecCtx);
    sws_freeContext(pSwsCtx);
    avcodec_close(pCodecCtx);
    avcodec_free_context(&pCodecCtx);
    avformat_close_input(&pFormatCtx);
    avformat_network_deinit();

    return 0;
}

文章来源:https://blog.csdn.net/qq_40179458/article/details/135485390
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。