使用live555实时播放rtsp

      Android原生的MediaPlayer虽然也可以播放rtsp流媒体,可是却有几秒的延时,不符合实时的要求。于是需要使用第三方库live555来解决这个问题。

 

1、搭建live555框架

 

      我们先下载源码,然后在eclipse里创建一个新的library工程,在工程jni下创建一个live目录,然后将源码拷贝过来。之后在jni下新建一个Android.mk和Application.mk。

 

图Android.mk


 

图Application.mk

 

 

2、跑通rtsp client流程

 

      分析源码,我们先将testRTSPClient.cpp从jni/live/testProgs里拷贝出来,放到jni下, 然后新建一个jni_interface.h。

使用live555实时播放rtsp_第1张图片

图jni_interface.h

 

      Java_com_live555_ctl_liveRtsp_start、Java_com_live555_ctl_liveRtsp_dosometing这两个接口我们将在testRTSPClient.cpp里实现。

 

      在Java_com_live555_ctl_liveRtsp_start里我们根据传过来的url和progName调用openURL,然后调起主循环doEventLoop。 这个时候,我们可以跑通rtsp client的流程,可以连接server了,可是,接收到的视频数据还没有做处理。

 

3、接收处理视频数据

 

      在live555的架构里,要说明一下Sink  source,这两者的概念及关系:

      liveMedia库中Sink就是消费数据的对象,比如把接收到的数据存储到文件,这个文件就是一个Sink。 Source就是生产数据的对象,比如通过 RTP读取数据。数据流经过多个source和sinks。


图MediaSink


使用live555实时播放rtsp_第2张图片 

图MediaSource

 

 

      根据rtsp流程,我们在continueAfterSETUP里找到了

      {

      scs.subsession->sink =DummySink::createNew(env, *scs.subsession, rtspClient->url());

      }

      将其替换为

      {

      bool oneFilePerFrame = false;

      char const* fmtp_spropparametersets =(*scs.subsession).fmtp_spropparametersets();

       scs.subsession->sink =H264VideoFileSink::createNew(env,            (charconst*)"/storage/sdcard0/testRtsp.mp4",fmtp_spropparametersets,DUMMY_SINK_RECEIVE_BUFFER_SIZE,oneFilePerFrame);

      }

      替换DummySink为H264VideoFileSink后,我们就可以发现,rtsp传过来的视频数据被保存在了/storage/sdcard0/testRtsp.mp4。

 

      我们将H264VideoStreamSink.cpp、H264VideoStreamSink.hh、 H264or5VideoStreamSink.cpp、H264or5VideoStreamSink.hh、 StreamSink.cpp、StreamSink.hh拷贝到jni下,改名为WrH264VideoStreamSink.cpp、WrH264VideoStreamSink.hh、WrH264or5VideoStreamSink.cpp、WrH264or5VideoStreamSink.hh、 WrStreamSink.cpp、 WrStreamSink.hh。

      {

      scs.subsession->sink =H264VideoFileSink::createNew(env,(charconst*)"/storage/sdcard0/testRtsp.mp4",fmtp_spropparametersets,DUMMY_SINK_RECEIVE_BUFFER_SIZE,oneFilePerFrame);

      }

      改为

      {

      scs.subsession->sink =WrH264VideoStreamSink::createNew(env,

                &function_callback,fmtp_spropparametersets,

                        DUMMY_SINK_RECEIVE_BUFFER_SIZE);

      }

      传递一个回调进去typedefvoidfunctioncallback(unsignedchar* buffer,int datasize,int videowidth,int videoheight, int pts),然后修改相应的代码,将保存为mp4的功能去掉,改为将h264的视频frame通过回调传出来。

      {

            void function_callback(unsigned char* buffer,int datasize, int videowidth, int videoheight, int pts)

            {

               if(0!= liveRtsp_env && 0 != liveRtsp_obj && 0 != liveRtsp_array)     {

                  liveRtsp_env->SetByteArrayRegion(liveRtsp_array,0, datasize, (const jbyte*)buffer);

                  int iframeSize = datasize;

                  liveRtsp_env->CallVoidMethod(*liveRtsp_obj,mid_onNativeCallback, liveRtsp_array, videowidth, videoheight, pts, datasize);

               }

           }

       

      然后通过mid_onNativeCallback =env->GetMethodID(clsstring, "onNativeCallback","([BIIII)V")将h264的frame传到Java层。

 

 

4、Java层接口


图 live555接口

 

      至此,live555 rtsp client的library就搭建好了。

 

 

5、应用live555rtsp client的library

 

 

      {

        String prog = "dlna_connect";

        byte[] progName =new byte[prog.length() +1];

        System.arraycopy(prog.getBytes(), 0, progName, 0, prog.length());

        progName[prog.length()] = 0;   

 

        Stringuri = playURI;//"rtsp://192.168.43.1:8086";

        byte[] nameUri =new byte[uri.length() +1];

        System.arraycopy(uri.getBytes(), 0, nameUri, 0, uri.length());

       nameUri[uri.length()] = 0;

 

       if(null == mliveRtsp)

            mliveRtsp =new liveRtsp();

        mliveRtsp.mliveRtspInterface = liveRtspIf;

        mliveRtsp.start(progName, nameUri);

      }

      这里开始启动liveRtsp

 

      {

      public liveRtsp.liveRtspInterface liveRtspIf = new    liveRtsp.liveRtspInterface() {

 

          @Override

          public voidliveRtspCallback(byte[] data, int width, int height,

                         intpts, int len) {

                  ...在这里可以收到rtsp的视频帧

            }

      }

      }

      接收到视频帧后,需要解码显示到Surface上,需要注意的是,live555里只有一个主线程,所以回调也是在liveRtsp的主线程里,即创建liveRtsp的线程。

你可能感兴趣的:(android,jni,RTSP,RTP,Live555)