最简单的iOS 推流代码,视频捕获,软编码(faac,x264),硬编码(aac,h264),美颜,flv编码,rtmp协议,陆续更新代码解析,你想学的知识这里都有,愿意懂直播技术的同学快来看!!
源代码:https://github.com/hardman/AWLive
rtmp(一般大写,小写会被认为英文不好或不专业,iOS开发者对这一点更为敏感)协议是Adobe公司为Flash视频的实时传输开发的一个开放协议。
本文不探究rtmp协议的原理,只是从代码角度来看,客户端如何使用librtmp完成推流功能。
#librtmp 项目内使用的librtmp是使用rtmpdump编译的。如果遇到代码上的疑问可以通过阅读rtmpdump的源码寻找答案。
#代码解析 ##外部接口 rtmp相关代码在aw_rtmp.c和aw_rtmp.h中。 对外接口包含一个context和3个函数:
//aw_rtmp_context是一个context,用于存储一些外部传入及内部共享的变量。//写成context统一管理,否则就要写很多全局变量了。typedef struct aw_rtmp_context{ //rtmp url char rtmp_url[256]; //librtmp 中的结构体,作为RTMP连接上下文 RTMP *rtmp; ... ... //外部状态检测 //状态变化回调,注意,不要在状态回调中做释放aw_rtmp_context的操作。 //如果非要释放,请延迟一帧。 aw_rtmp_state_changed_cb state_changed_cb; //当前状态 aw_rtmp_state rtmp_state;} aw_rtmp_context;//打开rtmpextern int aw_rtmp_open(aw_rtmp_context *ctx);//写入数据extern int aw_rtmp_write(aw_rtmp_context *ctx, const char *buf, int size);//关闭rtmpextern int aw_rtmp_close(aw_rtmp_context *ctx);复制代码
3个主要函数分别是:打开,写入数据,关闭。 除此之外,对于外部调用者来说,最重要的是要监听rtmp连接的各种状态来调整上层逻辑。 而状态回调就在 aw_rtmp_context中。
项目中,初始化 & 关闭rtmp的代码在 aw_streamer.c 中
//初始化rtmp连接static int8_t aw_steamer_open_rtmp_context(){ //创建context 传入rtmpurl及状态回调 if (!s_rtmp_ctx) { s_rtmp_ctx = alloc_aw_rtmp_context(s_rtmp_url, aw_streamer_rtmp_state_changed_callback); } //open return aw_rtmp_open(s_rtmp_ctx);}//关闭rtmp连接static void aw_streamer_close_rtmp_context(){ if (s_rtmp_ctx) { aw_rtmp_close(s_rtmp_ctx); } aw_log("[d] closed rtmp context");}复制代码
发送数据的代码在aw_streamer.c中:
static void aw_streamer_send_flv_tag_to_rtmp(aw_flv_common_tag *common_tag){ ... ... aw_rtmp_write(s_rtmp_ctx, (const char *)s_output_buf->data, s_output_buf->size); ... ...}复制代码
##打开rtmp
//打开rtmp,都是固定套路。int aw_rtmp_open(aw_rtmp_context *ctx){ ... ... //初始化 ctx->rtmp = RTMP_Alloc(); RTMP_Init(ctx->rtmp); //连接超时 ctx->rtmp->Link.timeout = 1; //设置url if (!RTMP_SetupURL(ctx->rtmp, ctx->rtmp_url)) { AWLog("[error ] aw rtmp setup url = %s\n", ctx->rtmp_url); recode = -2; goto FAILED; } //可写 RTMP_EnableWrite(ctx->rtmp); //buffer长度 RTMP_SetBufferMS(ctx->rtmp, 0); //开始连接 if (!RTMP_Connect(ctx->rtmp, NULL)) { recode = -3; goto FAILED; } //连接 if (!RTMP_ConnectStream(ctx->rtmp, 0)) { recode = -4; goto FAILED; } return 1;FAILED: //若中间环节出错,断开连接 aw_rtmp_close(ctx); return !recode;}复制代码
##rtmp写入(发送)数据
int aw_rtmp_write(aw_rtmp_context *ctx, const char *buf, int size){ ... ... //RTMP_Write内部有时会排出SIGPIPE信号,在这里处理一下 signal(SIGPIPE, SIG_IGN); int write_ret = RTMP_Write(ctx->rtmp, buf, size); ... ... return write_ret;}复制代码
rtmp关闭
int aw_rtmp_close(aw_rtmp_context *ctx){ ... ... //主要这两句 RTMP_Close(ctx->rtmp); RTMP_Free(ctx->rtmp); ... ... return 1;}复制代码
librtmp库使用方法介绍完毕。