最簡單的iOS 推流代碼,視頻捕獲,軟編碼(faac,x264),硬編碼(aac,h264),美顏,flv編碼,rtmp協議,陸續更新代碼解析,你想學的知識這裏都有,願意懂直播技術的同窗快來看!!git
源代碼:https://github.com/hardman/AWLivegithub
rtmp(通常大寫,小寫會被認爲英文很差或不專業,iOS開發者對這一點更爲敏感)協議是Adobe公司爲Flash視頻的實時傳輸開發的一個開放協議。bash
本文不探究rtmp協議的原理,只是從代碼角度來看,客戶端如何使用librtmp完成推流功能。架構
#librtmp 項目內使用的librtmp是使用rtmpdump編譯的。若是遇到代碼上的疑問能夠經過閱讀rtmpdump的源碼尋找答案。函數
#代碼解析 ##外部接口 rtmp相關代碼在aw_rtmp.c和aw_rtmp.h中。 對外接口包含一個context和3個函數:post
//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;
//打開rtmp
extern int aw_rtmp_open(aw_rtmp_context *ctx);
//寫入數據
extern int aw_rtmp_write(aw_rtmp_context *ctx, const char *buf, int size);
//關閉rtmp
extern int aw_rtmp_close(aw_rtmp_context *ctx);
複製代碼
3個主要函數分別是:打開,寫入數據,關閉。 除此以外,對於外部調用者來講,最重要的是要監聽rtmp鏈接的各類狀態來調整上層邏輯。 而狀態回調就在 aw_rtmp_context中。ui
項目中,初始化 & 關閉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中:url
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);
... ...
}
複製代碼
##打開rtmpspa
//打開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;
}
複製代碼
int aw_rtmp_close(aw_rtmp_context *ctx){
... ...
//主要這兩句
RTMP_Close(ctx->rtmp);
RTMP_Free(ctx->rtmp);
... ...
return 1;
}
複製代碼
librtmp庫使用方法介紹完畢。