Linux下librtmp使用及编程实战

来源:互联网 发布:外国人抢购的国货知乎 编辑:程序博客网 时间:2024/06/17 14:44

最近想做rtmp的推流、直播的小项目,不想直接使用FFmpeg进行推流,FFmpeg进行推流特别简单,因为它已经将编码以及librtmp都集成好了,没啥意思。FFmpeg推流的例子,在雷神的博客里可以找到。这里主要是基于librmtp,结合libx264进行压缩,进行一些实验,包括三大部分:

  1. rtmp流保存
  2. flv文件推流
  3. h264推流

首先是rtmp流保存

复制代码
/* * RTMPRec.cpp * *  Created on: Jan 11, 2017 *      Author: tla001 */#include "RTMPRec.h"#include "sockInit.h"RTMPRec::RTMPRec(const string url,const string filename) {    // TODO Auto-generated constructor stub    rtmpUrl=url;    outFile=filename;    bufSize=1024*1024*10;    buf=new char[bufSize];    countSize=0;    b_live_stream=true;    rtmp=RTMP_Alloc();}RTMPRec::~RTMPRec() {    // TODO Auto-generated destructor stub     if (fp != NULL) {            fclose(fp);            fp = NULL;        }    if (buf != NULL) {        delete[] buf;        buf = NULL;    }    CleanupSockets();    if (rtmp != NULL) {        RTMP_Close(rtmp);        RTMP_Free(rtmp);        rtmp = NULL;    }}int RTMPRec::init(){    fp=fopen(outFile.c_str(),"wb");    if(NULL==fp){        RTMP_LogPrintf("Open File Error.\n");        return -1;    }    InitSockets();    RTMP_Init(rtmp);    //set connection timeout,default 30s    rtmp->Link.timeout=10;    if (!RTMP_SetupURL(rtmp,const_cast<char*>(rtmpUrl.c_str()))) {            RTMP_Log(RTMP_LOGERROR, "SetupURL Err\n");            RTMP_Free(rtmp);            return -1;        }    if (b_live_stream) {        rtmp->Link.lFlags |= RTMP_LF_LIVE;    }    //1hour    RTMP_SetBufferMS(rtmp, 3600 * 1000);    if (!RTMP_Connect(rtmp, NULL)) {        RTMP_Log(RTMP_LOGERROR, "Connect Err\n");        RTMP_Free(rtmp);        return -1;    }    if (!RTMP_ConnectStream(rtmp, 0)) {        RTMP_Log(RTMP_LOGERROR, "ConnectStream Err\n");        RTMP_Free(rtmp);        RTMP_Close(rtmp);        return -1;    }}void RTMPRec::run(){    worker();}void RTMPRec::worker(){    int nread;    while ((nread = RTMP_Read(rtmp, buf, bufSize)) != 0) {        fwrite(buf, 1, (size_t)nread, fp);        memset(buf,0,bufSize);        countSize += nread;        RTMP_LogPrintf("Receive: %5dByte, Total: %5.2fkB\n", nread, countSize * 1.0 / 1024);    }}void RTMPRec::doSave(){    this->start();}
复制代码

推送flv文件

  主要指根据flv文件储存结构进行读取与解析的

复制代码
/* * RTMPPushFlv.cpp * *  Created on: Jan 11, 2017 *      Author: tla001 */#include "RTMPPushFlv.h"#include "sockInit.h"RTMPPushFlv::RTMPPushFlv(const string url) {    // TODO Auto-generated constructor stub    rtmpUrl=url;    fp=NULL;     start_time = 0;     now_time = 0;     pre_frame_time = 0;     lasttime = 0;     b_next_is_key = 1;     pre_tag_size = 0;     type = 0;     datalength = 0;     timestamp = 0;     rtmp = RTMP_Alloc();}RTMPPushFlv::~RTMPPushFlv() {    // TODO Auto-generated destructor stub    if (fp != NULL) {        fclose(fp);        fp = NULL;    }    CleanupSockets();    if (rtmp != NULL) {        RTMP_Close(rtmp);        RTMP_Free(rtmp);        rtmp = NULL;    }    if (p_file_buf != NULL) {        free(p_file_buf);        p_file_buf = NULL;    }}int RTMPPushFlv::init(const string filename){    inFile=filename;     fp = fopen(inFile.c_str(), "rb");    if (NULL == fp) {        log_err("Open File Error");        return -1;    }    InitSockets();    RTMP_Init(rtmp);    //set connection timeout,default 30s    rtmp->Link.timeout = 5;    if (!RTMP_SetupURL(rtmp, const_cast<char*>(rtmpUrl.c_str()))) {        RTMP_Log(RTMP_LOGERROR, "SetupURL Err\n");        //RTMP_Free(rtmp);        return -1;    }    RTMP_EnableWrite(rtmp);    if (!RTMP_Connect(rtmp, NULL)) {        RTMP_Log(RTMP_LOGERROR, "Connect Err\n");        //RTMP_Free(rtmp);        return -1;    }    if (!RTMP_ConnectStream(rtmp, 0)) {        RTMP_Log(RTMP_LOGERROR, "ConnectStream Err\n");        //RTMP_Close(rtmp);        //RTMP_Free(rtmp);        return -1;    }    //jump over FLV Header    fseek(fp, 9, SEEK_SET);    //jump over previousTagSizen    fseek(fp, 4, SEEK_CUR);    return 0;}void RTMPPushFlv::run(){    worker();}void RTMPPushFlv::worker(){    log_info("Start to send data ...");    start_time = RTMP_GetTime();    while (1) {        if ((((now_time = RTMP_GetTime()) - start_time)                < (pre_frame_time)) && b_next_is_key) {            //wait for 1 sec if the send process is too fast            //this mechanism is not very good,need some improvement            if (pre_frame_time > lasttime) {                RTMP_LogPrintf("TimeStamp:%8lu ms\n", pre_frame_time);                lasttime = pre_frame_time;            }            sleep(1);            continue;        }        //jump over type        fseek(fp, 1, SEEK_CUR);        if (!ReadU24(&datalength, fp)) {            break;        }        if (!ReadTime(&timestamp, fp)) {            break;        }        //jump back        fseek(fp, -8, SEEK_CUR);        p_file_buf = (char *) malloc(11 + datalength + 4);        memset(p_file_buf, 0, 11 + datalength + 4);        if (fread(p_file_buf, 1, 11 + datalength + 4, fp) != (11 + datalength + 4)) {            break;        }        pre_frame_time = timestamp;        if (!RTMP_IsConnected(rtmp)) {            RTMP_Log(RTMP_LOGERROR, "rtmp is not connect\n");            break;        }        if (!RTMP_Write(rtmp, p_file_buf, 11 + datalength + 4)) {            RTMP_Log(RTMP_LOGERROR, "Rtmp Write Error\n");            break;        }        free(p_file_buf);        p_file_buf = NULL;        if (!PeekU8(&type, fp)) {            break;        }        if (0x09 == type) {            if (fseek(fp, 11, SEEK_CUR) != 0) {                break;            }            if (!PeekU8(&type, fp)) {                break;            }            if (type == 0x17) {                b_next_is_key = 1;            } else {                b_next_is_key = 0;            }            fseek(fp, -11, SEEK_CUR);        }    }    log_info("Send Data Over");}void RTMPPushFlv::doPush(){    this->start();}
复制代码

h264数据推流

  包括yuv数据的读入,h264编码,librtmp分包传输

  这里对参考的库进行了必要的修改,可以实现设置参数后,不同数据格式可以自动转换为420p。

复制代码
/* * RTMPPushH264.cpp * *  Created on: Jan 12, 2017 *      Author: tla001 */#include "RTMPPushH264.h"#include "librtmp/log.h"int runflag=0;static void sig_user(int signo){    if(signo==SIGINT){        runflag=0;        printf("received SIGINT\n");    }}void pushYUVByH264(){    char url[]="rtmp://localhost/live/test1";    int width=640;    int height=360;    int outSize=1024;    int baseFrameSize=width*height;    const long bufferSize=baseFrameSize*3;    char buffer[bufferSize];    int fps=25;    int rate=400;    char *frame=NULL;    if(signal(SIGINT,sig_user)==SIG_ERR)        perror("catch SIGINT err");    FILE* fp  = fopen("test_640x360_yuv420p.yuv", "rb");    enum AVPixelFormat src_pix_fmt=AV_PIX_FMT_YUV420P;    RTMP_CreatePublish(url,outSize,1,RTMP_LOGINFO);    printf("connected \n");    RTMP_InitVideoParams(width,height,fps,rate,src_pix_fmt,false);    printf("inited \n");    runflag=1;    unsigned int tick = 0;    unsigned int tick_gap = 1000/fps;    uint32_t now=0,last_update=0;    int index=0;    while(runflag){        if(index!=0){            RTMP_SendScreenCapture((char*)buffer,height,tick);            printf("send frame index -- %d\n",index);        }        last_update=RTMP_GetTime();        switch(src_pix_fmt){            case AV_PIX_FMT_YUV420P:                if (fread(buffer, 1, baseFrameSize*3/2, fp) != baseFrameSize*3/2){                    // Loop                    fseek(fp, 0, SEEK_SET);                    fread(buffer, 1, baseFrameSize*3/2, fp);                    //fclose(fp);                    //break;                }                printf("read file \n");                break;            case AV_PIX_FMT_YUV422P:                if (fread(buffer, 1, baseFrameSize*2, fp) != baseFrameSize*2){                    // Loop                    fseek(fp, 0, SEEK_SET);                    fread(buffer, 1, baseFrameSize*2, fp);                    //fclose(fp);                    //break;                }                    break;            case AV_PIX_FMT_RGB24:                if (fread(buffer, 1, baseFrameSize*3, fp) != baseFrameSize*3){                    // Loop                    fseek(fp, 0, SEEK_SET);                    fread(buffer, 1, baseFrameSize*3, fp);                    //fclose(fp);                    //break;                }                    break;            default:                printf("Not supports this format \n");                break;            }        tick +=tick_gap;        now=RTMP_GetTime();        usleep((tick_gap-now+last_update)*1000);        index++;    }    RTMP_DeletePublish();    fclose(fp);}
复制代码

 

完整工程

  https://github.com/tla001/RTMPApp

 

相关链接

  rmtp服务器配置

    http://www.cnblogs.com/tla001/p/6263215.html

  h264 rtmp封装

    https://github.com/njk888/LibRtmpH264

  librtmp学习

    http://blog.csdn.net/leixiaohua1020/article/details/15814587

转载请注明出处:http://www.cnblogs.com/tla001/ 一起学习,一起进步
原创粉丝点击