c++ ffmpeg结合opencv推流

c++ 利用ffmpeg推流的一个简单的demo实现代码。

#include "pushStream.h"

void initialize_avformat_context(AVFormatContext *&fctx, const char *format_name)
{
  int ret = avformat_alloc_output_context2(&fctx, nullptr, format_name, nullptr);
  if (ret < 0)
  {
    std::cout << "Could not allocate output format context!" << std::endl;
    exit(1);
  }
}

void initialize_io_context(AVFormatContext *&fctx, const char *output)
{
  if (!(fctx->oformat->flags & AVFMT_NOFILE))
  {
    int ret = avio_open2(&fctx->pb, output, AVIO_FLAG_WRITE, nullptr, nullptr);
    if (ret < 0)
    {
      std::cout << "Could not open output IO context!" << std::endl;
      exit(1);
    }
  }
}

void set_codec_params(AVFormatContext *&fctx, AVCodecContext *&codec_ctx, double width, double height, int fps, int bitrate)
{
  const AVRational dst_fps = {fps, 1};

  codec_ctx->codec_tag = 0;
  codec_ctx->codec_id = AV_CODEC_ID_H264;
  codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
  codec_ctx->width = width;
  codec_ctx->height = height;
  codec_ctx->gop_size = 12;
  codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
  codec_ctx->framerate = dst_fps;
  codec_ctx->time_base = av_inv_q(dst_fps);
  codec_ctx->bit_rate = bitrate;
  if (fctx->oformat->flags & AVFMT_GLOBALHEADER)
  {
    codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
  }
}

void initialize_codec_stream(AVStream *&stream, AVCodecContext *&codec_ctx, const AVCodec *&codec, std::string codec_profile)
{
  int ret = avcodec_parameters_from_context(stream->codecpar, codec_ctx);
  if (ret < 0)
  {
    std::cout << "Could not initialize stream codec parameters!" << std::endl;
    exit(1);
  }

  AVDictionary *codec_options = nullptr;
  av_dict_set(&codec_options, "profile", codec_profile.c_str(), 0);
  av_dict_set(&codec_options, "preset", "superfast", 0);
  av_dict_set(&codec_options, "tune", "zerolatency", 0);

  // open video encoder
  ret = avcodec_open2(codec_ctx, codec, &codec_options);
  if (ret < 0)
  {
    std::cout << "Could not open video encoder!" << std::endl;
    exit(1);
  }
}

SwsContext *initialize_sample_scaler(AVCodecContext *codec_ctx, double width, double height)
{
  SwsContext *swsctx = sws_getContext(width, height, AV_PIX_FMT_BGR24, width, height, codec_ctx->pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr);
  if (!swsctx)
  {
    std::cout << "Could not initialize sample scaler!" << std::endl;
    exit(1);
  }

  return swsctx;
}

AVFrame *allocate_frame_buffer(AVCodecContext *codec_ctx, double width, double height)
{
  AVFrame *frame = av_frame_alloc();
  int i = av_image_get_buffer_size(codec_ctx->pix_fmt, width, height, 1);
  uint8_t *framebuf = new uint8_t[i];

  av_image_fill_arrays(frame->data, frame->linesize, framebuf, codec_ctx->pix_fmt, width, height, 1);
  frame->width = width;
  frame->height = height;
  frame->format = static_cast<int>(codec_ctx->pix_fmt);

  return frame;
}

void write_frame(AVCodecContext *codec_ctx, AVFormatContext *fmt_ctx, AVFrame *frame)
{
  AVPacket pkt = {0};
  av_new_packet(&pkt, 0);

  int ret = avcodec_send_frame(codec_ctx, frame);
  if (ret < 0)
  {
    std::cout << "Error sending frame to codec context!" << std::endl;
    exit(1);
  }

  ret = avcodec_receive_packet(codec_ctx, &pkt);
  if (ret < 0)
  {
    std::cout << "Error receiving packet from codec context!" << std::endl;
    exit(1);
  }

  av_interleaved_write_frame(fmt_ctx, &pkt);
  av_packet_unref(&pkt);
}

void push_stream(int bitrate, std::string& codec_profile, std::string& source_rtsp, std::string& target_rtmp, std::queue<std::vector<FrameBox>>* frameBoxs)
{
    std::cout << "start push stream\n";
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
    av_register_all();
#endif
    avformat_network_init();

    const char *output = target_rtmp.c_str();
    int ret;
    // CAP_FFMPEG:使用ffmpeg解码
    cv::VideoCapture cam = cv::VideoCapture(source_rtsp, cv::CAP_FFMPEG);              //使用opencv打开rtsp流
    if (!cam.isOpened()) {
        std::cout << "取流失败\n";
        exit(1);
    }
  
    int fps = int(cam.get(cv::CAP_PROP_FPS));                                          //取得rtsp流帧率
    double width = cam.get(cv::CAP_PROP_FRAME_WIDTH);                                  //取得rtsp流图像宽度
    double height = cam.get(cv::CAP_PROP_FRAME_HEIGHT);                                //取得rtsp流图像高度
  
    std::vector<uint8_t> imgbuf(height * width * 3 + 16);
    cv::Mat image(height, width, CV_8UC3, imgbuf.data(), width * 3);
    AVFormatContext *ofmt_ctx = nullptr;
    const AVCodec *out_codec = nullptr;
    AVStream *out_stream = nullptr;
    AVCodecContext *out_codec_ctx = nullptr;
  
    initialize_avformat_context(ofmt_ctx, "flv");
    initialize_io_context(ofmt_ctx, output);
  
    out_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    out_stream = avformat_new_stream(ofmt_ctx, out_codec);
    out_codec_ctx = avcodec_alloc_context3(out_codec);
  
    set_codec_params(ofmt_ctx, out_codec_ctx, width, height, fps, bitrate);
    initialize_codec_stream(out_stream, out_codec_ctx, out_codec, codec_profile);
  
    out_stream->codecpar->extradata = out_codec_ctx->extradata;
    out_stream->codecpar->extradata_size = out_codec_ctx->extradata_size;
  
    av_dump_format(ofmt_ctx, 0, output, 1);
  
    auto *swsctx = initialize_sample_scaler(out_codec_ctx, width, height);
    auto *frame = allocate_frame_buffer(out_codec_ctx, width, height);
  
    int cur_size;
    uint8_t *cur_ptr;
  
    ret = avformat_write_header(ofmt_ctx, nullptr);
    if (ret < 0)
    {
      std::cout << "Could not write header!" << std::endl;
      exit(1);
    }
    clock_t start, end;
    while(true)
    {
        start = clock();
        cam >> image;
        const int stride[] = {static_cast<int>(image.step[0])};
        sws_scale(swsctx, &image.data, stride, 0, image.rows, frame->data, frame->linesize);
        frame->pts += av_rescale_q(1, out_codec_ctx->time_base, out_stream->time_base);
        write_frame(out_codec_ctx, ofmt_ctx, frame);
        end = clock();
        std::cout << "one frame time:" << double(end - start)/ CLOCKS_PER_SEC << "\r";
    }
  
    av_write_trailer(ofmt_ctx);
    av_frame_free(&frame);
    avcodec_close(out_codec_ctx);
    avio_close(ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要使用FFmpegOpenCV推流,可以按照以下步骤进行操作: 1. 安装FFmpegOpenCV 首先需要安装FFmpegOpenCV。可以在官网下载源码然后编译安装,也可以通过包管理器进行安装。 2. 准备要推流的视频 要推流的视频可以是本地视频文件,也可以是通过摄像头捕获的实时视频流。如果是本地视频文件,可以使用FFmpeg打开文件,并从文件中读取视频帧。如果是实时视频流,则需要使用OpenCV捕获摄像头并获取每个视频帧。 3. 对视频进行处理 如果需要对视频进行处理,例如裁剪、缩放、滤镜等,则可以使用OpenCV对每个视频帧进行处理。 4. 使用FFmpeg将视频帧推流 最后,使用FFmpeg将视频帧推送到指定的服务器或平台。可以使用命令行或编程方式调用FFmpeg进行推流。 以下是一个使用FFmpegOpenCV推流的Python示例代码: ``` import cv2 import subprocess # 准备要推流的视频 cap = cv2.VideoCapture('test.mp4') # 打开FFmpeg进程 ffmpeg = subprocess.Popen([ 'ffmpeg', '-re', '-i', '-', '-c:v', 'libx264', '-preset', 'ultrafast', '-f', 'flv', 'rtmp://example.com/live/stream' ], stdin=subprocess.PIPE) # 推送视频帧 while True: ret, frame = cap.read() if not ret: break # 对视频进行处理 frame = cv2.resize(frame, (640, 480)) # 将视频帧写入FFmpeg进程 ffmpeg.stdin.write(frame.tobytes()) # 关闭FFmpeg进程 ffmpeg.stdin.close() ffmpeg.wait() # 释放资源 cap.release() ``` 在上面的示例中,首先使用OpenCV打开要推流的视频。然后使用FFmpeg打开一个推流进程,并将视频帧通过管道写入FFmpeg进程。最后,关闭FFmpeg进程和释放资源。 请注意,这只是一个示例,实际使用中可能需要根据具体情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值