FFmpeg 版本

version 4.0.2

搭建Rtmp服务

具体可以参考一下其它文章,本文主要讲的是如何使用FFmpeg api接口实现推流功能

推流flv文件

    av_register_all();AVFormatContext *ictx = NULL;//打开文件,解封文件头int re = avformat_open_input(&ictx, inUrl, 0, 0);if (re != 0){return ff_Error(re);}cout << "open file " << inUrl << " success..." << endl;//获取音频视频流信息re = avformat_find_stream_info(ictx, 0);if (re != 0){return ff_Error(re);}cout << "打印输入文件信息" << endl;av_dump_format(ictx, 0, inUrl, 0);//创建输出流上下文AVFormatContext *octx = NULL;re = avformat_alloc_output_context2(&octx, 0, "flv", outUrl);if (!octx){return ff_Error(re);}cout << "输出上下文创建成功" << endl;//配置输出流//遍历输入的AVStreamfor (int i = 0; i < ictx->nb_streams; i++){//创建输出流AVStream *out = avformat_new_stream(octx, ictx->streams[i]->codec->codec);if (!out){return ff_Error(0);}//复制配置信息AVCodecParameters *codecpar = ictx->streams[i]->codecpar;re = avcodec_parameters_copy(out->codecpar, codecpar);out->codec->codec_tag = 0;}cout << "打印输出流信息" << endl;av_dump_format(octx, 0, outUrl, 1);//rtmp推流//打开iore = avio_open(&octx->pb, outUrl, AVIO_FLAG_WRITE);if (!octx->pb){return ff_Error(re);}//写入头信息re = avformat_write_header(octx, 0);if (re < 0){return ff_Error(re);}AVPacket pkt;long long startTime = av_gettime();for (;;){re = av_read_frame(ictx, &pkt);if (re != 0){break;}if (ictx->streams[pkt.stream_index]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {continue;}cout << pkt.pts << " " << flush;//计算转换pts dtsAVRational itime = ictx->streams[pkt.stream_index]->time_base;AVRational otime = octx->streams[pkt.stream_index]->time_base;pkt.pts = av_rescale_q_rnd(pkt.pts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));pkt.dts = av_rescale_q_rnd(pkt.dts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));pkt.duration = av_rescale_q_rnd(pkt.duration, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));pkt.pos = -1;//视频帧推送速度if (ictx->streams[pkt.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){AVRational tb = ictx->streams[pkt.stream_index]->time_base;//已经过去的时间long long now = av_gettime() - startTime;long long dts = 0;dts = pkt.dts * (1000 * 1000 * r2d(tb));if (dts > now)av_usleep(dts - now);}//推送帧数据re = av_interleaved_write_frame(octx, &pkt);if (re<0){return ff_Error(re);}}cout << "rtmp 推流结束" << endl;

推流H264数据帧

有时候我们想推流的数据并非来自文件,而是来自编码器,视频数据通过函数参数传入,所以我们需要另一种方式实现推流,在这里通过读H264文件模拟视频数据帧

代码实现

static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{// rescale output packet timestamp values from  codec to stream timebaseav_packet_rescale_ts(pkt, *time_base, st->time_base);pkt->stream_index = st->index;printf("pkt pts = %d dts = %d \n", pkt->pts, pkt->dts);return av_write_frame(fmt_ctx, pkt);
}static int write_video_frame(AVFormatContext *ofmt_ctx, AVStream *st, char* data, int datalen)
{int ret = 0;int isI = 0;AVCodecContext *c = st->codec;AVPacket pkt = { 0 };av_init_packet(&pkt);isI = isIdrFrame((uint8_t*)data, datalen);pkt.flags |= isI ? AV_PKT_FLAG_KEY : 0;pkt.data = (uint8_t*)data;pkt.size = datalen;AVRational time_base = {1, 1000};pkt.pts = av_rescale_q(ptsInc++, time_base, st->time_base);enum AVRounding rnd = (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.dts = av_rescale_q_rnd(pkt.dts, st->time_base, st->time_base, rnd);pkt.duration = av_rescale_q(pkt.duration, st->time_base, st->time_base);pkt.pos = -1;ret = write_frame(ofmt_ctx, &c->time_base, st, &pkt);if (ret < 0){printf("Error while writing video frame\n");return -1;}return 0;
}
static int pushFlow2(char *outUrl)
{av_register_all();//输出流//创建输出流上下文AVFormatContext *octx = NULL;int re = avformat_alloc_output_context2(&octx, 0, "flv", outUrl);if (!octx){return ff_Error(re);}cout << "输出上下文创建成功" << endl;AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (codec == NULL) {printf("No codec for format: H264 \n");return -1;}AVCodecContext *codec_context = avcodec_alloc_context3(codec);if (! codec) {printf("Could not alloc an encoding context \n");return -1;}AVStream *vstream = avformat_new_stream(octx, NULL);if (vstream == NULL) {printf("cannot new video stream \n");return -1;}vstream->id = 0;vstream->codec = codec_context;codec_context->codec_id = codec->id;codec_context->codec_type = AVMEDIA_TYPE_VIDEO;codec_context->pix_fmt = AV_PIX_FMT_YUV420P;codec_context->bit_rate = 4000000;codec_context->width = 1280;codec_context->height = 720;AVRational time_base = {1, 30};vstream->time_base = time_base;codec_context->time_base = time_base;codec_context->codec_tag = 0;if (octx->oformat->flags & AVFMT_GLOBALHEADER) {codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;}int ret = avcodec_open2(codec_context, codec, NULL);if(ret < 0){printf("open video codec failed ! \n");}if(avcodec_parameters_from_context(vstream->codecpar, codec_context) < 0){printf("acvodec_parameters_from_context failed!\n");}cout << "打印输出流信息" << endl;av_dump_format(octx, 0, outUrl, 1);//rtmp推流//打开iore = avio_open(&octx->pb, outUrl, AVIO_FLAG_WRITE);if (!octx->pb){return ff_Error(re);}//写入头信息re = avformat_write_header(octx, 0);if (re < 0){return ff_Error(re);}H264FileSource *source = h264_file_source_new("1.h264");if (source == NULL) {return -1;}for (;;){usleep(33 * 1000);const H264Nal *frame = H264_file_source_read(source);if (frame == NULL) {break;}int ret = write_video_frame(octx, vstream, (char *)frame->data, frame->size);if (ret < 0) {printf("write video frame fail \n");return -1;}}cout << "rtmp 推流结束" << endl;
}

ffmpeg api接口实现rtmp推流的两种方式相关推荐

  1. ASP.NET Web API接受AngualrJS的QueryString的两种方式

    ASP.NET Web API如何接受来自AngualrJS的QueryString呢?本篇体验两种方式. 第一种方式:http://localhost:49705/api/products?sear ...

  2. 【FFMPEG】AVFrame中buffer分配的两种方式

    AVFrame在使用ffmpeg进行编解码过程中,是最基本的数据结构. 在某些场景下,需要对AVFrame的数据区域进行提前分配,有两种方法,需要根据自己的需求来使用. (1) * This func ...

  3. 使用ArcGIS JS API加载WMTS图层的两种方式

    文章目录 前言 方式一 方式二 前言 某些项目可能多方参与,每一方使用的GIS平台有时会有所不同,这时为了统一各方地图服务,通常会发布OGC标准的WMTS地图服务供各方使用.ArcGIS API fo ...

  4. API数据传输,flask发送接收两种方式/cryptography is required for sha256_password or caching_sha2_password

    import requests import jsondata = {"texts": '{"uuid": [5, 1], "createName&q ...

  5. 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    实验4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 姓名:李冬辉 学号:20133201 注: 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http ...

  6. python 收发微信之一:利用 WxPusher 的 web api 及 python SDK 两种方式给自己发微信

    目 录 摘要 实操 代码分析 需求来源与路径选择 参考 摘要 本文给出利用 WxPusher 提供的 web api 与 python SDK 两种方式,实现微信发送的 python 代码样例,并简单 ...

  7. java操作Excel有两种方式 方式1:jxl操作Excel jxl的API

    java操作Excel有两种方式 方式1:jxl操作Excel 方式2:poi操作Excel 下面介绍jxl API: 使用Windows操作系统的朋友对Excel(电子表格)一定不会陌生,但是要使用 ...

  8. 对外API接口的安全性设计及鉴权方式

    对外API接口的安全性设计及鉴权方式 API鉴权方式 API Key + API Secret实现API鉴权 Cookie + Session实现API鉴权 token机制实现API鉴权 API接口的 ...

  9. 实验四:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    贺邦+原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验目的: 使用库函数 ...

最新文章

  1. 实践作业3 (2017-12-4)
  2. mt7601u linux驱动下载,Ubuntu16.04安装DPO_MT7601U_LinuxSTA_3.0.0.4_20130913.tar.bz2
  3. SpringBoot中配置为开发模式,代码修改后不用重新运行
  4. linux mount挂载设备(u盘,光盘,iso等 )使用说明
  5. EOJ_1049_三元组稀疏矩阵相加
  6. 磁共振线圈分类_收藏:磁共振检查序列及临床应用总结
  7. python字符串添加成员_Python - 字符串的操作方法
  8. 运行MonkeyRunner时使用Genymotion模拟器
  9. cmd查看IP地址指令
  10. WOL局域网与外网远程唤醒概要
  11. 看过这篇数据分析,再也不要说你是凭实力单身了!
  12. linux 动态加载日志,Linux动态显示文件内容-linux tailf命令详解-Linux tailf命令退出-嗨客网...
  13. 微信小程序 后端接口(thinkphp)
  14. 在 Vue2 中引入高德地图和三维模型
  15. 学习笔记HHL:Generalizing a Person Retrieval Model--Hetero-Homogeneous Learning UDA郑良2018
  16. 只读存储器和随机存储器有什么区别?
  17. ServiceNow主要模块介绍
  18. 关于Ubuntu启动activeMq无效果的错误解决方案
  19. 深入小程序云开发之云函数 第三部分 云函数经验谈
  20. JAVA实现word导出,word转PDF,预览汇总

热门文章

  1. Unity性能优化教程
  2. [oeasy]python0117 文字的演化_埃及圣书体_象形文字_楔形文字
  3. linux火狐怎么清除缓存文件,Firefox缓存文件夹位置设置及清除缓存方法
  4. 中小企业知识管理的实施策略
  5. 为什么企业需要社会化媒体营销?
  6. ANDROID N 在SetupWizard后加入自己的页面
  7. 最新版去水印小程序源码/基于WordPress的短视频去水印小程序源码
  8. npm install报错,npm WARN ajv-keywords@3.4.0 requires a peer of ajv@^6.9.1 but none is installed. You m
  9. 用虚幻引擎制作逼真毛发:获取白皮书!
  10. css海浪动画代码,css3圆形波浪滚动上升加载动画特效