def cleanup(self): """ Cleans up on exiting the application, i.e. the manipulation settings are reverted to normal settings. """ """ tc: http://lartc.org/manpages/tc.txt qdisc <OPERATOR=add|change|del|replace|link>: defines the operation to be done on the traffic control dev <DEVICE>: sets the device to set the traffic control for <NODE=root|parent>: node of the device to operate in """ # delete tc settings -> reset to default tc_cleanup_command = Command('tc') tc_cleanup_command.set_as_argument('QDISC-OPERATION', 'qdisc del') \ .set_as_argument('DEVICE', 'dev %s root' % STREAM_NETWORK_INTERFACE) self._cmd(tc_cleanup_command)
def __get_new_tc_add_command(): """ Generates and returns a command for the TC tool, which adds a qdisc-operation. :return: A TC command which adds a qdisc-operation :rtype: Command """ """ tc: http://lartc.org/manpages/tc.txt qdisc <OPERATOR=add|change|del|replace|link>: defines the operation to be done on the traffic control dev <DEVICE>: sets the device to set the traffic control for <NODE=root|parent>: node of the device to operate in """ tc_command = Command('tc') tc_command.set_as_argument('QDISC-OPERATION', 'qdisc add') \ .set_as_argument('DEVICE', 'dev %s root' % STREAM_NETWORK_INTERFACE) return tc_command
def __get_base_telchemy_command(self): """ Returns a basic telchemy command, which can be used for further specifications. :return: A basic telchemy command, which can be used for further specifications :rtype: Command """ telchemy_command = Command(self._parent.MANIPULATOR_PROGRAM_PATH) # specify markov model | NOTE: the P.NAMS/P.BNAMS model is not specified in here! if self.__is_markov_2_state: telchemy_command.set_as_posix_option('m', 2) elif self.__is_markov_4_state: telchemy_command.set_as_posix_option('m', 4) # specify loss insertion start time telchemy_command.set_as_posix_option('s', self._settings[TelchemyMarkovRes.DB_FIELD_START_AFTER]) # specify loss insertion end time telchemy_command.set_as_posix_option('e', self._settings[TelchemyMarkovRes.DB_FIELD_END_BEFORE]) return telchemy_command
def __get_general_encoding_command_without_destination(self, encoding_set, src_set, is_debug_mode): """ Returns the general encoding command without a destination path. After adding a destination path it can be directly executed or further modified (useful for twopass coding) :param encoding_set: the configuration set describing the encoding configuration :type encoding_set: dict :param src_set: the settings of the source to encode :type src_set: dict :param is_debug_mode: True is debug logging is allowed, False otherwise :type is_debug_mode: bool :return: the general encoding command without a destination path. :rtype: Command """ assert self._src_path != self.DEFAULT_SRC_PATH assert self._destination_path != self.DEFAULT_DESTINATION_PATH assert isinstance(encoding_set, dict) assert isinstance(src_set, dict) # build encoder command command = Command(APP_PATH) if EncodingTable.DB_TABLE_FIELD_NAME_ALTERNATIVE_COMMAND_LINE in encoding_set: self.__extend_command_with_alternative_command_line( command, encoding_set[EncodingTable.DB_TABLE_FIELD_NAME_ALTERNATIVE_COMMAND_LINE], src_set, is_debug_mode ) else: self.__extend_command_with_encoding_table_settings( command, encoding_set, src_set, is_debug_mode ) return command
def __handle_tcpdump_on_destination(self): """ Starts a "tcpdump" process, which captures packets transmitted over the network and collects them in a pre-specified destination file. :return: The tcpdump process which is used to dump the transmitted packets into the destination file :rtype: Process """ """ tcpdump: http://www.tcpdump.org/tcpdump_man.html -i <INPUT>: specifies input resource -w <OUTPUT>: specifies output resource to write pcap content additional filter used here: '<PROTOCOL> port <PORT>' --> Capture only all packets which are delivered via the <PROTOCOL> protocol over port <PORT> """ tcpdump_command = Command('tcpdump') tcpdump_command.set_as_subprocess() \ .set_as_posix_option('i', STREAM_NETWORK_INTERFACE) \ .set_as_posix_option('w', self._dst_file_path) \ .set_as_argument('PROTOCOL', STREAM_PROTOCOL_UDP) \ .set_as_argument('PORT', 'port %d' % STREAM_PORT) # set loggings if self._log_folder and self._log_suffix: tcpdump_log_file_path = self._get_log_file_path('tcpdump') tcpdump_command.set_as_log_file(tcpdump_log_file_path) \ .set_std_err_redirect_to_file() process = self._cmd(tcpdump_command) # wait a short time wherein the process is able to initialize itself if not self._is_dry_run: from time import sleep sleep(1) return process
def __replay_stream(self): """ Replays the pre-specified packet source stream. """ """ tcpreplay: http://tcpreplay.synfin.net/wiki/tcpreplay -i <NETWORK_INTERFACE>: replay packets to the interface <NETWORK_INTERFACE> <INPUT>: input resource to replay the packets from """ tcpreplay_command = Command('tcpreplay') tcpreplay_command.set_as_posix_option('i', STREAM_NETWORK_INTERFACE) \ .set_as_argument('INPUT', self._src_file_path) if self._log_folder: from os import devnull tcpreplay_log_file_path = self._get_log_file_path('tcpreplay') tcpreplay_command.set_std_err_redirect_to_std_out() \ .tee(tcpreplay_log_file_path + ' > ' + devnull) \ self._cmd(tcpreplay_command)
def manipulate(self): """ Performs the manipulation based on existing traces. """ telchemy_command = Command(self._parent.MANIPULATOR_PROGRAM_PATH) trace_file_path = self._path \ + TRACES_FOLDER_NAME \ + PATH_SEPARATOR \ + self._settings[TelchemyReadTraceRes.DB_FIELD_NAME_TRACE_FILE_NAME] assert isfile(trace_file_path) and exists(trace_file_path), \ "The specified trace file: `%s` is not a valid existing file!" % trace_file_path self._set_telchemy_command_file_input_output_options(telchemy_command) telchemy_command.set_as_posix_option('r', trace_file_path) # set loggings if self._log_folder and self._log_suffix: telchemy_log_file_path = self._get_log_file_path('telchemy') telchemy_command.set_as_log_file(telchemy_log_file_path) self._cmd(telchemy_command)
def __stream_source_by_hrc_set(self, src_id, hrc_set): """ Streams a source by the given settings of the HRC table :param src_id: the id of the source to send the stream :param hrc_set: the set which contains all information """ assert isinstance(src_id, int) assert isinstance(hrc_set, dict) codec = self._get_codec_by_hrc_set(hrc_set) file_path = self._path + STREAM_SOURCE_DIR + PATH_SEPARATOR + self._get_output_file_name( src_id, hrc_set, codec.get_raw_file_extension() ) if not isfile(file_path): raise Warning( 'Source %d could not be streamed, because no appropriate file has been found' % src_id ) pcap_path = self._path + STREAM_DESTINATION_DIR + PATH_SEPARATOR + self._get_output_file_name( src_id, hrc_set, STREAM_OUTPUT_FILE_TYPE_EXTENSION ) # check if the destination path already exists -> check override mode to skip or to override assert self._hrc_table.DB_TABLE_FIELD_NAME_HRC_ID in hrc_set if exists(pcap_path): if self._is_override_mode: if not self._is_dry_run: remove(pcap_path) ts_path = self._path + STREAM_SOURCE_DIR + PATH_SEPARATOR + self._get_output_file_name( src_id, hrc_set, 'ts' ) # remove also old ts conversion, if one exists! if exists(ts_path): remove(ts_path) print "# \033[95m\033[1mREMOVE src %d : hrc %d\033[0m"\ % (src_id, int(hrc_set[self._hrc_table.DB_TABLE_FIELD_NAME_HRC_ID])) else: assert self._hrc_table.DB_TABLE_FIELD_NAME_HRC_ID in hrc_set print "# \033[95m\033[1mSKIP src %d : hrc %d\033[0m"\ % (src_id, int(hrc_set[self._hrc_table.DB_TABLE_FIELD_NAME_HRC_ID])) return # setup coder coder_id = hrc_set[self._hrc_table.DB_TABLE_FIELD_NAME_CODER_ID] coder = get_validated_coder(coder_id, self._config.get_config_folder_path()) assert self._hrc_table.DB_TABLE_FIELD_NAME_STREAM_MODE in hrc_set stream_mode = hrc_set[self._hrc_table.DB_TABLE_FIELD_NAME_STREAM_MODE] if stream_mode == self._hrc_table.DB_STREAM_MODE_FIELD_VALUE_MPEGTS_UDP: file_path = self.__convert_to_mpeg2ts(file_path, codec.get_library_name()) coder.set_src_path(file_path) if self._log_folder: coder_log_file_path = self._log_folder \ + PATH_SEPARATOR \ + coder.__class__.__name__ \ + '_' \ + self._get_output_file_name(src_id, hrc_set, 'log') coder.set_log_file(coder_log_file_path) # # Activate tcp dump to record the streamed packets # """ tcpdump: http://www.tcpdump.org/tcpdump_man.html -i <INPUT>: specifies input resource -w <OUTPUT>: specifies output resource to write pcap content additional filter used here: '<PROTOCOL> port <PORT>' --> Capture only all packets which are delivered via the <PROTOCOL> protocol over port <PORT> """ tcpdump_command = Command('tcpdump') tcpdump_command.set_as_subprocess() \ .set_as_posix_option('i', STREAM_NETWORK_INTERFACE) \ .set_as_posix_option('w', pcap_path) \ .set_as_argument('PROTOCOL', STREAM_PROTOCOL_UDP) \ .set_as_argument('PORT', 'port %d' % STREAM_PORT) # set tcpdump log if self._log_folder: tcpdump_log_file_path = self._log_folder \ + PATH_SEPARATOR \ + 'tcpdump_' \ + self._get_output_file_name(src_id, hrc_set, 'log') tcpdump_command.set_as_log_file(tcpdump_log_file_path) \ .set_std_err_redirect_to_file() tcpdump_process = self._cmd(tcpdump_command) if not self._is_dry_run: from time import sleep sleep(1) # # Stream video # coder.set_dry_mode(self._is_dry_run) \ .send_stream( STREAM_SERVER, STREAM_PORT, stream_mode, codec ) # # Stop tcpdump # if isinstance(tcpdump_process, Process): self._terminate_process_with_children(tcpdump_process)
def __convert_to_mpeg2ts(self, input_path, codec_name): """ Converts an input file to a specific output format with MP4Box to MPEG2-TS :param input_path: the path to the file to convert :type input_path: basestring :param codec_name: the name of the codec to use for the conversion :type codec_name: basestring :return: the path where the converted file can be found after the operation succeeded :rtype: basestring """ assert isinstance(input_path, basestring) assert isinstance(codec_name, basestring) assert isfile(input_path) assert exists(input_path) """ ffmpeg: http://ffmpeg.org/ """ from coder.ffmpegCoder import APP_PATH as FFMPEG_PATH ffmpeg_command = Command(FFMPEG_PATH) """ i: input file """ ffmpeg_command.set_as_posix_option('i', input_path) """ c: codec used """ ffmpeg_command.set_as_posix_option('c:v', codec_name) """ set output file """ output_path = self._switch_file_extension(input_path, 'ts') ffmpeg_command.set_as_argument('OUTPUT', output_path) """ set log output """ if self._log_folder: from os.path import splitext, basename, extsep mp42ts_log_file_path = self._log_folder \ + PATH_SEPARATOR \ + 'mp42ts_' \ + splitext(basename(input_path))[0] \ + extsep \ + 'log' ffmpeg_command.set_as_log_file(mp42ts_log_file_path) \ .set_std_err_redirect_to_file() ffmpeg_process = self._cmd(ffmpeg_command) if isinstance(ffmpeg_process, Process): ffmpeg_process.join() return output_path
def send_stream(self, server, port, stream_mode, codec, is_debug_mode=_GLOBAL_DEBUG_MODE): """ Streams the ffmpeg video to a given server:port by a given protocol. :param server: the server to stream to :type port: int :param port: the port to stream to :type server: basestring :param stream_mode: the mode how to stream the video :type stream_mode: basestring :param codec: the codec used for the encoding of the video (required to set bit stream filters) :type codec: AbstractCodec :param is_debug_mode: True is debug logging is allowed, False otherwise :type is_debug_mode: bool """ assert isinstance(server, basestring) assert isinstance(port, int) assert isinstance(stream_mode, basestring) assert stream_mode in HrcTable.VALID_STREAM_MODES # build streaming command command = Command(APP_PATH) """ -re: play back in real-time """ command.set_as_posix_option('re') command.set_as_posix_option('y') """ -i <INPUT_FILE>: defines the input file """ command.set_as_posix_option('i', self._src_path) """ -c:v sets the video codec """ if stream_mode == HrcTable.DB_STREAM_MODE_FIELD_VALUE_MPEGTS_RTP: command.set_as_posix_option('c:v', codec.get_library_name()) # for MPEGTS_RTP required! else: command.set_as_posix_option('c:v', 'copy') """ -an (<OUTPUT>): disable audio output """ command.set_as_posix_option('an') """ -f <FMT> (<INPUT/OUTPUT>): force the input/output file format to <FMT>. In general the output format is automatically detected by the given input files, so this option is usually not needed. """ command.set_as_posix_option('f', self.__get_io_file_format(stream_mode)) """ -bsf:v <FILTER>: sets a filter operation on the stream """ if stream_mode in ( HrcTable.DB_STREAM_MODE_FIELD_VALUE_MPEGTS_UDP, HrcTable.DB_STREAM_MODE_FIELD_VALUE_MPEGTS_RTP ): bsf_name = codec.get_bit_stream_filter() if bsf_name: command.set_as_posix_option('bsf:v', bsf_name) if stream_mode == HrcTable.DB_STREAM_MODE_FIELD_VALUE_RAW_RTP: """ -sdp_file <SDP_FILE_PATH>: path where to dump the sdp file content """ # noinspection PyPep8Naming from os.path import splitext, extsep as FILE_EXTENSION_SEPARATOR (base_path, extension) = splitext(self._src_path) command.set_as_posix_option('sdp_file', base_path + FILE_EXTENSION_SEPARATOR + 'sdp') """ address where to send the stream to """ command.set_as_argument('DESTINATION', '%s://%s:%d' % (self.__get_stream_protocol(stream_mode), server, port)) # TODO only for debug # command.set_as_argument('DEST2', 'test.ts'); # TODO /only for debug """ set the commands log output """ command.set_as_log_file(self._log_file) \ .set_std_err_redirect_to_file() """ SET DEBUG LOG """ if is_debug_mode: command.set_as_posix_option('loglevel', 'debug') # execute command self._cmd(command)
def decode_video(self, is_debug_mode=_GLOBAL_DEBUG_MODE): """ Receives a video stream from the given stream configuration and returns a process which is able to decode this stream :param is_debug_mode: True, will allow debug logging of the command, False will disallow this. :type is_debug_mode: bool :param is_debug_mode: True is debug logging is allowed, False otherwise :type is_debug_mode: bool """ command = Command(APP_PATH) """ -y: override without asking """ command.set_as_posix_option('y') """ -i <INPUT>: defines the input stream """ command.set_as_posix_option('i', self._src_path) """ -c:v <CODEC_TYPE>: sets the video codec """ command.set_as_posix_option('c:v', 'rawvideo') """ <OUTPUT>: file where the decoded video should be stored in """ command.set_as_argument('DESTINATION', self._destination_path) """ set commands log output """ command.set_as_log_file(self._log_file) \ .set_std_err_redirect_to_file() """ SET DEBUG LOG """ if is_debug_mode: command.set_as_posix_option('loglevel', 'debug') # execute command return self._cmd(command)