请选择 进入手机版 | 继续访问电脑版

ChinaFFmpeg

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7215|回复: 4

我想将内存里的RGB或者YUV图片用FFMPEG编码,然后用rtsp推流

[复制链接]
发表于 2019-5-6 14:48:16 | 显示全部楼层 |阅读模式
[C++] 纯文本查看 复制代码
int RGB2RTSP(Mat frame, const int WIDTH, const int HEIGHT, const int FPS)
{
//    namedWindow("video");
    //获取视频帧的尺寸
    int inWidth  = WIDTH;
    int inHeight = HEIGHT;
    int fps = FPS;
    //输出封装器和视频流配置
//    fmtctx = avformat_alloc_context();
//    //Guess Format
//    fmt = av_guess_format(NULL, outUrl, NULL);
//    fmtctx->oformat = fmt;

    ret = avformat_alloc_output_context2(&fmtctx, NULL, "h264", outUrl);
    fmt = fmtctx->oformat;
    if(!fmtctx)
    {
       printf("output error\n");
       return -1;
    }

    //   fmt = av_guess_format(NULL, outUrl, NULL);
    //   fmtctx->oformat = fmt;
    //   printf("output format %s\n",fmt);
    //添加视频流   视音频流对应的结构体,用于视音频编解码。
    //找到编码器
    avcodec_alloc_context3(video_codec);
    video_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (!video_codec)
    {
       printf("Can`t find h264 encoder!");
    }
    AVStream *video_st = avformat_new_stream(fmtctx, 0);
    if (video_st == NULL)
    {
       printf("avformat_new_stream failed");
    }
//    video_st->id = fmtctx->nb_streams-1;  //add
    //附加标志,这个一定要设置
    video_st->codecpar->codec_tag = 0;
    if (fmtctx->oformat->flags & AVFMT_GLOBALHEADER)
               video_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
    //从编码器复制参数
    av_dump_format(fmtctx, 0, outUrl, 1);

    //Open output URL
    if (!(fmtctx->flags & AVFMT_NOFILE))
    {
       ret = avio_open(&fmtctx->pb,outUrl, AVIO_FLAG_WRITE);
       if(ret < 0)
       {
           printf("Failed to open output file! \n");
           return -1;
       }
    }
    //写入封装头
    if(avformat_write_header(fmtctx, NULL) < 0)
    {
       printf("write header failed\n");
       return -1;
    }
    //初始化编码
    //   c = video_st->codec;

    //创建编码器
    c = avcodec_alloc_context3(video_codec);
    if (!c)
    {
       printf("avcodec_alloc_context3 failed!");
    }
    //配置编码器参数
    c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //全局参数
    c->codec_id = video_codec->id;
    c->codec_type = AVMEDIA_TYPE_VIDEO;
    c->thread_count = 8;
    c->bit_rate = 50 * 1024 * 8;//压缩后每秒视频的bit位大小 50kB
    c->width = inWidth;
    c->height = inHeight;
    c->pix_fmt = AV_PIX_FMT_YUV420P;
    c->time_base = { 1,fps };
    c->framerate = { fps,1 };
    //画面组的大小,多少帧一个关键帧
    c->gop_size = 10;
    c->max_b_frames = 3;

    c->qmin = 10;
    c->qmax = 51;

    // Set Option
    AVDictionary *param = 0;
    //H.264
    av_dict_set(¶m, "preset", "slow", 0);
    av_dict_set(¶m, "tune", "zerolatency", 0);

    //打开编码器
    if(avcodec_open2(c, video_codec, ¶m) < 0)
    {
       printf("Failed to open encoder! \n");
       return -1;
    }
    printf("avcodec_open2 success!\n");

    //   int vpts = 0;

//    imshow("video", frame);
//    waitKey(1);

    //初始化格式转换上下文
    vsc = sws_getCachedContext(vsc,
       inWidth, inHeight, AV_PIX_FMT_BGR24,     //源宽、高、像素格式
       inWidth, inHeight, AV_PIX_FMT_YUV420P,//目标宽、高、像素格式
       SWS_BICUBIC,  // 尺寸变化使用算法
       0, 0, 0
    );
    if (!vsc)
    {
       printf("sws_getCachedContext failed!");
    }
    //初始化输出的数据结构。未压缩的数据
    yuv = av_frame_alloc();
    yuv->format = AV_PIX_FMT_YUV420P;
    yuv->width = inWidth;
    yuv->height = inHeight;
    yuv->pts = 0;
    //分配yuv空间
    ret = av_frame_get_buffer(yuv, 32);
    picture_size = avpicture_get_size(AV_PIX_FMT_YUV420P, OUTWIDTH, OUTHEIGHT);
    uint8_t* picture_buf = (uint8_t *)av_malloc(picture_size);
    avpicture_fill((AVPicture *)yuv, picture_buf, c->pix_fmt, c->width, c->height);
    ///rgb to yuv
    //输入的数据结构
    uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
    //indata[0] bgrbgrbgr
    //plane indata[0] bbbbb indata[1]ggggg indata[2]rrrrr
    indata[0] = frame.data;
    int insize[AV_NUM_DATA_POINTERS] = { 0 };
    //一行(宽)数据的字节数
    insize[0] = frame.cols * frame.elemSize();
    int h = sws_scale(vsc, indata, insize, 0, frame.rows, //源数据
       yuv->data, yuv->linesize);
    if (h <= 0)
    {
       printf("transmode error");
       return 1;
    }
    //cout << h << " " << flush;
    //存储压缩数据(视频对应H.264等码流数据,音频对应AAC/MP3等码流数据)
    //   pack = av_packet_alloc();
    av_new_packet(&pkt, picture_size);

    ///h264编码
    yuv->pts = vpts;
    vpts++;
    int got_output;
    ret = avcodec_encode_video2(c, &pkt, yuv, &got_output);
    if(ret < 0)
    {
       printf("Failed to encode \n");
       return -1;
    }
    printf("ret: %i\n",ret);
    if(got_output == 1)
    {
       printf("encoded successed\n");
       waitKey();
       pkt.stream_index = video_st->index;
       ret = av_write_frame(fmtctx, &pkt);
       av_free_packet(&pkt);
    }

    //Flush Encoder
    //   ret = flush_encoder(fmtctx,0);
    //   if (ret < 0)
    //   {
    //       printf("Flushing encoder failed\n");
    //       return -1;
    //   }

    //Write file trailer
    av_write_trailer(fmtctx);
    if (video_st)
    {
       av_free(yuv);
       av_free(picture_buf);
    }
    //   ret = avcodec_send_frame(vc, yuv);
    //   if (ret != 0)
    //       return 1;

    //   ret = avcodec_receive_packet(vc, pack);
    //   if (ret == 0 || pack->size > 0)
    //   {
    //       printf("pack size: %d\n", pack->size);
    //   }
    //   else
    //   {
    //       printf("encoded error\n");
    //       return 1;
    //   }
    //   AVRational rate = {1, FPS};
    //   printf("pre pack pts: %d\n", pack->pts);
    //   printf("vc time_base: %d\n", vc->time_base);
    //   printf("vs time_base: %d\n", vs->time_base);
    //   //计算pts dts和duration。
    ////   pack.pts = av_rescale_q(pack.pts, vc->time_base, vs->time_base);
    //   pack->pts = av_rescale_q(pack->pts,rate,vs->time_base);
    //   printf("pack pts: %d\n", pack->pts);


    //   ret = av_interleaved_write_frame(ic, pack);
    ////   ret = av_write_frame(ic, &pack);
    //   if (ret == 0)
    //   {
    //       printf("#");
    //   }

    //   sws_freeContext(vsc);
    //   vsc = NULL;
    //   avio_closep(&ic->pb);
    //   avcodec_free_context(&vc);

    //getchar();
    return 0;
}
回复

使用道具 举报

 楼主| 发表于 2019-5-6 14:50:40 | 显示全部楼层
操作系统ubuntu16.04 ,FFMPEG版本3.4.4, 现在有两个问题,rtp输出流无法发布出去;然后就是编码后avcodec_encode_video2返回值为0
回复 支持 反对

使用道具 举报

发表于 2019-5-6 18:52:19 | 显示全部楼层
先编码成h264文件,不发出去,看看啥情况
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-5-8 18:17:13 | 显示全部楼层
孙悟空 发表于 2019-5-6 18:52
先编码成h264文件,不发出去,看看啥情况

我现在没有发布出去,把yuv图片编码为h264存在本地。运行的时候显示编码成功,然后卡在av_write_frame这个函数了
回复 支持 反对

使用道具 举报

发表于 2019-7-29 18:01:45 | 显示全部楼层
楼主你好,我最近也在做将YUV编码然后推流至rtsp服务器的项目,现在推流成功了,但有个bug,就是rtsp地址错误的话程序就会卡死,请问用什么方法能判断rtsp地址是否正确
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|Archiver|ChinaFFmpeg

GMT+8, 2024-3-29 21:16 , Processed in 0.054124 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表