RTP на Android MediaPlayer - PullRequest
       33

RTP на Android MediaPlayer

10 голосов
/ 06 апреля 2011

Я реализовал RTSP на Android MediaPlayer, используя VLC в качестве сервера rtsp с этим кодом:

# vlc -vvv /home/marco/Videos/pippo.mp4 --sout 
#rtp{dst=192.168.100.246,port=6024-6025,sdp=rtsp://192.168.100.243:8080/test.sdp}

и в проекте Android:


Uri videoUri = Uri.parse("rtsp://192.168.100.242:8080/test.sdp"); 
videoView.setVideoURI(videoUri); 
videoView.start(); 

Это работает нормально, но если я хотел бы также воспроизвести RTP в режиме реального времени, я скопировал файл sdp в sdcard (/mnt/sdcard/test.sdp) и установил vlc:

# vlc -vvv /home/marco/Videos/pippo.mp4 --sout 
#rtp{dst=192.168.100.249,port=6024-6025} 

Я попыталсяВоспроизвести поток RTP, установив путь к файлу sdp локально:


Uri videoUri = Uri.parse("/mnt/sdcard/test.sdp");
videoView.setVideoURI(videoUri); 
videoView.start(); 

Но я получил ошибку:


D/MediaPlayer( 9616): Couldn't open file on client side, trying server side 
W/MediaPlayer( 9616): info/warning (1, 26) 
I/MediaPlayer( 9616): Info (1,26) 
E/PlayerDriver(   76): Command PLAYER_INIT completed with an error or info PVMFFailure 
E/MediaPlayer( 9616): error (1, -1)
E/MediaPlayer( 9616): Error (1,-1) 
D/VideoView( 9616): Error: 1,-1 

кто-нибудь знает в чем проблема?Я не прав или невозможно воспроизвести RTP на MediaPlayer?Приветствия Джорджио

Ответы [ 3 ]

2 голосов
/ 27 февраля 2013

У меня есть частичное решение для вас.

В настоящее время я работаю над проектом Ra & D, предусматривающим потоковую передачу RTP медиаданных с сервера на клиенты Android.

Выполняя эту работу, я добавляю свою собственную библиотеку smpte2022lib, которую вы можете найти здесь: http://sourceforge.net/projects/smpte-2022lib/.

С помощью такой библиотеки (реализация Java на данный момент является лучшей), вы можете анализировать многоадресные потоки RTP, поступающие от профессионального потокового оборудования, сеансы VLC RTP, ...

Я уже успешно протестировал его с потоками, полученными из захваченных профессиональных RTP-потоков с помощью SMPTE-2022 2D-FEC, или с простыми потоками, сгенерированными с помощью VLC.

К сожалению, я не могу поместить сюда фрагмент кода, так как проект, использующий его, фактически защищен авторским правом, но я гарантирую, что вы можете использовать его просто, анализируя потоки UDP, которые помогли с конструктором RtpPacket.

Если пакеты являются действительными RTP-пакетами (байтами), они будут декодированы как таковые.

В этот момент я заключаю вызов конструктора RtpPacket в поток, который фактически сохраняет декодированную полезную нагрузку в виде медиа-файла. Затем я вызову VideoView с этим файлом в качестве параметра.

Скрещивание пальцев; -)

С уважением,

Дэвид Фишер

0 голосов
/ 07 декабря 2013

Возможно в Android-использовании (не mediaPlayer, а другие вещи, расположенные ниже по стеку), но вы действительно хотите использовать RTSP / RTP, когда остальная часть медиа-экосистемы этого не делает?

IMO - под эгидой HTML5 / WebRTC есть гораздо лучшие подходы к медиа / потокам. Например, посмотрите, что 'Ondello' делает с потоками.

Тем не менее, вот код старого проекта для Android / RTSP / SDP / RTP с использованием 'netty' и 'efflux'. Он будет согласовывать некоторые части «сеансов» на провайдерах файлов SDP. Не могу вспомнить, будет ли на самом деле воспроизводить аудио часть Youtube / RTSP , но это было моей целью в то время. (Я думаю, что это работало с использованием кодека AMR-NB, но было множество проблем, и я бросил RTSP на Android как плохая привычка!)

на Git ....

        @Override
        public void mediaDescriptor(Client client, String descriptor)
        {
            // searches for control: session and media arguments.
            final String target = "control:";
            Log.d(TAG, "Session Descriptor\n" + descriptor);
            int position = -1;
            while((position = descriptor.indexOf(target)) > -1)
            {
                descriptor = descriptor.substring(position + target.length());
                resourceList.add(descriptor.substring(0, descriptor.indexOf('\r')));
            }
        }
        private int nextPort()
        {
            return (port += 2) - 2;
        }       


        private void getRTPStream(TransportHeader transport){

            String[] words;
            // only want 2000 part of 'client_port=2000-2001' in the Transport header in the response

            words = transport.getParameter("client_port").substring(transport.getParameter("client_port").indexOf("=") +1).split("-");
            port_lc = Integer.parseInt(words[0]);

            words = transport.getParameter("server_port").substring(transport.getParameter("server_port").indexOf("=") +1).split("-");
            port_rm = Integer.parseInt(words[0]);

            source = transport.getParameter("source").substring(transport.getParameter("source").indexOf("=") +1);          
            ssrc = transport.getParameter("ssrc").substring(transport.getParameter("ssrc").indexOf("=") +1);
            // assume dynamic Packet type = RTP , 99
            getRTPStream(session, source, port_lc, port_rm, 99);
            //getRTPStream("sessiona", source, port_lc, port_rm, 99);
            Log.d(TAG, "raw parms " +port_lc +" " +port_rm +" " +source );
//          String[] words = session.split(";");
        Log.d(TAG, "session: " +session);   
        Log.d(TAG, "transport: " +transport.getParameter("client_port") 
                +" "  +transport.getParameter("server_port") +" "  +transport.getParameter("source") 
                +" "  +transport.getParameter("ssrc"));

        }

        private void getRTPStream(String session, String source, int portl, int portr, int payloadFormat ){
            // what do u do with ssrc?
            InetAddress addr;
            try {
                addr = InetAddress.getLocalHost();
                // Get IP Address
 //             LAN_IP_ADDR = addr.getHostAddress();
                LAN_IP_ADDR = "192.168.1.125";
                Log.d(TAG, "using client IP addr " +LAN_IP_ADDR);

            } catch (UnknownHostException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }


            final CountDownLatch latch = new CountDownLatch(2);

            RtpParticipant local1 = RtpParticipant.createReceiver(new RtpParticipantInfo(1), LAN_IP_ADDR, portl, portl+=1);
     //       RtpParticipant local1 = RtpParticipant.createReceiver(new RtpParticipantInfo(1), "127.0.0.1", portl, portl+=1);
            RtpParticipant remote1 = RtpParticipant.createReceiver(new RtpParticipantInfo(2), source, portr, portr+=1);


            remote1.getInfo().setSsrc( Long.parseLong(ssrc, 16));
            session1 = new SingleParticipantSession(session, payloadFormat, local1, remote1);

           Log.d(TAG, "remote ssrc " +session1.getRemoteParticipant().getInfo().getSsrc());

            session1.init();

            session1.addDataListener(new RtpSessionDataListener() {
                @Override
                public void dataPacketReceived(RtpSession session, RtpParticipantInfo participant, DataPacket packet) {
     //               System.err.println("Session 1 received packet: " + packet + "(session: " + session.getId() + ")");
                    //TODO close the file, flush the buffer
//                  if (_sink != null) _sink.getPackByte(packet);
                    getPackByte(packet);

     //             System.err.println("Ssn 1  packet seqn: typ: datasz "  +packet.getSequenceNumber()  + " " +packet.getPayloadType() +" " +packet.getDataSize());
     //             System.err.println("Ssn 1  packet sessn: typ: datasz "  + session.getId() + " " +packet.getPayloadType() +" " +packet.getDataSize());
 //                   latch.countDown();
                }

            });
     //       DataPacket packet = new DataPacket();
      //      packet.setData(new byte[]{0x45, 0x45, 0x45, 0x45});
     //       packet.setSequenceNumber(1);
     //       session1.sendDataPacket(packet);


//        try {
       //       latch.await(2000, TimeUnit.MILLISECONDS);
     //     } catch (Exception e) {
   //         fail("Exception caught: " + e.getClass().getSimpleName() + " - " + e.getMessage());

 //      }
        }
 //TODO  below should collaborate with the audioTrack object and should write to the AT buffr
        // audioTrack write was blocking forever 

    public void getPackByte(DataPacket packet) {
            //TODO this is getting called but not sure why only one time 
            // or whether it is stalling in mid-exec??

            //TODO on firstPacket write bytes and start audioTrack
            // AMR-nb frames at 12.2 KB or format type 7 frames are handled . 
            // after the normal header, the getDataArray contains extra 10 bytes of dynamic header that are bypassed by 'limit'


            // real value for the frame separator comes in the input stream at position 1 in the data array
            // returned by 

//          int newFrameSep = 0x3c;
            // bytes avail = packet.getDataSize() - limit;

//          byte[] lbuf = new byte[packet.getDataSize()];
//          if ( packet.getDataSize() > 0)
//              lbuf = packet.getDataAsArray();
            //first frame includes the 1 byte frame header whose value should be used 
            // to write subsequent frame separators 
            Log.d(TAG, "getPackByt start and play");

            if(!started){
                Log.d(TAG, " PLAY  audioTrak");
                track.play();
                started = true;
            }

//          track.write(packet.getDataAsArray(), limit, (packet.getDataSize() - limit));
            track.write(packet.getDataAsArray(), 0, packet.getDataSize() );
            Log.d(TAG, "getPackByt aft write");

//          if(!started && nBytesRead > minBufferSize){
    //          Log.d(TAG, " PLAY  audioTrak");
        //      track.play();
        //  started = true;}
            nBytesRead += packet.getDataSize(); 
            if (nBytesRead % 500 < 375) Log.d(TAG, " getPackByte plus 5K received");
        }       
    }
0 голосов
/ 04 ноября 2011

К сожалению, невозможно воспроизвести поток RTP с помощью Android MediaPlayer.

Решения этой проблемы включают декодирование потока RTP с помощью ffmpeg.Учебные руководства по компиляции ffmpeg для Android можно найти в Интернете.

...