9.JRTPLIB使用

JRTPLIB使用

1.RTP简介

实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议,它是由IETF的多媒体传输工作小组1996年在RFC 1889中公布的。

国际电信联盟ITU-T也发布了自己的RTP文档,作为H.225.0,但是后来当IETF发布了关于它的稳定的标准RFC后就被取消了。它作为因特网标准在RFC 3550(该文档的旧版本是RFC 1889)有详细说明。RFC 3551(STD 65,旧版本是RFC 1890)详细描述了使用最小控制的音频和视频会议。

RTP协议详细说明了在互联网上传递音频和视频的标准数据包格式。它一开始被设计为一个多播协议,但后来被用在很多单播应用中。RTP协议常用于流媒体系统(配合RTSP协议),视频会议和一键通(Push to Talk)系统(配合H.323或SIP),使它成为IP电话产业的技术基础。RTP协议和RTP控制协议RTCP一起使用,而且它是建立在UDP协议上的。实时传输协议------wiki

2.JRTPLIB

RTP 是目前解决流媒体实时传输问题的最好办法,如果需要在Linux平台上进行实时流媒体编程,可以考虑使用一些开放源代码的RTP库,如LIBRTP、 JRTPLIB等。 JRTPLIB是一个面向对象的RTP库,它完全遵循RFC 1889设计,在很多场合下是一个非常不错的选择,下面就以JRTPLIB为例,讲述如何在Linux平台上运用RTP协议进行实时流媒体编程。

JRTPLIB 是一个用C++语言实现的RTP库,目前已经可以运行在Windows、Linux、FreeBSD、Solaris、Unix和 VxWorks等多种操作系统上。------jrtp详细介绍

3.JRTPLIB编译

git clone https://github.com/j0r1/JRTPLIB.git
cd JRTPLIB
mkdir build
cd build
cmake .. && make && sudo make install

如果需要启用JThread支持,需要在编译JRTPLIB之前编译JThread

git clone https://github.com/j0r1/JThread.git
cd JRTPLIB
mkdir build
cd build
cmake .. && make && sudo make install

4.JRTPLIB例程

官方历程参见https://github.com/j0r1/JRTPLIB/tree/master/examples,以下是example1.cpp,添加了一些中文注释

#include "rtpsession.h"
#include "rtpudpv4transmitter.h"
#include "rtpipv4address.h"
#include "rtpsessionparams.h"
#include "rtperrors.h"
#include "rtplibraryversion.h"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>

using namespace jrtplib;

// 打印错误信息
void checkerror(int rtperr)
{
    if (rtperr < 0)
    {
        std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
        exit(-1);
    }
}

// 主循环

int main(void)
{

// windows相关,不需要可以删了
#ifdef RTP_SOCKETTYPE_WINSOCK
    WSADATA dat;
    WSAStartup(MAKEWORD(2,2),&dat);
#endif // RTP_SOCKETTYPE_WINSOCK

    RTPSession sess;
    uint16_t portbase,destport;
    uint32_t destip;
    std::string ipstr;
    int status,i,num;

    // 打印JRTPLIB版本
    std::cout << "Using version " << RTPLibraryVersion::GetVersion().GetVersionString() << std::endl;

    // 获取本地端口,用以接收
    std::cout << "Enter local portbase:" << std::endl;
    std::cin >> portbase;
    std::cout << std::endl;

    // 目标地址,本机使用127.0.0.1
    std::cout << "Enter the destination IP address" << std::endl;
    std::cin >> ipstr;
    destip = inet_addr(ipstr.c_str());
    if (destip == INADDR_NONE)
    {
        std::cerr << "Bad IP address specified" << std::endl;
        return -1;
    }

    // inet_addr函数返回的是网络字节序,需要将网络字节序转化为主机字节序
    destip = ntohl(destip);

    // 目标端口,如果发送给本机,与上面的接收端口相同即可
    std::cout << "Enter the destination port" << std::endl;
    std::cin >> destport;

    // 发包数量
    std::cout << std::endl;
    std::cout << "Number of packets you wish to be sent:" << std::endl;
    std::cin >> num;

    // 创建传输参数和会话参数
    RTPUDPv4TransmissionParams transparams;
    RTPSessionParams sessparams;

    // IMPORTANT: The local timestamp unit MUST be set, otherwise
    //            RTCP Sender Report info will be calculated wrong
    // In this case, we'll be sending 10 samples each second, so we'll
    // put the timestamp unit to (1.0/10.0)
    // 设置时间戳
    sessparams.SetOwnTimestampUnit(1.0/10.0);

    // 是否接收自己发送的包
    sessparams.SetAcceptOwnPackets(true);
    // 设置接收端口
    transparams.SetPortbase(portbase);
    // 创建端口
    status = sess.Create(sessparams,&transparams);
    checkerror(status);

    // 写入IPv4地址和端口
    RTPIPv4Address addr(destip,destport);

    // 添加目标地址
    status = sess.AddDestination(addr);
    checkerror(status);

    for (i = 1 ; i <= num ; i++)
    {
        printf("\nSending packet %d/%d\n",i,num);

        // 发包
        status = sess.SendPacket((void *)"1234567890",10,0,false,10);
        checkerror(status);

        sess.BeginDataAccess();

        // 检查收包
        if (sess.GotoFirstSourceWithData())
        {
            do
            {
                RTPPacket *pack;

                while ((pack = sess.GetNextPacket()) != NULL)
                {
                    // 在这里进行数据处理
                    printf("Got packet !\n");

                    // 不再需要这个包了,删除之
                    sess.DeletePacket(pack);
                }
            } while (sess.GotoNextSourceWithData());
        }

        sess.EndDataAccess();

// 这部分与JThread库相关
#ifndef RTP_SUPPORT_THREAD
        status = sess.Poll();
        checkerror(status);
#endif // RTP_SUPPORT_THREAD

        // 等待一秒,发包间隔
        RTPTime::Wait(RTPTime(1,0));
    }

    // 销毁对话
    sess.BYEDestroy(RTPTime(10,0),0,0);

// Windows相关
#ifdef RTP_SOCKETTYPE_WINSOCK
    WSACleanup();
#endif // RTP_SOCKETTYPE_WINSOCK
    return 0;
}

这里会有问题,怎么读取收到的packet中的data,需要先包含头文件

#include "rtppacket.h"

在进行数据处理的地方使用以下函数获取负载数据,和负载长度

pack->GetPayloadData();
pack->GetPayloadLength();

5.CMake配置

在使用CMake进行编译的时候可能会出现找不到库的情况,需要手写FindJRTPLIB.cmake

# - Find JRTPLIB library
# Once done this will define
# JRTPLIB_FOUND - system has JRTPLIB
# JRTPLIB_INCLUDE_DIR - JRTPLIB include directories
# JRTPLIB_LIBRARY - where to find the JRTPLIB library

if(JRTPLIB_INCLUDE_DIR)
    # Already in cache, be silent
    set(JRTPLIB_FIND_QUIETLY TRUE)
endif()

find_path(JRTPLIB_INCLUDE_DIR
    NAMES rtpsession.h
    PATH_SUFFIXES jrtplib jrtplib3
    DOC "JRTPLIB include directories"
    )

find_library(JRTPLIB_LIBRARY
    NAMES jrtp
    DOC "JRTPLIB library"
    )

# handle the QUIETLY and REQUIRED arguments and set JRTPLIB_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JRTPLIB
                                  REQUIRED_VARS JRTPLIB_LIBRARY JRTPLIB_INCLUDE_DIR
                                  VERSION_VAR JRTPLIB_VERSION_STRING)

if(JRTPLIB_INCLUDE_DIR AND JRTPLIB_LIBRARY)
    set(JRTPLIB_FOUND TRUE)
    set(JRTPLIB_LIBRARIES ${JRTPLIB_LIBRARY})
    set(JRTPLIB_INCLUDE_DIRS ${JRTPLIB_INCLUDE_DIR})
else()
    set (JRTPLIB_FOUND FALSE)
    message(FATAL_ERROR "JRTPLIB not found")
endif()

mark_as_advanced(
    JRTPLIB_INCLUDE_DIR
    JRTPLIB_LIBRARY)

如果前面编译了JThread库,或者在编译的时候提示

This function is not available when using the RTP Poll thread feature.

则还需要将JThread库进行链接,FindJTHREAD.cmake如下

# - Find JTHREAD library
# Once done this will define
# JTHREAD_FOUND - system has JTHREAD
# JTHREAD_INCLUDE_DIR - JTHREAD include directories
# JTHREAD_LIBRARY - where to find the JTHREAD library

if(JTHREAD_INCLUDE_DIR)
    # Already in cache, be silent
    set(JTHREAD_FIND_QUIETLY TRUE)
endif()

find_path(JTHREAD_INCLUDE_DIR
    NAMES jthread.h
    PATH_SUFFIXES jthread jthread3
    DOC "JTHREAD include directories"
    )

find_library(JTHREAD_LIBRARY
    NAMES jthread
    DOC "JTHREAD library"
    )

# handle the QUIETLY and REQUIRED arguments and set JTHREAD_FOUND to TRUE if all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(JTHREAD
                                  REQUIRED_VARS JTHREAD_LIBRARY JTHREAD_INCLUDE_DIR
                                  VERSION_VAR JTHREAD_VERSION_STRING)

if(JTHREAD_INCLUDE_DIR AND JTHREAD_LIBRARY)
    set(JTHREAD_FOUND TRUE)
    set(JTHREAD_LIBRARIES ${JTHREAD_LIBRARY})
    set(JTHREAD_INCLUDE_DIRS ${JTHREAD_INCLUDE_DIR})
else()
    set (JTHREAD_FOUND FALSE)
    message(FATAL_ERROR "JTHREAD not found")
endif()

mark_as_advanced(
    JTHREAD_INCLUDE_DIR
    JTHREAD_LIBRARY)

之后在顶层的CMakeLists.txt中使用find_package(JRTPLIB)进行链接,不再赘述。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 值得学习的C语言开源项目 WebbenchWebbench是一个在Linux下使用的非常简单的网站压测工具。它使用...
    资深小夏阅读 3,502评论 0 50
  • RTSP SDP RTP/RTCP 介绍应用层 RTSP、SDP; 传输层 RTP、TCP、UDP; 网络层 IP...
    Atom_Woo阅读 3,801评论 0 7
  • 我们都曾如此渴望命运的波澜,也许到最后才发现:人生最曼妙的风景,竟是内心的淡定与从容。 我们曾如此期盼得到外界的认...
    仲念念阅读 1,148评论 11 20
  • 时光 磨灭曾经的辉煌 岁月 吞噬骄傲的放纵 今天 带着崭新的面貌 明天 前往神圣的殿堂 曾经 志同道合赴梦境 如今...
    Jession恬淡阅读 255评论 0 2
  • 在腾讯大家专栏上看到一篇署名龍昇的《最会骗人的日本妖精》,在文中,作者所谓的日本最会骗人的动物是“狸”。日语中的“...
    丛阑阅读 8,716评论 1 3