Noch einmal über Videoüberwachung, Kameras, RTSP, onvif. Und das "Fahrrad"!

    Die Informationen waren bereits auf der habr: habrahabr.ru/post/115808 und habrahabr.ru/post/117735
    Motion-JPEG (MJPEG) ist dort beschrieben.
    Die Welt steht nicht still und auch die Videoüberwachung. Es werden immer mehr andere Codecs verwendet.
    Hier beschreibe ich meine Erfahrung in dieser "Welt".
    Profis lernen nichts Neues, andere sind vielleicht nur interessiert.
    Alles wurde als Training und Training entwickelt.
    Wir werden über RTP, RTSP, h264, mjpeg, onvif und alles zusammen sprechen.
    Lesen Sie vor dem Lesen unbedingt die oben angegebenen Artikel eines anderen Autors.

    Was ist RTSP kann gelesen werden:

    Die Besonderheit von RTSP ist, dass es selbst nicht die Videodaten überträgt, die wir benötigen. Nachdem die Kommunikation hergestellt ist, werden alle Arbeiten unter Verwendung des RTP-Protokolls ( RFC ) ausgeführt.

    Das RTP-Protokoll muss zwischen zwei Übertragungsarten unterscheiden
    1. Nicht verschachtelter Modus (UDP)
    2. Interleaved-Modus (TCP)


    Nicht verschachtelter Modus.
    RTSP stellt die Kommunikation her und überträgt an die Kamera Informationen darüber, wohin Daten gesendet werden sollen (UDP-Ports).
    RTSP-Kommunikationsbeispiel

    //INFO: connect to: rtsp://10.112.28.231:554/live1.sdp
    OPTIONS rtsp://10.112.28.231:554/live1.sdp RTSP/1.0
    CSeq: 1
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    RTSP/1.0 200 OK
    CSeq: 1
    Date: Tue, Jan 15 2013 02:02:56 GMT
    Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER
    DESCRIBE rtsp://10.112.28.231:554/live1.sdp RTSP/1.0
    CSeq: 2
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Accept: application/sdp
    RTSP/1.0 200 OK
    CSeq: 2
    Date: Tue, Jan 15 2013 02:02:56 GMT
    Content-Base: rtsp://10.112.28.231/live1.sdp/
    Content-Type: application/sdp
    Content-Length: 667
    //667 - Размер SDP пакета, о нем позже
    SETUP rtsp://10.112.28.231:554/live1.sdp/track1 RTSP/1.0
    CSeq: 3
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Transport: RTP/AVP;unicast;client_port=49501-49502
    RTSP/1.0 200 OK
    CSeq: 3
    Date: Tue, Jan 15 2013 02:02:56 GMT
    Transport: RTP/AVP;unicast;destination=10.112.28.33;source=10.112.28.231;client_port=49501-49502;server_port=6970-6971
    Session: 7BFE9DAA
    SETUP rtsp://10.112.28.231:554/live1.sdp/track2 RTSP/1.0
    CSeq: 4
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Transport: RTP/AVP;unicast;client_port=49503-49504
    Session: 7BFE9DAA
    RTSP/1.0 200 OK
    CSeq: 4
    Date: Tue, Jan 15 2013 02:02:56 GMT
    Transport: RTP/AVP;unicast;destination=10.112.28.33;source=10.112.28.231;client_port=49503-49504;server_port=6972-6973
    Session: 7BFE9DAA
    PLAY rtsp://10.112.28.231:554/live1.sdp RTSP/1.0
    CSeq: 5
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Session: 7BFE9DAA
    Range: npt=0.000-
    RTSP/1.0 200 OK
    CSeq: 5
    Date: Tue, Jan 15 2013 02:02:56 GMT
    Range: npt=0.000-
    Session: 7BFE9DAA
    RTP-Info: url=rtsp://10.112.28.231/live1.sdp/track1;seq=7746;rtptime=0,url=rtsp://10.112.28.231/live1.sdp/track2;seq=13715;rtptime=0
    


    Erinnern Sie sich an den
    Transport: RTP/AVP;unicast;destination=10.112.28.33;source=10.112.28.231;client_port=49501-49502;server_port=6970-6971

    Interleaved-Modus.
    Der Unterschied zum Non-Interleaved-Modus besteht darin, dass alle Pakete zum gleichen Port gestreamt werden.
    Ein Beispiel:

    OPTIONS rtsp://10.113.151.152:554/tcp_live/profile_token_0 RTSP/1.0
    CSeq: 1
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    RTSP/1.0 200 OK
    CSeq: 1
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Public: OPTIONS, DESCRIBE, SETUP, PLAY, TEARDOWN, SET_PARAMETER
    DESCRIBE rtsp://10.113.151.152:554/tcp_live/profile_token_0 RTSP/1.0
    CSeq: 2
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Accept: application/sdp
    RTSP/1.0 200 OK
    CSeq: 2
    Content-Type: application/sdp
    Content-Length: 316
    SETUP rtsp://10.113.151.152:554/tcp_live/profile_token_0/video/h264 RTSP/1.0
    CSeq: 3
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Transport: RTP/AVP/TCP;unicast;interleaved=0-1
    RTSP/1.0 200 OK
    CSeq: 3
    Session: 52cd95de
    Transport: RTP/AVP/TCP;interleaved=0-1;unicast
    SETUP rtsp://10.113.151.152:554/tcp_live/profile_token_0/audio/pcma RTSP/1.0
    CSeq: 4
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Transport: RTP/AVP/TCP;unicast;interleaved=2-3
    Session: 52cd95de
    RTSP/1.0 200 OK
    CSeq: 4
    Session: 52cd95de
    Transport: RTP/AVP/TCP;interleaved=2-3;unicast
    PLAY rtsp://10.113.151.152:554/tcp_live/profile_token_0 RTSP/1.0
    CSeq: 5
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Session: 52cd95de
    Range: npt=0.000-
    RTSP/1.0 200 OK
    CSeq: 5
    Session: 52cd95de
    


    Wir erinnern
    Transport: RTP/AVP/TCP;unicast;interleaved=0-1

    uns Jetzt schauen wir uns an, was und wie.
    Kameras senden Video und Audio an verschiedene RTP-Streams. 2n-Stream - Daten, 2n + 1-Stream - RTCP.
    Im Video gehen wir zu Kanal 0 und 1, im Audio zu Kanal 2 und 3.
    Nun schauen Sie, im ersten Fall werden die Ports angezeigt, im zweiten Fall die Kanäle. Im Non-Interleaved-Modus ist alles klar. Es ist nur so, dass RTP-Pakete in die Ports eingespeist werden und wie folgt gelesen werden können: Probleme beginnen mit dem Interleaved-Modus. In der Tat sollte es keine Probleme geben. Per RFC suchen wir nach dem magischen Zeichen "$", das nächste Byte ist der Kanal (es wird bei uns in der Verbindung 0-4 angezeigt) und 2 Bytes Länge. Nur 4 Bytes. Es gibt aber keine normalen Kameras. Beispielsweise "füllt" D-Ling DCS-2103 einige Daten nach einem RTP-Paket. Rahmen ergibt eine Größe von 1448,
    Transport: RTP/AVP;unicast;destination=10.112.28.33;source=10.112.28.231;client_port=49501-49502;server_port=6970-6971
    Transport: RTP/AVP/TCP;unicast;interleaved=0-1




    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
    s.receive(packet);





    sendet 1448 Frames und nach 827 Bytes eine Art Müll. (Dies ist, was Dlink DCS-2103 Firmware 1.00 und 1.20

    tut ) Und das passiert ständig für sie. Dies ist häufig bei chinesischen Kameras der Fall. Qihan (356) litt nicht darunter.
    Außer wie man diesen Müll überspringt, gibt es keine Ideen mehr.
    RTP gießt nützliche Daten. Beim Beschreiben von RTSP wird ein SDP-Paket zurückgegeben.
    Beispiele für SDP (h264, mjpeg, mpeg4):
    v=0
    o=- 1357245962093293 1 IN IP4 10.112.28.231
    s=RTSP/RTP stream 1 from DCS-2103
    i=live1.sdp with v2.0
    t=0 0
    a=type:broadcast
    a=control:*
    a=range:npt=0-
    a=x-qt-text-nam:RTSP/RTP stream 1 from DCS-2103
    a=x-qt-text-inf:live1.sdp
    m=video 0 RTP/AVP 96
    c=IN IP4 0.0.0.0
    b=AS:1500
    a=rtpmap:96 H264/90000
    a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-parameter-sets=Z2QAKK2EBUViuKxUdCAqKxXFYqOhAVFYrisVHQgKisVxWKjoQFRWK4rFR0ICorFcVio6ECSFITk8nyfk/k/J8nm5s00IEkKQnJ5Pk/J/J+T5PNzZprQCgDLSpAAAAwHgAAAu4YEAAPQkAABEqjve+F4RCNQ=,aO48sA==
    a=control:track1
    m=audio 0 RTP/AVP 97
    c=IN IP4 0.0.0.0
    b=AS:64
    a=rtpmap:97 G726-32/8000
    a=control:track2
    v=0
    o=- 1357245962095633 1 IN IP4 10.112.28.231
    s=RTSP/RTP stream 3 from DCS-2103
    i=live3.sdp with v2.0
    t=0 0
    a=type:broadcast
    a=control:*
    a=range:npt=0-
    a=x-qt-text-nam:RTSP/RTP stream 3 from DCS-2103
    a=x-qt-text-inf:live3.sdp
    m=video 0 RTP/AVP 26
    c=IN IP4 0.0.0.0
    b=AS:1500
    a=x-dimensions:640,360
    a=control:track1
    m=audio 0 RTP/AVP 97
    c=IN IP4 0.0.0.0
    b=AS:64
    a=rtpmap:97 G726-32/8000
    a=control:track2
    v=0
    o=- 1357245962094966 1 IN IP4 10.112.28.231
    s=RTSP/RTP stream 2 from DCS-2103
    i=live2.sdp with v2.0
    t=0 0
    a=type:broadcast
    a=control:*
    a=range:npt=0-
    a=x-qt-text-nam:RTSP/RTP stream 2 from DCS-2103
    a=x-qt-text-inf:live2.sdp
    m=video 0 RTP/AVP 96
    c=IN IP4 0.0.0.0
    b=AS:1500
    a=rtpmap:96 MP4V-ES/90000
    a=fmtp:96 profile-level-id=1;config=000001B001000001B509000001010000012000845D4C29402320A21F
    a=control:track1
    m=audio 0 RTP/AVP 97
    c=IN IP4 0.0.0.0
    b=AS:64
    a=rtpmap:97 G726-32/8000
    a=control:track2
    


    Lesen Sie mehr über SDP
    Da der Modus auf h264 mjpeg und aktuell war, werden wir sie berücksichtigen.
    Mit MJpeg ist alles sehr klar. Aber mit H264 beginnen die Unterschiede in den Kameras.
    Das h264-Format besteht aus Blöcken mit NAL-Headern ( 7.4.1 NAL-Einheitensemantik ).
    Um h264 dekodieren zu können, sind zusätzlich zu den Daten von h264 selbst SPS- (Sequenzparametersatz) und PPS- (Bildparametersatz) Daten erforderlich. Die erste beschreibt den Ablauf, die zweiten Parameter des Bildes. Da der h264-Codec selbst sehr wenig bekannt ist, erfolgt keine weitere Beschreibung. SPS ist Typ 7, PPS 8. Ohne sie kann h264 nicht decodiert werden.
    Das Interessanteste ist, dass Qihan SPS und PPS direkt in RTP-Paketen sendet, Dlink sendet sie nicht in RTP-Paketen. SPS und PPS werden jedoch im SDP-Paket im Parameter sprop-parameter-sets in der Base64-Codierung gesendet.
    sprop-parameter-sets=Z2QAKK2EBUViuKxUdCAqKxXFYqOhAVFYrisVHQgKisVxWKjoQFRWK4rFR0ICorFcVio6ECSFITk8nyfk/k/J8nm5s00IEkKQnJ5Pk/J/J+T5PNzZprQCgDLSpAAAAwHgAAAu4YEAAPQkAABEqjve+F4RCNQ=,aO48sA==
    Sie werden durch Kommas getrennt gesendet
    .
    //split по ','
    sps = Base64.decode(props[0].getBytes());
    pps = Base64.decode(props[1].getBytes());
    


    Da es sich bei den Kameras um 720p oder 1080p handelt, passen weder ein JPEG-Frame noch ein H264-Frame in ein RTP-Paket. Sie werden in Pakete geschnitten.
    RTP-Payload-Format für JPEG-komprimiertes Video Das
    RTP-Payload-Format für H.264-Video-

    JPEG-
    RTP-Paket enthält den Haupt-JPEG-Header
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       | Type-specific |              Fragment Offset                  |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |      Type     |       Q       |     Width     |     Height    |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    

    und dann kann es von Typ und Q variieren
    if(getType() < 64){
                return JPEG_HEADER_SIZE;
            } else if(getType() < 128){
                //we have 3.1.7.  Restart Marker header
                return JPEG_HEADER_SIZE + JPEG_RESTART_MARKER_HEADER_SIZE;
            }
    

    Um JPEG zu dekodieren, müssen Sie Quantisierungstabellen kennen oder berechnen.
    Bei meinen Kameras befanden sich die Quantisierungstabellen im JPEG-Starterpaket, daher wurden sie nur von dort übernommen.
    Alle Berechnungen erfolgen im RFC.
    Das letzte Rahmenpaket wird durch das RTP-Header-Markierungsbit berechnet. Wenn es 1 ist, ist dies das letzte Paket des Rahmens.

    H264
    NAL Header
          +---------------+
          |0|1|2|3|4|5|6|7|
          +-+-+-+-+-+-+-+-+
          |F|NRI|  Type   |
          +---------------+
    


    Single NAL Unit Packet
    Dies sind nur SPS und PPS. Typ = 7 oder Typ = 8
         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |F|NRI|  Type   |                                               |
        +-+-+-+-+-+-+-+-+                                               |
        |                                                               |
        |               Bytes 2..n of a single NAL unit                 |
        |                                                               |
        |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                               :...OPTIONAL RTP padding        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    


    Wenn der h264-Frame nicht in das RTP-Paket (1448 Byte) passt, wird der Frame in Fragmente geschnitten. (5.8. Fragmentation Units (FUs))
    Type = 28
         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        | FU indicator  |   FU header   |                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
        |                                                               |
        |                         FU payload                            |
        |                                                               |
        |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        |                               :...OPTIONAL RTP padding        |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    

    Diese Header folgen unmittelbar nach dem RTP-Header.
    public int getH264PayloadStart() {
            switch(getNAL().getType()){
                case NAL.FU_A:
                    return rtp.getPayloadStart() + 2;
                case NAL.SPS:
                case NAL.PPS:
                    return rtp.getPayloadStart();
                default:
                    throw new NotImplementedException("NAL type " + getNAL().getType() + " not implemented");
            }
        }
    


    Für h264 NAL-Decoder - die notwendigen Informationen. Wenn eine Frame-Fragmentierung durchgeführt wird, muss die NAL wiederhergestellt werden. (FU)
    Sie müssen die ersten 3 Bits vom FU-Indikator nehmen und mit den letzten 5 FU-Headern zusammenführen.

    Jetzt ist es am wichtigsten, den Stream zu speichern.
    JPEG
    public void writeRawJPEGtoStream(OutputStream out) throws IOException {
            //if(isMustBeZero()){
            if(isStart()){
                //first
                //System.out.println("first");
                byte[] headers = new byte[1024];
                int length = makeJpeg(headers);
                out.write(headers, 0, length);
                out.write(rtp.getBuffer(), getJPEGPayloadStart(), getJPEGPayloadLength());
            }else
            //if(getMarker()){
            if(isEnd()){
                //end
                //System.out.println("end");
                out.write(rtp.getBuffer(), getJPEGPayloadStart(), getJPEGPayloadLength());
                //EOI
            } else {
              //middle
                //System.out.println("middle");
                out.write(rtp.getBuffer(), getJPEGPayloadStart(), getJPEGPayloadLength());
            }
        }
    

    h264
    public static final byte[] NON_IDR_PICTURE = {0x00, 0x00, 0x00, 0x01};
    public void writeRawH264toStream(OutputStream out) throws IOException, NotImplementedException {
            switch (nal.getType()){
                case NAL.FU_A:    //FU-A, 5.8.  Fragmentation Units (FUs)/rfc6184
                    FUHeader fu = getFUHeader();
                    if(fu.isFirst()){
                        //if(debug) System.out.println("first");
                        out.write(H264RTP.NON_IDR_PICTURE);
                        out.write(getReconstructedNal());
                        out.write(rtp.getBuffer(), getH264PayloadStart(), getH264PayloadLength());
                    } else if(fu.isEnd()){
                        //if(debug) System.out.println("end");
                        out.write(rtp.getBuffer(), getH264PayloadStart(), getH264PayloadLength());
                    } else{
                        //if(debug) System.out.println("middle");
                        out.write(rtp.getBuffer(), getH264PayloadStart(), getH264PayloadLength());
                    }
                    break;
                case NAL.SPS: //Sequence parameter set
                case NAL.PPS: //Picture parameter set
                    //System.out.println("sps or pps write");
                    out.write(H264RTP.NON_IDR_PICTURE);
                    out.write(rtp.getBuffer(), rtp.getPayloadStart(), rtp.getPayloadLength());
                    break;
                default:
                    throw new NotImplementedException("NAL type " + getNAL().getType() + " not implemented");
            }
        }
    

    NON_IDR_PICTURE - zum Dekodieren von "Share" -Frames erforderlich. ( h264 )
    Hier muss ich korrigiert werden, da es sich nur um eine „Krücke“ handelt und es noch keine Rechtfertigung gibt. Es funktioniert einfach
    Der folgende Stream wird ausgegeben: 00000001 + SPS + 00000001 + PPS + 00000001 + NAL ...
    erlyvideo: 0,0,0,1 - Dies ist das AnnexB-Präfix des H264-Datensatzes. Dies ist kein Teil der H264 NAL-Einheit, sondern ein Trennzeichen zwischen den Einheiten.

    Nun, die Verarbeitung von "allem"
    while(!stop){
                    IRaw raw = rtp;
                    //читаем фрейм
                    try {
                        while(!frame.fill(in));
                        //полюбому читаем rtp пакет
                        rtp.fill(in, frame.getLength());
                        try {
                            raw = rtp.getByPayload();
                        } catch (NotImplementedException e) {
                            if(log.isLoggable(Level.FINE)) log.fine("rtp seq=" + rtp.getSequence() + ": " + e.getMessage());
                        }
                    } catch (SocketException e) {
                        log.warning(e.getMessage()); //socket closed?
                        break;
                    }
                    byte ch = frame.getChannel();
                    //RTCP? //прошивка D-link DCS2103 1.00 слала RTCP и interleaved
                    Source s = sources.get(source(ch));
                    if(rtp.getPayloadType() == RTPWrapper.TYPE_RTCP){
                        byte[] rb = new byte[frame.getLength()];
                        System.arraycopy(buffer, 0, rb, 0, rb.length);
                        s.lastRTCP = new RTCP(rb, rb.length);    //save last rtsp
                        s.lastRTCPTime = System.currentTimeMillis();
                        System.out.println(frame.getLength());
                    } else {
                        s.calculate(rtp); //вычисление для source параметров (для нужд RTCP)
                    }
                    if(os.length <= ch){
                        log.warning("Нужно больше out стримов: " + ch);
                        continue;
                    }
                    profiler.stop();
                    counter.count(profiler.getLast(), frame.getLength() / 1000.0);
                    //profiler.print(0);
                    if(os[ch] == null) continue;
                    //Нужна была синхронизация, так как os[ch] менялся, сейчас он постоянно rotator
                    synchronized (os[ch]){
                        raw.writeRawToStream(os[ch]);
                    }
                }
    

    in 2 Worten. Wir bekommen den RTSP Interleaved Frame (zum Beispiel Kanal: 0x00, 1448 Bytes), lesen 1448 Bytes, machen writeRawToStream, Polymorphismus macht den Trick.

    Dann muss es eingefahren werden. Um
    den RTSP-Fluss aufrechtzuerhalten, müssten Sie RTCP-Berichte erstellen, aber nein, es stellte sich heraus, dass alles einfacher war.

    GET_PARAMETER rtsp://10.112.28.231:554/live3.sdp RTSP/1.0
    CSeq: 7
    User-Agent: LibVLC/2.1.4 (LIVE555 Streaming Media v2014.01.21)
    Session: 327B23C6
    

    helme es einmal alle 55 Sekunden und das wars.

    Jetzt ist das Fahrrad selbst
    nur ein Programm, in dem Sie einen Link zur Kamera hinzufügen können (http oder rtsp) und es wird den Stream speichern. SQLite-Basis. "Normalisierung" eines Streams durch ffmpeg, Anzeigen durch Vlc.
    Keine erneute Verbindung nach Unterbrechung, Dateiproblemen usw.
    Es gibt keine halben Schecks und ähnliche Stücke.
    Wie sehen
    Buttons aus?
    1. Hinzufügen
    2. Löschen
    3. Rennen
    4. Halt an
    5. Archiv
    6. Anpassung
    7. Ausfahrt

    1

    Einstellungen :)
    2

    Archiv
    1. View - Startet Vlc
    2. Kleben und sehen - klebt Dateien und startet Vlc
    3. Ausfahrt

    3

    При простом просмотре генерируется m3u файл и кормится в VLC
    4

    При склеивании ffmpeg клеит, после запускается VLC
    5

    Программа нарезает поток на файлы, интервал задается в настройках

    Что делает ffmpeg:
    Клеит
    String command = String.format("%s -y -f concat -i concat.txt -codec copy concat.mp4",
    

    «Нормализует» (просчитывает заголовки и т.д.)
    String command = String.format("%s -i %s -codec copy %s",
                        settings.getFfmpegPath(),
                        settings.getFullTmpPath() + archive,
                        settings.getArchivePath() + "/" + settings.getRecPath() + "/" + archive + ".mp4")
    


    Am Ausgang befinden sich viele Dateien.
    6

    Sie können auf jeden OutputStream-
    Git-Hub schreiben .
    Möglicherweise gibt es keine weitere Programmlebensdauer. Vielleicht werde ich mal RTP-Klassen für Ton hinzufügen. (da ich noch SIP mag)

    Naja, das leckerste.
    Es gibt die Videoüberwachungsnorm ONVIF und
    professionelle Eisenstücke, die nur mit Kameras funktionieren.
    Es gibt Kameras, die daran arbeiten (Qihan, aka Proline), und RTSP-Links müssen googeln.
    Für die Verwaltung solcher Eisenstücke gibt es ein Open-Source-Produkt Onvif Device Manager.
    Ich habe das Programm ohne Autorisierung und mit Autorisierung um onvif-Unterstützung erweitert.
    7
    Git Hub

    In 2 Worten zu Onvif: Dies ist Seife.
    Die Arbeit ist einfach. 1. Helm POST-XML, 2.
    Holen Sie sich den XML- Code auf dem Github. Der Schalter -s speichert alle XML-Anforderungen und -Antworten.
    Beispiel anfordern:
    
    
    All
    
    
    
    

    Wenn Sie den obigen Links folgen, erhalten Sie die gesamte Dokumentation zu Onvif.
    Die Antwort lautet:
    
    
    
    
    http://10.112.28.231:80/onvif/device_service
    false
    falsefalse
    falsefalse
    truefalse
    falsefalse
    true
    12
    
    truefalse
    false
    false
    falsefalse
    falsefalse
    http://10.112.28.231:80/onvif/device_service
    false
    true
    false
    http://10.112.28.231:80/onvif/device_service
    http://10.112.28.231:80/onvif/device_service
    falsetrue
    true
    
    

    Die weitere unbefugte Kommunikation über onvif verläuft auf die gleiche Weise.

    Und hier ist ein Beispiel für Kommunikation, jedoch mit Autorisierung
    
    
    	
    		
    			admin
    			KSsJz8Lx0xPJd4pYdMuFblluNac=
    			Y2FsY09udmlm
    			2013-01-15T08:00:57.000Z
    		
    	
    
    
    

    Das heißt müssen eine Überschrift senden. (getestet auf D-Link DCS-2103, andere Kameras arbeiteten ohne Genehmigung, China).

    Zeitstempel (Erstellt)
    public static String getOnvifTimeStamp(DateTime dateTime){
            return String.format("%4d-%02d-%02dT%02d:%02d:%02d.000Z",
                    dateTime.getDate().getYear(),
                    dateTime.getDate().getMonth(),
                    dateTime.getDate().getDay(),
                    dateTime.getTime().getHour(),
                    dateTime.getTime().getMinute(),
                    dateTime.getTime().getSecond()
            );
        }
    

    Nonce
    public String getNonceDigest(){
            return base64(getNonce().getBytes());
        }
    

    und Passwort (Password_Digest = Base64 (SHA-1 (nonce + created + password))
    public String getPasswordDigest(){
            //Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )
            String line = getNonce() + timestamp + password;
            try {
                line = base64(sha1(line.getBytes()));
                return line;
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return "";
        }
    


    Всё было сделано в образовательных целях. Если есть вопросы и вдруг понадобиться более подробное описание чего либо — пишите.
    Надеюсь кому нибудь пригодится.

    PS Не надо писать в комментариях про организацию на большую букву «I». Их Server использует SQLite, SSL, avcodec (ffmpeg), а в папке \Resources есть божественный файлик с названием camera_list.json, но моя наглость не позволила его прикрутить к своей программе :) Но я не видел у них поддержку Onvif, видимо потому что они выпускают «свои» камеры. UPDATED: см комментарии от ivideon

    Если прикрутить к программе OpenVPN и OpenCV, то будет забавное решение и «велосипед»
    Ну и вот вам полезная ссылка на базу ссылок потоков камер

    Git hub:

    Jetzt auch beliebt: