PC端通过FFmpeg源码实现将H264数据RTMP推流到Nginx服务器上,这个是用于PC端的测试demo,程序可以直接移植到ARM版本中,需要将库文件交叉编译,以及修改对应的交叉编译工具链即可。

因为实现这个功能的环境比较恶劣(没有摄像头),本人通过将开发板端摄像头实时数据保存成二进制文件(.bin),
按规定格式[NAL_SIZE|NAL||NAL_SIZE|NAL|…|NAL_SIZE|NAL|NAL_SIZE|NAL|],现将一个完整的NAL帧数据大小写入文件,紧接是NAL数据,如此循环。当PC端读取文件时,先读取一帧数据的大小,再按照规定大小,读取一帧NAL数据,并将数据推送到Nginx服务器上。

完整工程:https://download.csdn.net/download/weixin_43793181/21481918

代码实现、库编译时遇到的问题

push_stream.c完整代码:

#include <stdio.h>
#include "uvc_video_handler.h"
#define __STDC_CONSTANT_MACROS#ifdef __cplusplus
extern "C"
{#endif
#include <libavformat/avformat.h>
#include <libavcodec/codec_id.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>#ifdef __cplusplus
};
#endifAVFormatContext *ofmt_ctx = NULL;
int ptsInc = 0;int add_stream(AVFormatContext *ofmt_ctx,OutputStream *ost, AVCodec **codecder, enum AVCodecID codec_id)
{AVCodecContext *codec = NULL;AVRational a_time_base;AVRational v_time_base;// find the encoder*codecder = avcodec_find_encoder(AV_CODEC_ID_H264);if (!(*codecder)) {printf("Could not find encoder for '%s'\n", avcodec_get_name(codec_id));return -1;}ost->st = avformat_new_stream(ofmt_ctx, NULL);if (!ost->st) {printf("Could not allocate stream\n");return -1;}codec = avcodec_alloc_context3(*codecder);if (!codec) {printf("Could not alloc an encoding context\n");return -1;}ost->st->id = ofmt_ctx->nb_streams - 1;ost->enc = codec;switch ((*codecder)->type) {case AVMEDIA_TYPE_AUDIO:codec->codec_id = codec_id;codec->codec_type = AVMEDIA_TYPE_AUDIO;codec->sample_fmt = AV_SAMPLE_FMT_FLTP;codec->bit_rate = 64000;codec->sample_rate = 8000;codec->channel_layout = AV_CH_LAYOUT_MONO;codec->channels = av_get_channel_layout_nb_channels(codec->channel_layout);a_time_base.num = 1;a_time_base.den = codec->sample_rate;ost->st->time_base = a_time_base;break;case AVMEDIA_TYPE_VIDEO:codec->codec_id = codec_id;codec->codec_type = AVMEDIA_TYPE_VIDEO;codec->pix_fmt = AV_PIX_FMT_YUV420P;codec->bit_rate = 400000;codec->width = 800;codec->height = 640;v_time_base.num = 1;v_time_base.den = 50;ost->st->time_base = v_time_base;codec->time_base = ost->st->time_base;codec->codec_tag = 0;break;default:break;}if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;int ret = avcodec_open2(codec,*codecder,NULL);if(ret < 0){printf("open video codec failed !\n");}if(avcodec_parameters_from_context(ost->st->codecpar,codec) < 0){printf("acvodec_parameters_from_context failed!\n");}   return 0;
}int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{// rescale output packet timestamp values from  codec to stream timebase av_packet_rescale_ts(pkt, *time_base, st->time_base);pkt->stream_index = st->index;//Write the compressed frame to the media file. return av_interleaved_write_frame(fmt_ctx, pkt);
}int write_video_frame(AVFormatContext *ofmt_ctx,OutputStream *ost, char* data, int datalen)
{int ret = 0;int isI = 0;AVCodecContext *c = ost->enc;AVPacket pkt = { 0 };av_init_packet(&pkt);isI = isIdrFrame1((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++) * 2, time_base, ost->st->time_base);pkt.dts = av_rescale_q_rnd(pkt.dts, ost->st->time_base, ost->st->time_base, (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.duration = av_rescale_q(pkt.duration, ost->st->time_base, ost->st->time_base);    pkt.pos = -1;ret = write_frame(ofmt_ctx, &c->time_base, ost->st, &pkt);if (ret < 0){printf("Error while writing video frame\n");return -1;}return 0;
}bool isIdrFrame2(uint8_t *buf, int len)
{switch (buf[0] & 0x1f) {case 7: // SPSreturn true;case 8: // PPSreturn true;case 5:return true;case 1:return false;default:return false;break;}return false;
}bool isIdrFrame1(uint8_t *buf, int size)
{int last = 0;for (int i = 2; i <= size; ++i) {if (i == size) {if (last) {bool ret = isIdrFrame2(buf + last, i - last);if (ret) {return true;}}}else if (buf[i - 2] == 0x00 && buf[i - 1] == 0x00 && buf[i] == 0x01) {if (last) {int size = i - last - 3;if (buf[i - 3]) ++size;bool ret = isIdrFrame2(buf + last, size);if (ret) {return true;}}last = i + 1;}}return false;
}int main(int argc, char* argv[])
{char buffer_size[6];               //每一帧数据的大小(字符串)char nal_buf[100000];          //每一帧数据的内容int nal_size = 0;                        //每一帧数据的大小(整型)int n,m = 0;AVDictionary *opt;AVPacket pkt;AVCodec *audio_codec,*video_codec;OutputStream audio_st,video_st;AVOutputFormat *ofmt = NULL;int ret,i,have_video,have_audio;int videoindex=-1;int frame_index=0;int64_t start_time=0;//输入对应一个AVFormatContext,输出对应一个AVFormatContextAVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;const char *in_filename, *out_filename;in_filename  = "uvc_enc_out.bin";//输入文件(内容结构:NAL_SIZE|NAL|NAL_SIZE|NAL|NAL_SIZE|NAL)out_filename = "rtmp://10.1.40.34:1935/live/test";//输出 URL(Output URL)[RTMP]av_register_all();avformat_network_init();avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_filename); if (!ofmt_ctx) {printf( "Could not create output context\n");ret = AVERROR_UNKNOWN;return -1;}ofmt = ofmt_ctx->oformat;    if(ofmt->video_codec != AV_CODEC_ID_NONE){ofmt->video_codec = AV_CODEC_ID_H264;ret = add_stream(ofmt_ctx,&video_st, &video_codec,ofmt->video_codec);if(ret < 0){printf("Could not add video stream.\n");return -1;}}
/*if (ofmt->audio_codec != AV_CODEC_ID_NONE) {ofmt->audio_codec = AV_CODEC_ID_AAC;ret = add_stream(ofmt_ctx,&audio_st, &audio_codec, ofmt->audio_codec);if (ret < 0){printf("Could not add audio stream.\n");return -1;}}
*/av_dump_format(ofmt_ctx, 0, out_filename, 1);if (!(ofmt->flags & AVFMT_NOFILE)) {ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_READ_WRITE);if (ret < 0) {printf("Could not open '%s' %d: %s\n", out_filename,ret, av_err2str(ret));return -1;}}//ret = avformat_write_header(ofmt_ctx, &opt);ret = avformat_write_header(ofmt_ctx, NULL);if (ret < 0) {printf("Error occurred when opening output URL\n");return -1;}FILE *dst= fopen(in_filename,"rb");if(dst == NULL)        //打开失败返回NULL{perror("打开源文件失败!\n");exit(0);}while(!feof(dst)){n = fread(buffer_size,1,5,dst);                                                                                      //前5个字节为NAL_SIZEif(n == 5){nal_size = atoi(buffer_size);                                                                                     //字符串转为整型printf("nal_size == %d\n",nal_size);memset(nal_buf,0,100000);                                                                                      //清空数组n = fread(nal_buf,1,nal_size,dst);                                                                           //读取一帧NAL数据if(n == nal_size){printf("这是%d帧数据!\n",++m);ret = write_video_frame(ofmt_ctx,&video_st,  nal_buf, nal_size);    //写NAL数据,推流}else{printf("帧数据出不来n == %d\n",n);}}else{printf("n不为5,n==%d\n",n);}}return 0;
}

推流+拉流成功

Ubuntu+FFmpeg源码+H264+RTMP推流相关推荐

  1. ffmpeg源码优化之推流发送篇

    1.引言 大家好,距离上篇文章已经过去有一段时间了,主要是最近太忙了,一直没有更新.今天总算能抽出一点时间,说说ffmpeg源码级别的优化了,这块应该会连载,请大家持续关注.废话不多说,接下来就进入正 ...

  2. ffmpeg源码实现H264推流

    Ubuntu+FFmpeg源码+H264+RTMP推流具体DEMO 因为项目的需要,需要将摄像头的实时流,通过ffmpeg源码实现将一帧帧的H264数据推流到Nginx服务器上. 程序运行时出现报错: ...

  3. FFmpeg源码编译出支持音频AAC编码以及H264,H265编码的库

    先决条件: 需要安装msys2(是一个在windows中模拟linux操作系统的软件) 由于在linux中编译ffmpeg比较简单, 所以利用一下msys2, 直接去官网下载安装即可 需要安装visu ...

  4. 一对一直播app源码开发,推流技术的实现

    在说一对一直播app源码推流技术之前,先说一对一直播app源码推流的过程:采集-->前处理-->编码-->推流--->流分发--->播放. 1.采集:音视频采集 pc段屏 ...

  5. WINDOWS 下编译 ffmpeg 源码总结

    WINDOWS 下编译 ffmpeg 源码,有两种方式:VC.GCC 1.VC 编译:   https://github.com/ShiftMediaProject/FFVS-Project-Gene ...

  6. Android录屏并利用FFmpeg转换成gif(二)交叉编译FFmpeg源码

    Android录屏并利用FFmpeg转换成gif(二) 写博客时经常会希望用一段动画来演示app的行为,目前大多数的做法是在电脑上开模拟器,然后用gif录制软件录制模拟器屏幕,对于非开发人员来讲这种方 ...

  7. ffmpeg源码分析与应用示例(一)——H.264解码与QP提取

    本文包含以下内容 1.H.264解码流程详述与对应ffmpeg源码解析 2.针对一个应用实例介绍通过修改ffmpeg源码解决问题的方案 具有较强的综合性. 先介绍一下在第二部分中将要解决的实际问题:自 ...

  8. Android FFmpeg源码编译及在Android studio的集成

    准备工具: 1,ubuntu server 18.04.4(其他发行版服务器或桌面版都行,我这里以ubuntu为例,可以使用虚拟机,也可以使用公网的服务器) 2,ndk R17c linux版 (下载 ...

  9. 从头用脚分析FFmpeg源码 --- avformat_open_input

    本文所使用的是FFmpeg n4.4的源码,所有分析均来自博主瞎猜,如果有误,欢迎批评指正. 建议边调试源码,边看对应的源码分析.走上一遍就了解个大概了. avformat_open_input 作用 ...

最新文章

  1. OC 消息转发实现多继承
  2. (纯干货)万字长文,数据分析利器 pandas 全教程
  3. linux异地文件同步软件,rsync完成异地文件的同步
  4. 【详细注释】1058 选择题 (20 分)
  5. 信息学奥赛一本通(2070:【例2.13】数字对调)
  6. python fromarray_python --- 之pil image.fromarray
  7. win7 下安装ubuntu14.04 本人实测撰写
  8. asp.net Coolite 学习
  9. 彻底卸载VS2015的工具及使用方法,亲测有效!!!
  10. 记一次hw中的上线骚姿势(异速联+用友U8)
  11. Java算法面试题(008) 字符串反转
  12. Ubuntu18.04安装CAJViewer
  13. 2022年上半年软件设计师下午真题试题(案例分析)及答案
  14. 试凑法整定PID参数
  15. 随机存储器:SRAM、DRAM、SDRAM的区别
  16. 开源软件的法律风险及防控
  17. 定位篇align_measurements
  18. 微信公众平台开发之基于百度 BAE3.0 的开发环境搭建(MyEclipse + SVN)
  19. 原生PHP 调用原生GD库 生成海报
  20. spring boot+iview 前后端分离架构之文件上传的实现(三十一)

热门文章

  1. Linux常用安装命令
  2. -如何调整html页面的间距,css中字间距怎么设置?
  3. 手把手教你做一个最最最简单的爱心飘落动画
  4. python 3.0以上版本print函数为什么从print 变成print()
  5. Canvas画图设置渐变色
  6. clock wizard 生成VHDL例化
  7. Python爬虫入门教程:爬取妹子图网站 - 独行大佬
  8. ps从零开始之制作图片水印制作网站水印
  9. 基于微信小程序的在线医生答疑系统
  10. Istio-sidecar注入原理