若该文为原创文章,转载请注明原文出处
编译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