openrtsp源码(openwrt源码)
本文目录一览:
- 1、ijkplayer支持rtsp吗
- 2、RTSP传输方式由什么决定呢? TCP or UDP解决方法
- 3、怎样编译live555 openrstp
- 4、C++ 借用ffmpeg的类库, 获取rtsp流媒体中音频的程序
- 5、怎么实现最小的RTSP服务器
- 6、基于RTP\RTSP数据传输中的丢包现象...
ijkplayer支持rtsp吗
ijkplayer是Bilibili基于ffmpeg开发并开源的轻量级视频播放器,支持播放本地网络视频,也支持流媒体播放。支持AndroidiOS。
ijkplayer的编译这里不多阐述,我也是直接获取别人编译完成的so库文件,直接使用的。如果你对ijkplayer的编译感兴趣,可以百度一下,有很多文章。
使用ijkplayer
导包
ijkplayer源码官方下载地址:
上面是官方提供的ijkplayer的源码地址,但是它是没有编译过的。下面我给大家分享一份编译好的ijkplayer源码,由于比较大,分了三个包才上传完成,需要三个包都下载后才能一起解压:
编译好的ijkplayer.part1
编译好的ijkplayer.part2
编译好的ijkplayer.part3
我们下载完成,进入android/ijkplayer目录:
ijkplayer-java:ijkplayer的一些操作封装及定义。这里面是通用的API接口,里面最主要的是IMediaPlayer,它是用来渲染显示多媒体的。
ijkplayer-exo:google开源的一个新的播放器ExoPlayer,在Demo中和ijkplayer对比用的。通过安装ijkplayer可以发现setting里面可以选择不同player来渲染多媒体显示,该模块下面就是一个MediaPlayer。
ijkplayer-example:测试程序
ijkplayer-{arch}:编译出来的各个版本的.so文件。
官方提供的Demo的代码还是挺多的,甚至还用了otto,需要对官方的demo进行精简,去除一些用不到的代码。
首先需要的是ijkplayer-{arch}、ijkplayer-Java两个库。exo是Google提供的新的播放器,这里不需要,直接砍掉。其次是ijkplayer-example里的,我们需要的只有tv.danmaku.ijk.media.example.widget.media包下的部分类。
注:
链接库ijkplayer-arm64,ijkplayer-armv5,ijkplayer-armv7a,ijkplayer-x86,ijkplayer-x86_64是不同体系架构的动态链接库,在当前工程结构里面作为一个模块,如果不想做兼容多平台问题,可以删除其他目录结构,单独保留自己需要的平台目录。
新建一个工程:
(1)把ijkplayer-armv7a/src/main/libs下的文件拷贝到新工程app目录的libs下。
(2)把ijkplayer-java/build/outputs/aar/ijkplayer-java-release.aar复制到新工程app目录的libs下。
(3)修改APP下的build.gradle, 主要设置.so及.aar的位置:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.hx.ijkplayer_demo"
minSdkVersion 14
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs'] /**在libs文件夹下找so文件*/
}
}
}
repositories {
mavenCentral()
flatDir {
dirs 'libs' /**在libs文件夹下找aar文件*/
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.2.1'
testCompile 'junit:junit:4.12'
compile(name: 'ijkplayer-java-release', ext: 'aar') /**编译ijkplayer-java-release.aar文件*/
}
(4)复制ijkplayer-example下面的tv.danmaku.ijk.media.example.widget.media到新的工程,删掉一些不需要类。
(5)IjkVideoView里面还是有很多如exo等没用的东西,删!具体可以参见我后面的Demo。
(6)Manifest
...
activity android:name=".MainActivity"
android:screenOrientation="sensorLandscape"
android:configChanges="orientation|keyboardHidden"
...
/activity
...
uses-permission android:name="android.permission.INTERNET"/
RTSP传输方式由什么决定呢? TCP or UDP解决方法
Transport: RTP/AVP 【UDP传输方式】 ------------------------- 我用的是openRTSP,如果没有 -t 参数的话,就接受不到数据,加上-t 才能收到数据。 -t 参数为 TCP方式传输. 我用抓包工具观察 有-t 的话 Transport: RTP/AVP/TCP; 无-t 的话 Transport: RTP/AVP; ----------------------- ------解决方案-------------------------------------------------------- openRTSP有-t参数说明使用tcp接收数据; 如果rtsp server在外网,外网udp数据自然无法到达你所在的内网的; rtsp协议本身不支持似网穿透、UDP打洞等; ------解决方案--------------------------------------------------------貌似发describ的时候,服务器会返回一些信息的吧,貌似就能知道是tcp还是udp了。
怎样编译live555 openrstp
1: 编译
(1): ./genMakefiles linux
(2): make
2: 服务器环境
服务器端是一个支持RTSP server的H.264的摄像头;
3: 运行 openRTSP
./openRTSP -d 20 -f 20 -w 640 -h 480 -b 400000 "rtsp://192.168.2.239/id=0"
或 ./openRTSP -f 20 -w 640 -h 480 -b 400000 "rtsp://192.168.2.239/id=0"
参数解释; -d 20 ---程序运行时间,如果没有程序持续从服务器获取视频;
-f 20 ---- 帧率
-w 640 -h 480 ----- 帧分辨率
-b 400000 ----码率
4: 如果不修改playCommon.cpp的代码,openRTSP将获取的视频数据通过stdout直接打印到屏幕
5: 如果是自己取裸码流,则可以调用SPS相关的函数,将H264的帧信息告诉解码器,否则无法解码
unsigned int num=1;
SPropRecord * sps = parseSPropParameterSets(subsession-fmtp_spropparametersets(),num);
fileSink = H264VideoFileSink::createNew(*env, outFileName,
subsession-fmtp_spropparametersets(),
fileSinkBufferSize, oneFilePerFrame);
struct timeval tv={0,0};
unsigned char start_code[4] = {0x00, 0x00, 0x00, 0x01};
fileSink- addData(start_code, 4, tv);
fileSink-addData(sps[0].sPropBytes,sps[0].sPropLength,tv);
delete[] sps;
6: 稍微修改代码让openRTSP只录视频,且保存到指定的文件
streamURL = argv[1];
// add by Andy_xi
createReceivers = True; // 保存视频
outputAVIFile = False; //因为是H264
videoOnly = True;
singleMedium = "video"; //只要视频
//------end
7: 调试记录
启动openRTSP后,一定的看到SDP信息中的SPS信息,否则解码器可能不能解码
a=fmtp:106 profile-level-id=42001E;sprop-parameter-sets=Z0KAKNoB4AiXlQ==,aM48gA==;packetization-mode=0
只要有这个信息,用file 命令看生成h264文件显示如下:
new.h264: JVT NAL sequence, H.264 video, baseline @ L 40
C++ 借用ffmpeg的类库, 获取rtsp流媒体中音频的程序
我不打代码了。
avformat_open_input这些代码打开文件
然后av_read_frame不停的读文件内容
然后decode,然后encode。然后avio_open打开输出文件,然后不停的将encode结果av_interleaved_write_frame到文件里。
怎么实现最小的RTSP服务器
亲 很高兴为你解答 以下答案有道友提供
//////rtsp.c//////
#include stdio.h
#include stdlib.h
#include string.h
#include memory.h
#include errno.h
#include netdb.h
#include time.h
#include sys/types.h
#include netinet/in.h
#include sys/socket.h
#include arpa/inet.h
#include unistd.h //close()
#include "h264.h"
//#define DEST_PORT 8888
typedef struct
{
int startcodeprefix_len; //, 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
unsigned len; //, Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
unsigned max_size; //, Nal Unit Buffer size
int forbidden_bit; //, should be always FALSE
int nal_reference_idc; //, NALU_PRIORITY_xxxx
int nal_unit_type; //, NALU_TYPE_xxxx
char *buf; //, contains the first byte followed by the EBSP
unsigned short lost_packets; //, true, if packet loss is detected
} NALU_t;
FILE *bits = NULL; //, the bit stream file
static int FindStartCode2 (unsigned char *Buf);//查找开始字符0x000001
static int FindStartCode3 (unsigned char *Buf);//查找开始字符0x00000001
//static bool flag = true;
static int info2=0, info3=0;
RTP_FIXED_HEADER *rtp_hdr;
NALU_HEADER *nalu_hdr;
FU_INDICATOR *fu_ind;
FU_HEADER *fu_hdr;
/**
int sock_init(int sockfd,struct sockaddr_in addr,int SERVER_PORT)
{
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd0)
{
fprintf(stderr,"Socket Error:%s\n",strerror(errno));
exit(1);
}
printf("sockfd is %d\n",sockfd);
bzero(addr,sizeof(struct sockaddr_in));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(SERVER_PORT);
if(bind(sockfd,(struct sockaddr *)addr,sizeof(struct sockaddr_in))0)
{
fprintf(stderr,"Bind Error:%s\n",strerror(errno));
exit(1);
}
printf("init successfel,,\nport is %dsockfd is %d\n",SERVER_PORT,sockfd);
return 0;
}
*/
char* sock_recv(int sockfd,struct sockaddr *addr_client,int *addrlen)
{
//int *tem_len = addrlen;
socklen_t len;
printf("sock_recv sockfd is %d\n",sockfd);
char *recv_buffer = malloc (sizeof (char));
//printf("sock_recv sockfd is88888888888888 %d\n",sockfd);
int n;
n=recvfrom(sockfd,recv_buffer,256,0,addr_client,len);
//printf("recv number is %d\n",n);
if(0)
{
printf("recvfrom error,\n");
exit (1);
}
if(-1==n)
{
perror("recv error:");
}
else
{
addrlen=(int *)len;
printf("sock recv success,,\n");
/** char IPdotdec[20]; //存放点分十进制IP地址
struct in_addr s =
inet_ntop(AF_INET, (void *)s, IPdotdec, 16);
printf("addr_client.data=%s\n",IPdotdec);
*/ printf("addr_len=%ld\n",addrlen);
}
return recv_buffer;
}
//为NALU_t结构体分配内存空间
NALU_t *AllocNALU(int buffersize)
{
NALU_t *n;
if ((n = (NALU_t*)calloc (1, sizeof (NALU_t))) == NULL)
{
printf("AllocNALU: n");
exit(0);
}
n-max_size=buffersize;
if ((n-buf = (char*)calloc (buffersize, sizeof (char))) == NULL)
{
free (n);
printf ("AllocNALU: n-buf");
exit(0);
}
return n;
}
//释放
void FreeNALU(NALU_t *n)
{
if (n)
{
if (n-buf)
{
free(n-buf);
n-buf=NULL;
}
free (n);
}
}
void OpenBitstreamFile (char *fn)
{
if (NULL == (bits=fopen(fn, "rb")))
{
printf("open file error\n");
exit(0);
}
printf("test264 open successful,\n");
}
//这个函数输入为一个NAL结构体,主要功能为得到一个完整的NALU并保存在NALU_t的buf中,获取他的长度,填充F,IDC,TYPE位。
//并且返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度
int GetAnnexbNALU (NALU_t *nalu)
{
int pos = 0;
int StartCodeFound, rewind;
unsigned char *Buf;
if ((Buf = (unsigned char*)calloc (nalu-max_size , sizeof(char))) == NULL)
printf ("GetAnnexbNALU: Could not allocate Buf memory\n");
nalu-startcodeprefix_len=3;//初始化码流序列的开始字符为3个字节
if (3 ,= fread (Buf, 1, 3, bits))//从码流中读3个字节
{
free(Buf);
return 0;
}
info2 = FindStartCode2 (Buf);//判断是否为0x000001
if(info2 ,= 1)
{
//如果不是,再读一个字节
if(1 ,= fread(Buf+3, 1, 1, bits))//读一个字节
{
free(Buf);
return 0;
}
info3 = FindStartCode3 (Buf);//判断是否为0x00000001
if (info3 ,= 1)//如果不是,返回-1
{
free(Buf);
return -1;
}
else
{
//如果是0x00000001,得到开始前缀为4个字节
pos = 4;
nalu-startcodeprefix_len = 4;
}
}
else
{
//如果是0x000001,得到开始前缀为3个字节
nalu-startcodeprefix_len = 3;
pos = 3;
}
//查找下一个开始字符的标志位
StartCodeFound = 0;
info2 = 0;
info3 = 0;
while (,StartCodeFound)
{
if (feof (bits))//判断是否到了文件尾
{
nalu-len = (pos-1)-nalu-startcodeprefix_len;
memcpy (nalu-buf, Buf[nalu-startcodeprefix_len], nalu-len);
nalu-forbidden_bit = nalu-buf[0] 0x80; //1 bit
nalu-nal_reference_idc = nalu-buf[0] 0x60; // 2 bit
nalu-nal_unit_type = (nalu-buf[0]) 0x1f;// 5 bit
free(Buf);
return pos-1;
}
Buf[pos++] = fgetc (bits);//读一个字节到BUF中
info3 = FindStartCode3(Buf[pos-4]);//判断是否为0x00000001
if(info3 ,= 1)
info2 = FindStartCode2(Buf[pos-3]);//判断是否为0x000001
StartCodeFound = (info2 == 1 || info3 == 1);
}
// Here, we have found another start code (and read length of startcode bytes more than we should
// have. Hence, go back in the file
rewind = (info3 == 1)? -4 : -3;
if (0 ,= fseek (bits, rewind, SEEK_CUR))//把文件指针指向前一个NALU的末尾
{
free(Buf);
printf("GetAnnexbNALU: Cannot fseek in the bit stream file");
}
// Here the Start code, the complete NALU, and the next start code is in the Buf.
// The size of Buf is pos, pos+rewind are the number of bytes excluding the next
// start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start code
// 不管有没有再次读到 头 ,其主要 关心的还是 nalu-len
nalu-len = (pos+rewind)-nalu-startcodeprefix_len;
memcpy (nalu-buf, Buf[nalu-startcodeprefix_len], nalu-len);//拷贝一个完整NALU,不拷贝起始前缀0x000001或0x00000001
nalu-forbidden_bit = nalu-buf[0] 0x80; //1 bit
nalu-nal_reference_idc = nalu-buf[0] 0x60; // 2 bit
nalu-nal_unit_type = (nalu-buf[0]) 0x1f;// 5 bit
free(Buf);
return (pos+rewind);//返回两个开始字符之间间隔的字节数,即包含有前缀的NALU的长度
}
//输出NALU长度和TYPE
void dump(NALU_t *n)
{
if (,n)return;
//printf("a new nal:");
printf(" len: %d ", n-len);
printf("nal_unit_type: %x\n", n-nal_unit_type);。
基于RTP\RTSP数据传输中的丢包现象...
如果是udp的话 发送方丢包可能性不大,可能是路由设备或者客户端接收逻辑垃圾 导致客户端丢码。但是rtp提供了tcp方式传输,如果你tcp方式发现也丢得话,那估计就是发送逻辑的问题。一般都是send的时候返回错误而没有判断造成的。建议使用多线程发送,将网络和其他逻辑分开,网络部分最好使用异步。我做过rtsp服务器,主要就是io线程不能干其他的,这样就能确保数据即时发送出去。当然如果tcp的话带宽限制你发送不了那么快可以适当的从数据源这里就丢一些非关键帧b或者p。这样就能有稍微好点的实时性。
最后一句话,开发rtsp之前要计算好带宽,连接数,码流大小这些数据。