T31开发笔记:librtmp编译测试及推流测试

若该文为原创文章,转载请注明原文出处

编译librtmp库,及代码详解测试。

一、硬件和开发环境

1、硬件:T31X+SC5235 

2、开发环境: ubuntu16.04-64bit

3、编译器:mips-gcc540-glibc222-32bit-r3.3.0.tar.gz

注:板子和和WIFI模块是某淘上淘的,使用的是RTL8188,使用的是USB接口,uboot和内核是自己裁剪移植的,内核默认自带WIFI驱动,所以不用移植可以直接使用。

二、交叉编译

在交叉编译之前,要确保交叉编译链安装正常。

交叉编译librtmp需要编译zlib,openssl .

1、编译zlib库

1、获取源码
wget http://zlib.net/zlib-1.2.11
2、解压
tar -vxf zlib-1.2.11
3、进入目录 
cd zlib
4、设置环境,输入以下命令
CC=mips-linux-gnu-gcc ./configure --prefix=/usr/local
5、编译
make
6、安装
make install 

执行成功后会在/usr/local下生成库.

2、编译openssl

1、下载源码
get http://www.openssl.org/source/openssl-1.0.1u
2、解压
tar -vxf openssl-1.0.1u
3、进入openssl目录 
cd openssl-1.0.1.u
4、设置环境,输入以下命令
CC=mips-linux-gnu-gcc ./config no-asm shared --prefix=/usr/local
5、编译
make
6、安装
make install

3、编译librtmp

1、下载源码
git clone git://git.ffmpeg.org/rtmpdump
2、修改Makefile
1)、主要修改:
CC=$(CROSS_COMPILE)gcc 
LD=$(CROSS_COMPILE)ld 
AR=$(CROSS_COMPILE)ar
修改成:
CC=mips-linux-gnu-gcc
LD=mips-linux-gnu-ld 
AR=mips-linux-gnu-ar
2)、修改CRYPTO=OPENSSL
修改为:
CRYPTO=/usr/local/bin
3、编译
make
4、安装
make install

三、代码解析

编译代码需要用到的库,本人在T31上使用的是静态库,可以自行改成动态库,以减少编译文件的大小 。

编译所需的库有:librtmp.a、libssl.a、libcrypto.a、libz.a

代码:

/*!
 *****************************************************************************
 *
 *  Copyright ? 2017-2018 yifeng. All Rights Reserved.
 *
 * \file      main.c
 * \author    yifeng
 * \version   1.0
 * \date      2022年3月3日
 * \brief     rtmp测试代码
 *
 *----------------------------------------------------------------------------
 * \attention
 *
 *
 *****************************************************************************
 */

/*****************************************************************************
 change history: 
    1.date  : 2022年3月3日
      author: yifeng
      change: create file

*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>

/* 环形队列头文件 */
#include "ringfifo.h"
#include "faac/faac.h"
#include "xiecc_rtmp.h"

#include <imp/imp_audio.h>

#include <imp/imp_log.h>

#define AAC_ADTS_HEADER_SIZE 7

static uint32_t find_start_code(uint8_t *buf, uint32_t zeros_in_startcode)   
{   
  uint32_t info;   
  uint32_t i;   
   
  info = 1;   
  if ((info = (buf[zeros_in_startcode] != 1)? 0: 1) == 0)   
      return 0;   
       
  for (i = 0; i < zeros_in_startcode; i++)   
    if (buf[i] != 0)   
    { 
        info = 0;
        break;
    };   
     
  return info;   
}   

uint8_t * get_nal(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total)
{
    uint32_t info;
    uint8_t *q ;
    uint8_t *p  =  *offset;
    *len = 0;

    while(1) {
        info =  find_start_code(p, 3);
        if (info == 1)
            break;
        p++;
        if ((p - start) >= total)
            return NULL;
    }
    q = p + 4;
    p = q;
    while(1) {
        info =  find_start_code(p, 3);
        if (info == 1)
            break;
        p++;
        if ((p - start) >= total)
            return NULL;
    }
    
    *len = (p - q);
    *offset = p;
    return q;
}
uint8_t *get_adts(uint32_t *len, uint8_t **offset, uint8_t *start, uint32_t total)
{
    uint8_t *p  =  *offset;
    uint32_t frame_len_1;
    uint32_t frame_len_2;
    uint32_t frame_len_3;
    uint32_t frame_length;
   
    if (total < AAC_ADTS_HEADER_SIZE) {
        return NULL;
    }
    if ((p - start) >= total) {
        return NULL;
    }
    
    if (p[0] != 0xff) {
        return NULL;
    }
    if ((p[1] & 0xf0) != 0xf0) {
        return NULL;
    }
    frame_len_1 = p[3] & 0x03;
    frame_len_2 = p[4];
    frame_len_3 = (p[5] & 0xe0) >> 5;
    frame_length = (frame_len_1 << 11) | (frame_len_2 << 3) | frame_len_3;
    *offset = p + frame_length;
    *len = frame_length;
    return p;
}


/*!
 * \fn     main
 * \brief  主函数
 *          
 * \param  [in] int argc       #
 * \param  [in] char *argv[]   #
 * 
 * \retval int
 */
int main(int argc, char *argv[])
{
  pthread_t id;
  pthread_t audio_id;

  char serverStrBuf[100];

  if(argc != 2)
  {
    printf("Usage: rtmp serverip -eg << rtmp 192.168.1.100 >>");
    return -1;
  }

  sprintf(serverStrBuf, "rtmp://%s/live/stream", argv[1]);
  printf("Server=%s\n", serverStrBuf);

  /* 初始化内存 */
  ringmalloc(384*1024);

  void*p = rtmp_sender_alloc(serverStrBuf);
  if(rtmp_sender_start_publish(p, 0, 0) != 0)
  {
    printf("connect %s failed\n", serverStrBuf);
    return -1;
  }

  int fd = open("cms.264", O_RDONLY);
    uint8_t * buf = malloc(3 *1024 * 1024);
    uint32_t total;
    total = read(fd, buf, (1024*1024 *3));
    close(fd);
    int aacfd = open("audiotest.aac", O_RDONLY); 
    uint8_t * audio_buf = malloc(1 *1024 * 1024);
    uint32_t audio_total;
    audio_total = read(aacfd, audio_buf, (1024*1024 *3));
    close(aacfd);
    uint8_t *buf_offset = buf;
    uint8_t *audio_buf_offset = audio_buf;
    uint32_t len;
    uint32_t audio_len;
    uint8_t *p_video ;
    uint8_t *pp;
    uint8_t *p_audio;
    uint32_t audio_ts = 0;
    uint32_t ts = 0;
    uint32_t len_1;
    uint32_t len_2;
    while (1) {
    p_audio = get_adts(&audio_len, &audio_buf_offset, audio_buf, audio_total);
    if (p_audio == NULL){
        audio_buf_offset = audio_buf;
        continue;
    }
    rtmp_sender_write_audio_frame(p, p_audio, audio_len, audio_ts);

    p_video = get_nal(&len, &buf_offset, buf, total);
    if (p_video == NULL) {
        buf_offset = buf;
        continue;
    }
    printf("%x %d\n", p_video[0], len);
    if (p_video[0] == 0x67) {
            pp = get_nal(&len_1, &buf_offset, buf, total);
            printf("%x %d\n", pp[0], len_1);
            pp = get_nal(&len_2, &buf_offset, buf, total);
            printf("%x %d\n", pp[0], len_2);
            uint8_t temp = len + len_1 + len_2 + 12;
            printf("temp %d\n", temp);
            rtmp_sender_write_video_frame(p, p_video - 4, temp, ts, 0);
    }
    else
       rtmp_sender_write_video_frame(p, p_video - 4, len + 4, ts, 0);
    ts += 50;
    audio_ts += 50;
    usleep(50 * 1000);
    }

  return 0;
}

代码功能主要是读取h264和AAC文件,封装后,通过rtmp传到服务器,服务器可以用SRS,nginx等,具体服务器搭建不在演示。

把代码编译成可执行文件,运行测试。

四、总结

1、主要是测试和了解下rtmp的推流方式,由于硬件显示,不测试拉流。

如有侵权,请及时联系博主删除,VX:18750903063

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷忆枫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值