文本主要讲述windows系统下如何利用ffmpeg获取摄像机流并推送到rtmp服务,命令的用法前文

中有讲到过,这次是通过代码来实现。实现该项功能的基本流程如下:

图1 ffmpeg推流流程图

较前面的文章的流程图而言,本流程图显的复杂些,稍微解释下:

ffmpeg 打开摄像头跟打开普通的视频流方法一致,只是输入url是摄像头的名称。真正打开

摄像头操作由dshow来完成,ffmpeg只是调用dshow相应的接口获取返回值;读取packet

的API 依然是av_read_frame,返回的packet并不是编码后的视频包而是原始的图片帧,图片

帧的格式是YUV422(我测试的机器是这样的)。拿到图片帧后并不能直接编码,需要做格式转换

因为libx264不支持YUV422,所以有了上图中的格式转换这一环节。转换图片帧格式后将视频数据

丢给编码器就行编码,编码的packet才可以写到输出流中。

下面给出代码:

1.初始化Ffmpeg

void Init()
{av_register_all();avfilter_register_all();     avformat_network_init();avdevice_register_all();      av_log_set_level(AV_LOG_ERROR);
}

2.创建输入上下文,打开摄像头

int OpenInput(char *fileName)
{context = avformat_alloc_context();context->interrupt_callback.callback = interrupt_cb;AVInputFormat *ifmt = av_find_input_format("dshow");AVDictionary *format_opts =  nullptr;av_dict_set_int(&format_opts, "rtbufsize", 18432000  , 0);int ret = avformat_open_input(&context, fileName, ifmt, &format_opts);if(ret < 0){return  ret;}ret = avformat_find_stream_info(context,nullptr);av_dump_format(context, 0, fileName, 0);if(ret >= 0) {cout <<"open input stream successfully" << endl;}return ret;
}

 3. 初始化编码器

int InitOutputCodec(AVCodecContext** pOutPutEncContext, int iWidth, int iHeight)
{AVCodec *  pH264Codec = avcodec_find_encoder(AV_CODEC_ID_H264);if(NULL == pH264Codec){printf("%s", "avcodec_find_encoder failed");return  0;}*pOutPutEncContext = avcodec_alloc_context3(pH264Codec);(*pOutPutEncContext)->codec_id = pH264Codec->id;(*pOutPutEncContext)->time_base.num =0;(*pOutPutEncContext)->time_base.den = 1;(*pOutPutEncContext)->pix_fmt            = AV_PIX_FMT_YUV420P;(*pOutPutEncContext)->width              =  iWidth;(*pOutPutEncContext)->height             = iHeight;(*pOutPutEncContext)->has_b_frames = 0;(*pOutPutEncContext)->max_b_frames = 0;AVDictionary *options = nullptr;(*pOutPutEncContext)->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;int ret = avcodec_open2(*pOutPutEncContext, pH264Codec, &options);if (ret < 0){printf("%s", "open codec failed");return  ret;}return 1;
}

 4.创建输出上下文以及输出流

int OpenOutput(char *fileName)
{int ret = 0;ret  = avformat_alloc_output_context2(&outputContext, nullptr, "flv", fileName);if(ret < 0){goto Error;}ret = avio_open2(&outputContext->pb, fileName, AVIO_FLAG_READ_WRITE,nullptr, nullptr);  if(ret < 0){goto Error;}for(int i = 0; i < context->nb_streams; i++){AVStream * stream = avformat_new_stream(outputContext, pOutPutEncContext->codec);stream->codec = pOutPutEncContext;if(ret < 0){goto Error;}}av_dump_format(outputContext, 0, fileName, 1);ret = avformat_write_header(outputContext, nullptr);if(ret < 0){goto Error;}if(ret >= 0)cout <<"open output stream successfully" << endl;return ret ;
Error:if(outputContext){for(int i = 0; i < outputContext->nb_streams; i++){avcodec_close(outputContext->streams[i]->codec);}avformat_close_input(&outputContext);}return ret ;
}

 4.从输入流读取视频包

std::shared_ptr<AVPacket> ReadPacketFromSource()
{std::shared_ptr<AVPacket> packet(static_cast<AVPacket*>(av_malloc(sizeof(AVPacket))), [&](AVPacket *p) { av_packet_free(&p); av_freep(&p); });av_init_packet(packet.get());lastFrameRealtime = av_gettime();int ret = av_read_frame(context, packet.get());if(ret >= 0){return packet;}else{return nullptr;}
}

  5.格式转换

int YUV422To420(uint8_t *yuv422, uint8_t *yuv420, int width, int height)
{int s = width * height;int i,j,k = 0;for(i = 0; i < s;i++){yuv420[i] = yuv422[i * 2];}for(i = 0; i < height; i++){if(i%2 != 0) continue;for(j = 0; j <(width /2); j++){if(4 * j + 1 > 2 * width) break;yuv420[s + k * 2 * width / 4 +j] = yuv422[i * 2 * width + 4 *j + 1];}k++;}k = 0;for(i = 0; i < height; i++){if(i % 2 == 0) continue;for(j = 0; j < width / 2; j++){if(4 * j + 3 > 2 * width) break;yuv420[s + s / 4 + k * 2 *width / 4 + j] = yuv422[i *2 * width + 4 * j + 3];}k++;}return 1;
};

  6. 简单实例

 string fileInput="video=Integrated Webcam";string fileOutput="rtmp://127.0.0.1/live/mystream";Init();if(OpenInput((char *)fileInput.c_str()) < 0){cout << "Open file Input failed!" << endl;this_thread::sleep_for(chrono::seconds(10));return 0;}InitOutputCodec(&pOutPutEncContext,DstWidth,DstHeight);if(OpenOutput((char *)fileOutput.c_str()) < 0){cout << "Open file Output failed!" << endl;this_thread::sleep_for(chrono::seconds(10));return 0;}auto timebase = av_q2d(context->streams[0]->time_base);int count = 0;auto in_stream = context->streams[0];auto out_stream = outputContext->streams[0];int iGetPic = 0;uint8_t *yuv420Buffer = (uint8_t *)malloc(DstWidth * DstHeight * 3 / 2);yuv420Buffer[DstWidth * DstHeight * 3 / 2 - 1] = 0;while(true){auto packet = ReadPacketFromSource();if(packet){auto pSwsFrame = av_frame_alloc();int numBytes=av_image_get_buffer_size(AV_PIX_FMT_YUYV422, DstWidth, DstHeight, 1);YUV422To420(packet->data, yuv420Buffer, DstWidth, DstHeight);av_image_fill_arrays((pSwsFrame)->data, (pSwsFrame)->linesize, yuv420Buffer, AV_PIX_FMT_YUV420P, DstWidth, DstHeight, 1);AVPacket *pTmpPkt = (AVPacket *)av_malloc(sizeof(AVPacket));av_init_packet(pTmpPkt);pTmpPkt->data = NULL;pTmpPkt->size = 0;int iRet = avcodec_encode_video2(pOutPutEncContext, pTmpPkt, pSwsFrame, &iGetPic);if(iRet >= 0 && iGetPic){int ret = av_write_frame(outputContext, pTmpPkt);cout << "ret:"<< ret <<endl;//this_thread::sleep_for(std::chrono::milliseconds(40));}av_frame_free(&pSwsFrame);av_packet_free(&pTmpPkt);}}CloseInput();CloseOutput();cout <<"Transcode file end!" << endl;this_thread::sleep_for(chrono::hours(10));return 0;

  

如需交流,可以加QQ群766718184,或者QQ:350197870

视频教程 播放地址: http://www.iqiyi.com/u/1426749687

  

转载于:https://www.cnblogs.com/wanggang123/p/6133212.html

windows ffmpeg 推送摄像头数据到rtmp服务相关推荐

  1. Gstreamer推送摄像头数据到RTMP服务器的方法(SRS成功示例)

    最近在研究如何将Linux中的视频数据推送到流媒体服务器,看到gstreamer还比较不错,于是试了一下 服务端用的SRS,RTMP推流,搭建非常简单,教程可参考:https://blog.csdn. ...

  2. FFmpeg 推送摄像头 rtsp 流

    FFmpeg 推送摄像头 rtsp 流 Windows 环境下使用 FFmpeg 推送本地 USB 摄像头为 rtsp 流,并使用 vlc 播放. 本文主要使用环境是 Windows 下的 FFmpe ...

  3. ffmpeg推送摄像头rtmp流

    /*** * 张晖 Hui Zhang* zhanghuicuc@gmail.com* 中国传媒大学/数字电视技术* Communication University of China / Digit ...

  4. linux下ffmpeg命令行推送摄像头和麦克风

    linux 下ffmpeg命令行推送摄像头和麦克风 最近学习ffmpeg,用到命令测试麦克风和摄像头,参考了很多blog,综合测试后得到如下命令. 测试系统使用的Ubuntu系统,在虚拟机中使用摄像头 ...

  5. 2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写。

    2023-03-05:ffmpeg推送本地视频至lal流媒体服务器(以RTMP为例),请用go语言编写. 答案2023-03-05: 使用 github.com/moonfdd/ffmpeg-go 库 ...

  6. FFmpeg推送命令

    ffmpeg推流命令 使用命令推送成rtp流 使用rtp发送 ffmpeg -i rtsp://admin:1qaz2wsx@192.168.10.250:554/Streaming/Channels ...

  7. 服务器主动推送消息数据给客户端

    1 引言 这个问题第一次是我在实现一个导师的方案的时候所发现的,一开始我需要实现服务器与客户端的密钥协商和数据传递,服务器需要主动分发(推送)密钥给客户端,因为以前没有做过相关编码,后来只能想到用反向 ...

  8. EasyDarwin+ffmpeg进行PC(摄像头+麦克风)流媒体直播服务

    上一回我们描述了用EasyDarwin+ffmpeg进行摄像机直播的过程:ffmpeg推送,EasyDarwin转发,vlc播放 实现整个RTSP直播 我们再进行一个方面的描述,那就是pc摄像头+麦克 ...

  9. 使用极光推送实现分组发送和服务端集成

    推送功能在手机应用开发中越来越重要,几乎成为所有App必备的功能,由于Android本身没有消息推送机制,通常采用的是基于XMPP协议的推送,但这种开发很麻烦,因此在市场上应运而生了提供消息推送服务的 ...

最新文章

  1. struts.xml配置详解
  2. NLP分词数据准备及模型训练实例
  3. W3C HTML 工作组联合主席Paul Cotton谈HTML5发展愿景
  4. Apache rewrite
  5. C++求最小公倍數LCM的实现算法(附完整源码)
  6. VC++ 19 (VS2015) 编译器系统环境变量配置
  7. 在 SAP Analytics Cloud 上开发和使用 Queries
  8. 1022. 宠物小精灵之收服
  9. MongoDB 字段拼接 $concat(aggregation)
  10. java timer 序列化_编程达人 应用层timer_如何序列化timer
  11. odbc数据源的配置
  12. 求01矩阵中的最大的正方形面积
  13. IDEA官网以往版本下载
  14. Excel密码解除方法 破解
  15. 688. 骑士在棋盘上的概率(中等 动态规划)
  16. Carson带你学Android:这是一份全面 详细的Android代码命名规范
  17. Solidity入门-开发众筹智能合约
  18. 《公安机关办理刑事案件电子数据取证规则》
  19. 小小白的Android入门之计算器学习
  20. pytorch优化器详解:SGD

热门文章

  1. java书籍台湾翻译_《现代专业Javasctript 技术》一书中英文目录,翻译记录下来方便学习用...
  2. python基础教程运行程序_Python入门基础教程:WSGI
  3. 去哪儿-16-detail-banner
  4. C++/C--set常见用法详解【转载】
  5. python优化算法_python – 优化算法
  6. 图的单源最短路径(Dijkstra算法)
  7. G - A Bug‘s Life(并查集) acm寒假集训日记22/1/2
  8. centos7源码安装mysql8.0_CentOS7下源码安装MySQL 8.x
  9. java复制文件夹_java实现拷贝一个文件夹,里面存在目录和文件,使用文件创建和文件流...
  10. python调用github_Python调用GithubAPI并进行初步的数据分析