На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Соблюдайте общие правила форума
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Указывайте точные версии Delphi и используемых сетевых библиотек.

Не приветствуется поднятие старых тем. Если ваш вопрос перекликается со старой темой, то для вопроса лучше создать новую тему, а старую указать в первом сообщении с описанием взаимосвязи.

Внимание:
попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Krid, user posted image Rouse_

Модераторы: Krid, Rouse_
Страницы: (3) 1 [2] 3  все  ( Перейти к последнему сообщению )  
> интерфейс RTSP(554)
    подумал... почитал... посмотрел...

    получилось сделать, на winsock отправку и приём текста для управления камерой
    после получения камерой команды PLAY, она начинает вещать/передавать уже по UDP, и в этом случае н придумал ничего лучшего как просто за биндить (BIND) рандомно выбранные порты
    выглядит это вот так:
    ExpandedWrap disabled
      procedure TRTSPSocket.SetError(error: Integer);
      begin
        Ferror := error;
      end;
       
      function TRTSPSocket.init (const ver: word; const socktype: integer; protocol: integer): boolean;
      var
        iResult: integer;
       
      begin
        Result := true;
        iResult := WSAStartup(Fver, vWSAData);
        if iResult<>0 then
          begin
            SetError(WSAGetLastError());
            exit(false);
          end;
       
        vSocket := socket(AF_INET, socktype, protocol);
        if vSocket = INVALID_SOCKET then
          begin
            SetError(WSAGetLastError());
            exit(false);
          end;
      end;
       
      function TRTSPSocket._GetLocalIP : string;
      var
        HostEnt : PHostEnt;
        Name : PAnsiChar;
        InAddr : PInAddr;
        h_addr_list : MarshaledAStringList;
       
      begin
        GetHostName( Name, $FF );
        HostEnt := GetHostByName( Name );
      //  Result := inet_ntoa( PInAddr( HostEnt.h_addr_list^ )^ );
        h_addr_list := HostEnt.h_addr_list;
        InAddr := PInAddr( h_addr_list^ );
        Result := inet_ntoa( InAddr^ );
      end;
       
      function TRTSPSocket.create(const AAddress: string; const APort: integer = 554; ASockType: integer = SOCK_STREAM; AProtocol: integer = IPPROTO_IP): boolean;
      var
        iResult, p : integer;
        a : string;
       
      begin
        if not init(Fver, ASockType, AProtocol) then
          begin
            SetError(WSAGetLastError());
            exit(false);
          end;
       
        a := _GetLocalIP;
        vSockAddrIn.sin_family := AF_INET;
        Randomize;
        p := Random( 65535 - 1024 ) + 1024;
        vSockAddrIn.sin_port := htons( p );
        vSockAddrIn.sin_addr.S_addr := inet_addr(PAnsiChar(AnsiString(a)));
      //  vSockAddrIn.sin_addr.S_addr := inet_addr(PAnsiChar(AnsiString('10.10.10.10')));
       
        vSockAddrOut.sin_family := AF_INET;
        vSockAddrOut.sin_port := htons(APort);
        vSockAddrOut.sin_addr.S_addr := inet_addr(PAnsiChar(AnsiString(AAddress)));
       
        iResult := bind(vSocket, vSockAddrIn, sizeof(vSockAddrIn));
        if iResult = SOCKET_ERROR then
          begin
            SetError(WSAGetLastError());
            exit(false);
          end;
      end;


    камера начинает передавать на нужн(ый/ые) порты данные, они иду кусками, сначала 31 байт, потом 15, потом валит несколько кусков по 1480 (примерно), далее, всё повторяется 31,15,... и так далее
    интересно то что если смотреть на лог liveMedia, то там сначала 20 байт, потом 4 и потом разные размеры без остановки
    я так понимаю у них читается только первый заголовок, а потом просто идёт складывание всех кусков (пакетов - ХЗ как эти части правильно назвать) и они пропускают следующие заголовки, но опять же не понятно почему такая разница в размерах: у меня 31 и 15 - у них 20 и 4

    по скольку с камеры прёт только видео h264 то значит получать его надо в структуру (или reord) описывающий данный стандарт (rfc6184), попытался отправить данные в такую структуру, но она как то не верно заполняется

    ExpandedWrap disabled
      /**
         Sequence Parameter Set
         @see 7.3.2.1 Sequence parameter set RBSP syntax
         @see read_seq_parameter_set_rbsp
         @see write_seq_parameter_set_rbsp
         @see debug_sps
      */
      typedef struct
      {
          int profile_idc;
          int constraint_set0_flag;
          int constraint_set1_flag;
          int constraint_set2_flag;
          int constraint_set3_flag;
          int constraint_set4_flag;
          int constraint_set5_flag;
          int reserved_zero_2bits;
          int level_idc;
          int seq_parameter_set_id;
          int chroma_format_idc;
          int residual_colour_transform_flag;
          int bit_depth_luma_minus8;
          int bit_depth_chroma_minus8;
          int qpprime_y_zero_transform_bypass_flag;
          int seq_scaling_matrix_present_flag;
            int seq_scaling_list_present_flag[8];
            int* ScalingList4x4[6];
            int UseDefaultScalingMatrix4x4Flag[6];
            int* ScalingList8x8[2];
            int UseDefaultScalingMatrix8x8Flag[2];
          int log2_max_frame_num_minus4;
          int pic_order_cnt_type;
            int log2_max_pic_order_cnt_lsb_minus4;
            int delta_pic_order_always_zero_flag;
            int offset_for_non_ref_pic;
            int offset_for_top_to_bottom_field;
            int num_ref_frames_in_pic_order_cnt_cycle;
            int offset_for_ref_frame[256];
          int num_ref_frames;
          int gaps_in_frame_num_value_allowed_flag;
          int pic_width_in_mbs_minus1;
          int pic_height_in_map_units_minus1;
          int frame_mbs_only_flag;
          int mb_adaptive_frame_field_flag;
          int direct_8x8_inference_flag;
          int frame_cropping_flag;
            int frame_crop_left_offset;
            int frame_crop_right_offset;
            int frame_crop_top_offset;
            int frame_crop_bottom_offset;
          int vui_parameters_present_flag;
          
          struct
          {
              int aspect_ratio_info_present_flag;
                int aspect_ratio_idc;
                  int sar_width;
                  int sar_height;
              int overscan_info_present_flag;
                int overscan_appropriate_flag;
              int video_signal_type_present_flag;
                int video_format;
                int video_full_range_flag;
                int colour_description_present_flag;
                  int colour_primaries;
                  int transfer_characteristics;
                  int matrix_coefficients;
              int chroma_loc_info_present_flag;
                int chroma_sample_loc_type_top_field;
                int chroma_sample_loc_type_bottom_field;
              int timing_info_present_flag;
                int num_units_in_tick;
                int time_scale;
                int fixed_frame_rate_flag;
              int nal_hrd_parameters_present_flag;
              int vcl_hrd_parameters_present_flag;
                int low_delay_hrd_flag;
              int pic_struct_present_flag;
              int bitstream_restriction_flag;
                int motion_vectors_over_pic_boundaries_flag;
                int max_bytes_per_pic_denom;
                int max_bits_per_mb_denom;
                int log2_max_mv_length_horizontal;
                int log2_max_mv_length_vertical;
                int num_reorder_frames;
                int max_dec_frame_buffering;
          } vui;
       
          struct
          {
              int cpb_cnt_minus1;
              int bit_rate_scale;
              int cpb_size_scale;
                int bit_rate_value_minus1[32]; // up to cpb_cnt_minus1, which is <= 31
                int cpb_size_value_minus1[32];
                int cbr_flag[32];
              int initial_cpb_removal_delay_length_minus1;
              int cpb_removal_delay_length_minus1;
              int dpb_output_delay_length_minus1;
              int time_offset_length;
          } hrd;
       
      } sps_t;
       
       
      /**
         Picture Parameter Set
         @see 7.3.2.2 Picture parameter set RBSP syntax
         @see read_pic_parameter_set_rbsp
         @see write_pic_parameter_set_rbsp
         @see debug_pps
      */
      typedef struct
      {
          int pic_parameter_set_id;
          int seq_parameter_set_id;
          int entropy_coding_mode_flag;
          int pic_order_present_flag;
          int num_slice_groups_minus1;
          int slice_group_map_type;
            int run_length_minus1[8]; // up to num_slice_groups_minus1, which is <= 7 in Baseline and Extended, 0 otheriwse
            int top_left[8];
            int bottom_right[8];
            int slice_group_change_direction_flag;
            int slice_group_change_rate_minus1;
            int pic_size_in_map_units_minus1;
            int slice_group_id[256]; // FIXME what size?
          int num_ref_idx_l0_active_minus1;
          int num_ref_idx_l1_active_minus1;
          int weighted_pred_flag;
          int weighted_bipred_idc;
          int pic_init_qp_minus26;
          int pic_init_qs_minus26;
          int chroma_qp_index_offset;
          int deblocking_filter_control_present_flag;
          int constrained_intra_pred_flag;
          int redundant_pic_cnt_present_flag;
       
          // set iff we carry any of the optional headers
          int _more_rbsp_data_present;
       
          int transform_8x8_mode_flag;
          int pic_scaling_matrix_present_flag;
             int pic_scaling_list_present_flag[8];
             int* ScalingList4x4[6];
             int UseDefaultScalingMatrix4x4Flag[6];
             int* ScalingList8x8[2];
             int UseDefaultScalingMatrix8x8Flag[2];
          int second_chroma_qp_index_offset;
      } pps_t;
       
       
      /**
        Slice Header
        @see 7.3.3 Slice header syntax
        @see read_slice_header_rbsp
        @see write_slice_header_rbsp
        @see debug_slice_header_rbsp
      */
      typedef struct
      {
          int first_mb_in_slice;
          int slice_type;
          int pic_parameter_set_id;
          int frame_num;
          int field_pic_flag;
            int bottom_field_flag;
          int idr_pic_id;
          int pic_order_cnt_lsb;
          int delta_pic_order_cnt_bottom;
          int delta_pic_order_cnt[ 2 ];
          int redundant_pic_cnt;
          int direct_spatial_mv_pred_flag;
          int num_ref_idx_active_override_flag;
          int num_ref_idx_l0_active_minus1;
          int num_ref_idx_l1_active_minus1;
          int cabac_init_idc;
          int slice_qp_delta;
          int sp_for_switch_flag;
          int slice_qs_delta;
          int disable_deblocking_filter_idc;
          int slice_alpha_c0_offset_div2;
          int slice_beta_offset_div2;
          int slice_group_change_cycle;
       
       
          struct
          {
              int luma_log2_weight_denom;
              int chroma_log2_weight_denom;
              int luma_weight_l0_flag[64];
              int luma_weight_l0[64];
              int luma_offset_l0[64];
              int chroma_weight_l0_flag[64];
              int chroma_weight_l0[64][2];
              int chroma_offset_l0[64][2];
              int luma_weight_l1_flag[64];
              int luma_weight_l1[64];
              int luma_offset_l1[64];
              int chroma_weight_l1_flag[64];
              int chroma_weight_l1[64][2];
              int chroma_offset_l1[64][2];
          } pwt; // predictive weight table
       
          struct // FIXME stack or array
          {
              int ref_pic_list_reordering_flag_l0;
              int ref_pic_list_reordering_flag_l1;
              int reordering_of_pic_nums_idc;
              int abs_diff_pic_num_minus1;
              int long_term_pic_num;
          } rplr; // ref pic list reorder
       
          struct // FIXME stack or array
          {
              int no_output_of_prior_pics_flag;
              int long_term_reference_flag;
              int adaptive_ref_pic_marking_mode_flag;
              int memory_management_control_operation;
              int difference_of_pic_nums_minus1;
              int long_term_pic_num;
              int long_term_frame_idx;
              int max_long_term_frame_idx_plus1;
          } drpm; // decoded ref pic marking
       
      } slice_header_t;
       
       
      /**
         Access unit delimiter
         @see 7.3.1 NAL unit syntax
         @see read_nal_unit
         @see write_nal_unit
         @see debug_nal
      */
      typedef struct
      {
          int primary_pic_type;
      } aud_t;
       
      /**
         Network Abstraction Layer (NAL) unit
         @see 7.3.1 NAL unit syntax
         @see read_nal_unit
         @see write_nal_unit
         @see debug_nal
      */
      typedef struct
      {
          int forbidden_zero_bit;
          int nal_ref_idc;
          int nal_unit_type;
          void* parsed; // FIXME
          int sizeof_parsed;
       
          //uint8_t* rbsp_buf;
          //int rbsp_size;
      } nal_t;
       
      typedef struct
      {
          int _is_initialized;
          int sps_id;
          int initial_cpb_removal_delay;
          int initial_cpb_delay_offset;
      } sei_buffering_t;
       
      typedef struct
      {
          int clock_timestamp_flag;
              int ct_type;
              int nuit_field_based_flag;
              int counting_type;
              int full_timestamp_flag;
              int discontinuity_flag;
              int cnt_dropped_flag;
              int n_frames;
       
              int seconds_value;
              int minutes_value;
              int hours_value;
       
              int seconds_flag;
              int minutes_flag;
              int hours_flag;
       
              int time_offset;
      } picture_timestamp_t;
       
      typedef struct
      {
        int _is_initialized;
        int cpb_removal_delay;
        int dpb_output_delay;
        int pic_struct;
        picture_timestamp_t clock_timestamps[3]; // 3 is the maximum possible value
      } sei_picture_timing_t;
       
       
      typedef struct
      {
        int rbsp_size;
        uint8_t* rbsp_buf;
      } slice_data_rbsp_t;
       
      /**
         H264 stream
         Contains data structures for all NAL types that can be handled by this library.  
         When reading, data is read into those, and when writing it is written from those.  
         The reason why they are all contained in one place is that some of them depend on others, we need to
         have all of them available to read or write correctly.
       */
      typedef struct
      {
          nal_t* nal;
          sps_t* sps;
          pps_t* pps;
          aud_t* aud;
          sei_t* sei; //This is a TEMP pointer at whats in h->seis...    
          int num_seis;
          slice_header_t* sh;
          slice_data_rbsp_t* slice_data;
       
          sps_t* sps_table[32];
          pps_t* pps_table[256];
          sei_t** seis;
       
      } h264_stream_t;
       
      typedef struct
      {
          int payloadType;
          int payloadSize;
          uint8_t* payload;
      } sei_t;

    это СИшное описание, переделал под Паскалевское


    live555
    брал данную библиотеку/программу для контроля получаемых данных, хочу сделать нечто подобное (пока с минимальным функционалом) на дельфях

    P.S. и для неё нужна камера, к которой можно данной прогой (из каталога testProgs) подцепится
      Цитата woojin @
      н придумал ничего лучшего как просто за биндить (BIND) рандомно выбранные порты

      Если порт уже кем-то занят, конструктор вывалит исключение, зачем оно тебе, если порт неважен? Делай в цикле до первого успеха.
      Цитата woojin @
      по скольку с камеры прёт только видео h264 то значит получать его надо в структуру (или reord) описывающий данный стандарт (rfc6184), попытался отправить данные в такую структуру, но она как то не верно заполняется

      А ты собираешься еще и видео сам проигрывать (в смысле, разбирать свойства, декодировать кадры, отображать на канвасе)? Если нет, то зачем тебе заголовок, просто скорми поток классу-плееру на свой вкус
        ВСЕХ С НАСТУПИВШИМ! УДАЧИ, СЧАСТЬЯ, УСПЕХОВ :crazy:

        Цитата Fr0sT @
        А ты собираешься еще и видео сам проигрывать (в смысле, разбирать свойства, декодировать кадры, отображать на канвасе)? Если нет, то зачем тебе заголовок, просто скорми поток классу-плееру на свой вкус

        нет конечно, не собираюсь
        приложение будет консольным, ему надо сохранять данный поток в файл (но использовать библиотеки типа "ffmpeg" не хочется для таких дел)

        хочется переложить (или написать аналог) данную программу с С/С++ на Pascal


        p.s. начал перекладывать потихоньку (как переложу, конечно покажу) и возник вопрос
        файл .hh
        ExpandedWrap disabled
          extern DelayInterval const DELAY_ZERO;
          extern DelayInterval const DELAY_SECOND;
          extern DelayInterval const DELAY_MINUTE;
          extern DelayInterval const DELAY_HOUR;
          extern DelayInterval const DELAY_DAY;

        файл cpp;
        ExpandedWrap disabled
          #ifndef INT_MAX
          #define INT_MAX 0x7FFFFFFF
          #endif
          const DelayInterval DELAY_ZERO(0, 0);
          const DelayInterval DELAY_SECOND(1, 0);
          const DelayInterval DELAY_MINUTE = 60*DELAY_SECOND;
          const DelayInterval DELAY_HOUR = 60*DELAY_MINUTE;
          const DelayInterval DELAY_DAY = 24*DELAY_HOUR;
          const DelayInterval ETERNITY(INT_MAX, MILLION-1);

        можно ли такое же сделать на паскале, у меня получается ни как правильно описать данные константы

        это оба файла целиком (без вступительных коментов)
        *.hh
        ExpandedWrap disabled
          #ifndef _DELAY_QUEUE_HH
          #define _DELAY_QUEUE_HH
           
          #ifndef _NET_COMMON_H
          #include "NetCommon.h"
          #endif
           
          #ifdef TIME_BASE
          typedef TIME_BASE time_base_seconds;
          #else
          typedef long time_base_seconds;
          #endif
           
          ///// A "Timeval" can be either an absolute time, or a time interval /////
           
          class Timeval {
          public:
            time_base_seconds seconds() const {
              return fTv.tv_sec;
            }
            time_base_seconds seconds() {
              return fTv.tv_sec;
            }
            time_base_seconds useconds() const {
              return fTv.tv_usec;
            }
            time_base_seconds useconds() {
              return fTv.tv_usec;
            }
           
            int operator>=(Timeval const& arg2) const;
            int operator<=(Timeval const& arg2) const {
              return arg2 >= *this;
            }
            int operator<(Timeval const& arg2) const {
              return !(*this >= arg2);
            }
            int operator>(Timeval const& arg2) const {
              return arg2 < *this;
            }
            int operator==(Timeval const& arg2) const {
              return *this >= arg2 && arg2 >= *this;
            }
            int operator!=(Timeval const& arg2) const {
              return !(*this == arg2);
            }
           
            void operator+=(class DelayInterval const& arg2);
            void operator-=(class DelayInterval const& arg2);
            // returns ZERO iff arg2 >= arg1
           
          protected:
            Timeval(time_base_seconds seconds, time_base_seconds useconds) {
              fTv.tv_sec = seconds; fTv.tv_usec = useconds;
            }
           
          private:
            time_base_seconds& secs() {
              return (time_base_seconds&)fTv.tv_sec;
            }
            time_base_seconds& usecs() {
              return (time_base_seconds&)fTv.tv_usec;
            }
           
            struct timeval fTv;
          };
           
          #ifndef max
          inline Timeval max(Timeval const& arg1, Timeval const& arg2) {
            return arg1 >= arg2 ? arg1 : arg2;
          }
          #endif
          #ifndef min
          inline Timeval min(Timeval const& arg1, Timeval const& arg2) {
            return arg1 <= arg2 ? arg1 : arg2;
          }
          #endif
           
          class DelayInterval operator-(Timeval const& arg1, Timeval const& arg2);
          // returns ZERO iff arg2 >= arg1
           
           
          ///// DelayInterval /////
           
          class DelayInterval: public Timeval {
          public:
            DelayInterval(time_base_seconds seconds, time_base_seconds useconds)
              : Timeval(seconds, useconds) {}
          };
           
          DelayInterval operator*(short arg1, DelayInterval const& arg2);
           
          extern DelayInterval const DELAY_ZERO;
          extern DelayInterval const DELAY_SECOND;
          extern DelayInterval const DELAY_MINUTE;
          extern DelayInterval const DELAY_HOUR;
          extern DelayInterval const DELAY_DAY;
           
          ///// _EventTime /////
           
          class _EventTime: public Timeval {
          public:
            _EventTime(unsigned secondsSinceEpoch = 0,
                  unsigned usecondsSinceEpoch = 0)
              // We use the Unix standard epoch: January 1, 1970
              : Timeval(secondsSinceEpoch, usecondsSinceEpoch) {}
          };
           
          _EventTime TimeNow();
           
          extern _EventTime const THE_END_OF_TIME;
           
           
          ///// DelayQueueEntry /////
           
          class DelayQueueEntry {
          public:
            virtual ~DelayQueueEntry();
           
            intptr_t token() {
              return fToken;
            }
           
          protected: // abstract base class
            DelayQueueEntry(DelayInterval delay);
           
            virtual void handleTimeout();
           
          private:
            friend class DelayQueue;
            DelayQueueEntry* fNext;
            DelayQueueEntry* fPrev;
            DelayInterval fDeltaTimeRemaining;
           
            intptr_t fToken;
            static intptr_t tokenCounter;
          };
           
          ///// DelayQueue /////
           
          class DelayQueue: public DelayQueueEntry {
          public:
            DelayQueue();
            virtual ~DelayQueue();
           
            void addEntry(DelayQueueEntry* newEntry); // returns a token for the entry
            void updateEntry(DelayQueueEntry* entry, DelayInterval newDelay);
            void updateEntry(intptr_t tokenToFind, DelayInterval newDelay);
            void removeEntry(DelayQueueEntry* entry); // but doesn't delete it
            DelayQueueEntry* removeEntry(intptr_t tokenToFind); // but doesn't delete it
           
            DelayInterval const& timeToNextAlarm();
            void handleAlarm();
           
          private:
            DelayQueueEntry* head() { return fNext; }
            DelayQueueEntry* findEntryByToken(intptr_t token);
            void synchronize(); // bring the 'time remaining' fields up-to-date
           
            _EventTime fLastSyncTime;
          };
           
          #endif

        .cpp
        ExpandedWrap disabled
          #include "DelayQueue.hh"
          #include "GroupsockHelper.hh"
           
          static const int MILLION = 1000000;
           
          ///// Timeval /////
           
          int Timeval::operator>=(const Timeval& arg2) const {
            return seconds() > arg2.seconds()
              || (seconds() == arg2.seconds()
              && useconds() >= arg2.useconds());
          }
           
          void Timeval::operator+=(const DelayInterval& arg2) {
            secs() += arg2.seconds(); usecs() += arg2.useconds();
            if (useconds() >= MILLION) {
              usecs() -= MILLION;
              ++secs();
            }
          }
           
          void Timeval::operator-=(const DelayInterval& arg2) {
            secs() -= arg2.seconds(); usecs() -= arg2.useconds();
            if ((int)useconds() < 0) {
              usecs() += MILLION;
              --secs();
            }
            if ((int)seconds() < 0)
              secs() = usecs() = 0;
           
          }
           
          DelayInterval operator-(const Timeval& arg1, const Timeval& arg2) {
            time_base_seconds secs = arg1.seconds() - arg2.seconds();
            time_base_seconds usecs = arg1.useconds() - arg2.useconds();
           
            if ((int)usecs < 0) {
              usecs += MILLION;
              --secs;
            }
            if ((int)secs < 0)
              return DELAY_ZERO;
            else
              return DelayInterval(secs, usecs);
          }
           
           
          ///// DelayInterval /////
           
          DelayInterval operator*(short arg1, const DelayInterval& arg2) {
            time_base_seconds result_seconds = arg1*arg2.seconds();
            time_base_seconds result_useconds = arg1*arg2.useconds();
           
            time_base_seconds carry = result_useconds/MILLION;
            result_useconds -= carry*MILLION;
            result_seconds += carry;
           
            return DelayInterval(result_seconds, result_useconds);
          }
           
          #ifndef INT_MAX
          #define INT_MAX 0x7FFFFFFF
          #endif
          const DelayInterval DELAY_ZERO(0, 0);
          const DelayInterval DELAY_SECOND(1, 0);
          const DelayInterval DELAY_MINUTE = 60*DELAY_SECOND;
          const DelayInterval DELAY_HOUR = 60*DELAY_MINUTE;
          const DelayInterval DELAY_DAY = 24*DELAY_HOUR;
          const DelayInterval ETERNITY(INT_MAX, MILLION-1);
          // used internally to make the implementation work
           
           
          ///// DelayQueueEntry /////
           
          intptr_t DelayQueueEntry::tokenCounter = 0;
           
          DelayQueueEntry::DelayQueueEntry(DelayInterval delay)
            : fDeltaTimeRemaining(delay) {
            fNext = fPrev = this;
            fToken = ++tokenCounter;
          }
           
          DelayQueueEntry::~DelayQueueEntry() {
          }
           
          void DelayQueueEntry::handleTimeout() {
            delete this;
          }
           
           
          ///// DelayQueue /////
           
          DelayQueue::DelayQueue()
            : DelayQueueEntry(ETERNITY) {
            fLastSyncTime = TimeNow();
          }
           
          DelayQueue::~DelayQueue() {
            while (fNext != this) {
              DelayQueueEntry* entryToRemove = fNext;
              removeEntry(entryToRemove);
              delete entryToRemove;
            }
          }
           
          void DelayQueue::addEntry(DelayQueueEntry* newEntry) {
            synchronize();
           
            DelayQueueEntry* cur = head();
            while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining) {
              newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining;
              cur = cur->fNext;
            }
           
            cur->fDeltaTimeRemaining -= newEntry->fDeltaTimeRemaining;
           
            // Add "newEntry" to the queue, just before "cur":
            newEntry->fNext = cur;
            newEntry->fPrev = cur->fPrev;
            cur->fPrev = newEntry->fPrev->fNext = newEntry;
          }
           
          void DelayQueue::updateEntry(DelayQueueEntry* entry, DelayInterval newDelay) {
            if (entry == NULL) return;
           
            removeEntry(entry);
            entry->fDeltaTimeRemaining = newDelay;
            addEntry(entry);
          }
           
          void DelayQueue::updateEntry(intptr_t tokenToFind, DelayInterval newDelay) {
            DelayQueueEntry* entry = findEntryByToken(tokenToFind);
            updateEntry(entry, newDelay);
          }
           
          void DelayQueue::removeEntry(DelayQueueEntry* entry) {
            if (entry == NULL || entry->fNext == NULL) return;
           
            entry->fNext->fDeltaTimeRemaining += entry->fDeltaTimeRemaining;
            entry->fPrev->fNext = entry->fNext;
            entry->fNext->fPrev = entry->fPrev;
            entry->fNext = entry->fPrev = NULL;
            // in case we should try to remove it again
          }
           
          DelayQueueEntry* DelayQueue::removeEntry(intptr_t tokenToFind) {
            DelayQueueEntry* entry = findEntryByToken(tokenToFind);
            removeEntry(entry);
            return entry;
          }
           
          DelayInterval const& DelayQueue::timeToNextAlarm() {
            if (head()->fDeltaTimeRemaining == DELAY_ZERO) return DELAY_ZERO; // a common case
           
            synchronize();
            return head()->fDeltaTimeRemaining;
          }
           
          void DelayQueue::handleAlarm() {
            if (head()->fDeltaTimeRemaining != DELAY_ZERO) synchronize();
           
            if (head()->fDeltaTimeRemaining == DELAY_ZERO) {
              // This event is due to be handled:
              DelayQueueEntry* toRemove = head();
              removeEntry(toRemove); // do this first, in case handler accesses queue
           
              toRemove->handleTimeout();
            }
          }
           
          DelayQueueEntry* DelayQueue::findEntryByToken(intptr_t tokenToFind) {
            DelayQueueEntry* cur = head();
            while (cur != this) {
              if (cur->token() == tokenToFind) return cur;
              cur = cur->fNext;
            }
           
            return NULL;
          }
           
          void DelayQueue::synchronize() {
            // First, figure out how much time has elapsed since the last sync:
            _EventTime timeNow = TimeNow();
            if (timeNow < fLastSyncTime) {
              // The system clock has apparently gone back in time; reset our sync time and return:
              fLastSyncTime  = timeNow;
              return;
            }
            DelayInterval timeSinceLastSync = timeNow - fLastSyncTime;
            fLastSyncTime = timeNow;
           
            // Then, adjust the delay queue for any entries whose time is up:
            DelayQueueEntry* curEntry = head();
            while (timeSinceLastSync >= curEntry->fDeltaTimeRemaining) {
              timeSinceLastSync -= curEntry->fDeltaTimeRemaining;
              curEntry->fDeltaTimeRemaining = DELAY_ZERO;
              curEntry = curEntry->fNext;
            }
            curEntry->fDeltaTimeRemaining -= timeSinceLastSync;
          }
           
           
          ///// _EventTime /////
           
          _EventTime TimeNow() {
            struct timeval tvNow;
           
            gettimeofday(&tvNow, NULL);
           
            return _EventTime(tvNow.tv_sec, tvNow.tv_usec);
          }
           
          const _EventTime THE_END_OF_TIME(INT_MAX);
        Сообщение отредактировано: woojin -
          Тут какая-то очередь, неясно зачем. Если надо только сохранять принятое (да еще и в консольном приложении), то никаких сложностей не вижу - блокирующие сокеты, простейший вариант. Коннектимся, пишем в сокет запрос, читаем ответ, откусываем заголовок, поток пишем в файл. Для отзывчивости перед каждым блокирующим вызовом (recv, send, connect) вызывать select с таймаутом. Всё.
            Цитата Fr0sT @
            Тут какая-то очередь, неясно зачем.

            вот и я не понял, а вообще такого же типа константу в delphi можно описать?
            Цитата Fr0sT @
            откусываем заголовок

            вот! именно!
            как откусить ХЗ сколько, по RFC там то ли 12 байт, то ли 12 бит, то ли все 32 байта
              Цитата woojin @
              вот и я не понял, а вообще такого же типа константу в delphi можно описать?

              const DELAY_SECOND: DelayInterval = (sec: 1, usec: 0);
              Но еще раз, с очередью какая-то странная муть, скорее всего, для твоих целей оно и не нужно.
              Цитата woojin @
              как откусить ХЗ сколько, по RFC там то ли 12 байт, то ли 12 бит, то ли все 32 байта

              Ну я имел в виду заголовок http ответа, весь заголовок бинарного потока по идее должен сохраниться.
                В аттаче к посту программа, в ней реализовано общение с трансляцией VLC-плеера. На молчаливый вопрос «почему не камера», ответ таков - пока нет ни одной камеры в офисе, к которой мне можно подключиться, жду закупки.
                Запускаем трансляцию в VLC, после этого запускаем прогу.

                Чтобы пошла трансляция, необходимо произвести такие шаги:
                - Жмём кнопку «Подключиться», после этого появится список команд
                - Жмём двойной клик на команде DESCRIBE – это отправит запрос на наличие потоков, к которым можно подключиться. Далее в списке появятся ссылки на доступные потоки. Все, которые начинаются там с «2=», это потоки видео. В этот же момент запоминается тип данных (96 – это видео в формате h264).
                - выбираем в списке ниже ту ссылку, которая начинается с 2= и жмём двойной клик на команде SETUP. От этого действия мы получаем идентификатор сессии, с помощью которого можно начинать получать видео.
                - жмём двойной клик на PLAY, после этого начинается передача видео на UDP-порт 54000.

                Теперь видео-кадры приходят. Отлично приходят, получаю их, нахожу смещение Payload, получаю RTP (обкурил RFC и эти материалы - https://habr.com/ru/post/117735/, https://habr.com/ru/post/233237/).
                Надеюсь, всё вышеперечисленное сможет кому-то помочь, включая проблему, оставшуюся без ответа в этом топике. В приложенном коде кроме описанного также присутствует:
                - отправка «логического» пинга, чтобы связь не обрывалась, по таймеру, который нужен источнику.
                - запоминание SPS и PPS кадров, потому что от VLC и многих камер, они просто не приходят

                И вот тут начинаются проблемы… Вроде всё сделано по инструкции, но внезапно оказалось, что тип кадра 5 (опорный) не приходит в пакетах с маркером конца пакета. Иногда он может быть у одного из «серединных» пакетов кадра. Тип кадра беру как последние 5 бит второго байта RTP-пакета если пакет – часть кадра или как последние 5 бит первого байта RTP-пакета, если кадр целиком уместился в пакет. При этом, по итогу сохранения данных, я вполне наблюдаю определённую периодичность бОльших, чем другие кадров.
                Помогите, пожалуйста, разобраться, где я промахнулся с получением типа кадра.

                Прошу прощения за некропост, но мне кажется, что тут в топике есть некоторая недосказанность, которая у меня уже решена. И в то же самое время, наступил тупик через несколько шагов. Если вы поможете мне из него выбраться, буду очень благодарен.

                Если будете запускать прогу до ознакомления с содержимым, то на этот случай предупреждаю - засирает папку файлами, в которые сохраняются RTP-пакеты, для отладочных целей.

                Прикреплённый файлПрикреплённый файлRTSPProtocol.rar (8,94 Кбайт, скачиваний: 976)
                  Не очень активная тема, к сожалению ...

                  В общем, решил я свой вопрос. Не разбирался непосредственно в проблеме, скорей всего неправильные сдвиги при распарсивании пакета. Просто сделал такие переделки:
                  - WinSock вместо Indy
                  - interleaved вместо non-interleaved
                  - ну и камеру подвезли, вместо эмулятора VLC

                  Получаемые кадры отлично скармливаются декодеру, картинка есть. В прилагаемом примере нет работы с авторизацией и логического пинга. Однако, работа непосредственно с RTP налажена. Забирайте кому надо :).
                  Прикреплённый файлПрикреплённый файлRTSPProtocol.rar (36,29 Кбайт, скачиваний: 957)
                    Скачал исходник, при компиляции ругается на отсутствующий модуль cBaseThread_TH

                    Добавлено
                    Lem0nti не думал реализовать трансляцию RTSP потока?
                      Там есть dcu для тех модулей, исходники которых включать неуместно. Не удаляйте их и всё срастётся.

                      Нет, не думал.
                      Но с трансляцией как есть всё просто - берём кадры как есть в h264 и пересылаем их куда надо. Собственно, у меня так работает. Конечно, если надо раздавать обязательно в соответствии с RFC и потребители видео условно неизвестны, то это может не помочь.
                        Lem0nti Есть коммерческое предложение, нужно сделать RTSP клиент который способен получить аудио-видео поток от видеокамеры/видеорегистратора кроме того, нужно писать этот поток на HDD, и после этого еще раздавать нуждающмся клиентам, их адреса заранее не известны

                        Добавлено
                        Lem0nti ни в какую не компилирует без этих юнитов, на DCUхи он и не смотрит

                        Добавлено
                        Lem0nti пока курил эту тему узнал что DCU годится при одинаковых версиях компилятора
                          По dcu - сделано в 10.2. Если она недосутпна, то вы можете попробовать адаптировать парсинг пакета из его текущей обёртки. TBaseThread это наследник от потока, ожидающий элементы очереди, а TThreadSignalledQueue это просто потокозащищённый наследник от TQueue.
                            Lem0ntiБоюсь что у меня нет таких знаний, проверьте лс
                              Добрый день.
                              У меня та же беда, старался поймать поток с камеры, но не получилось.
                              Что я делал:
                              1. Есть камеры ДАХУА -с них поток поймало по HTTP и скриншот сделало из потока .
                              Ну в VLC плеере работает так: rtsp://admin:admin@172.16.42.12:554/cam/realmonitor?channel=1&subtype=0
                              ExpandedWrap disabled
                                var
                                  Form1: TForm1;
                                  memorystream: TMemoryStream;
                                  Jpeg:  TJpegImage;
                                  aaa:string;
                                  Error:string;
                                 
                                implementation
                                 
                                {$R *.dfm}
                                 
                                procedure TForm1.BitBtn1Click(Sender: TObject);
                                begin
                                      memorystream.Clear;
                                      // edit1.Text  ---->  http://admin:admin@172.16.42.12:8080/cgi-bin/snapshot.cgi?channel1
                                      try
                                          NetHTTPClient1.Get (edit1.Text, memorystream);
                                          memorystream.SaveToFile('A_Teste.jpeg');
                                      except
                                              on E: Exception do
                                              begin
                                                      Error:=e.ToString();
                                                      showmessage(' Ошибка= '+Error);
                                              end;
                                      end;
                                end;



                              2. Есть иная камера , "HeroSpeed" ,location="Guangzhou", 172.16.42.11
                              Через VLC плеер пашет = rtsp://admin:admin@172.16.42.11:554/cam/realmonitor?channel=1&subtype=0
                              и так пашет = rtsp://admin:admin@172.16.42.11:554/cam/realmonitor
                              и так пашет = rtsp://admin:admin@172.16.42.11:8080/0
                              и так пашет = rtsp://admin:admin@172.16.42.11:554/0
                              но через DELPHI - не хочет по HTTP.
                              НЕ пашет = http://admin:admin@172.16.42.11:8080/cgi-b...ot.cgi?channel1

                              Может кто-то подсказать по этой камере, как ее заставить работать ?
                                Потому что это не HTTP-протокол. Если вы скачаете пример выше, то там есть как организовать общение с камерой по RTSP.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) 1 [2] 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0637 ]   [ 21 queries used ]   [ Generated: 28.03.24, 17:45 GMT ]