def _destroy_pdraw(self): ret = True if self.pdraw_demuxer: if not self.pdraw: self.logger.error( "Cannot destroy pdraw demuxer: a NULL pdraw session") return False self.logger.info("destroying pdraw demuxer...") res = od.pdraw_demuxer_destroy(self.pdraw, self.pdraw_demuxer) if res != 0: self.logger.error(f"cannot destroy pdraw demuxer {res}") ret = False else: self.logger.info("pdraw demuxer destroyed") self.pdraw_demuxer = od.POINTER_T(od.struct_pdraw_demuxer)() if self.pdraw: self.logger.info("destroying pdraw...") res = od.pdraw_destroy(self.pdraw) if res != 0: self.logger.error(f"cannot destroy pdraw {res}") ret = False else: self.logger.info("pdraw destroyed") self.pdraw = od.POINTER_T(od.struct_pdraw)() return ret
def listen(self): if self._listening: self.logger.info("Already listening") return True res = od.arsdk_publisher_net_new( self._backend._backend_net, self._thread_loop.pomp_loop, ctypes.c_char_p(), ctypes.byref(self._publisher_net), ) if res < 0: self.logger.error(f"arsdk_publisher_net_new: {res}") return False res = od.arsdk_backend_net_start_listen(self._backend._backend_net, ctypes.byref(self._listen_cbs), self._dcport) if res < 0: od.arsdk_publisher_net_destroy(self._publisher_net) self._publisher_net = od.POINTER_T(od.struct_arsdk_publisher_net)() self.logger.error(f"arsdk_backend_net_start_listen: {res}") return False # start net publisher res = od.arsdk_publisher_net_start( self._publisher_net, ctypes.byref(self._publisher_net_cfg)) if res < 0: od.arsdk_backend_net_stop_listen(self._backend._backend_net) od.arsdk_publisher_net_destroy(self._publisher_net) self._publisher_net = od.POINTER_T(od.struct_arsdk_publisher_net)() self.logger.error(f"arsdk_publisher_net_start: {res}") return False self._listening = True return True
def info(self): """ Returns a dictionary of video frame info """ if self._frame_info is not None: return self._frame_info frame = self._get_video_frame() if not frame: return self._frame_info ancillary_data = od.POINTER_T(od.struct_mbuf_ancillary_data)() self._mbuf.get_ancillary_data(frame, od.PDRAW_ANCILLARY_DATA_KEY_VIDEOFRAME, ctypes.byref(ancillary_data)) pdraw_video_frame_size = ctypes.c_size_t() pdraw_video_frame = ctypes.cast( od.mbuf_ancillary_data_get_buffer( ancillary_data, ctypes.byref(pdraw_video_frame_size)), od.POINTER_T(od.struct_pdraw_video_frame), ) assert pdraw_video_frame_size.value == ctypes.sizeof( od.struct_pdraw_video_frame) # FIXME: workaround bug in pdraw ancillary data API frame_type = self._stream["frame_type"] pdraw_video_frame_copy = ctypes.pointer( self._pdraw_video_frame_storage) pdraw_video_frame_copy.contents = pdraw_video_frame.contents pdraw_video_frame = pdraw_video_frame_copy pdraw_video_frame.contents.format = frame_type if frame_type == od.VDEF_FRAME_TYPE_CODED: res = self._mbuf_vt[frame_type].get_frame_info( self._get_video_frame(), pdraw_video_frame.contents.pdraw_video_frame_0.coded, ) else: res = self._mbuf_vt[frame_type].get_frame_info( self._get_video_frame(), pdraw_video_frame.contents.pdraw_video_frame_0.raw, ) if res < 0: self.logger.error( f"mbuf_raw/coded_video_frame_get_frame_info returned error {res}" ) return self._frame_info # convert the binary metadata into json self._frame_info = {} jsonbuf = ctypes.create_string_buffer(4096) res = od.pdraw_video_frame_to_json_str(pdraw_video_frame, self._vmeta_frame, jsonbuf, ctypes.sizeof(jsonbuf)) if res < 0: self.logger.error( f"pdraw_frame_metadata_to_json returned error {res}") else: self._frame_info = json.loads(str(jsonbuf.value, encoding="utf-8")) return self._frame_info
def _pop_stream_buffer(self, id_): buf = od.POINTER_T(od.struct_vbuf_buffer)() ret = od.vbuf_queue_pop(self.streams[id_]['video_queue'], 0, ctypes.byref(buf)) if ret < 0: if ret != -errno.EAGAIN: self.logging.error('vbuf_queue_pop returned error %d' % ret) buf = od.POINTER_T(od.struct_vbuf_buffer)() elif not buf: self.logging.error('vbuf_queue_pop returned NULL') return buf
def _do_create(self): # default userdata callback argument self.userdata = ctypes.c_void_p() # Create the arsdk_ctrl arsdk_ctrl = od.POINTER_T(od.struct_arsdk_ctrl)() res = od.arsdk_ctrl_new(self._thread_loop.pomp_loop, ctypes.byref(arsdk_ctrl)) backend_net = od.POINTER_T(od.struct_arsdkctrl_backend_net)() arsdk_ctrl_device_cbs = od.struct_arsdk_ctrl_device_cbs.bind({ "added": self._device_added_cb, "removed": self._device_removed_cb }) # Send a command to add callbacks to the arsdk_ctrl res = od.arsdk_ctrl_set_device_cbs(arsdk_ctrl, arsdk_ctrl_device_cbs) if res != 0: raise RuntimeError("arsdk_ctrl_set_device_cbs: {}".format(res)) self.logger.info("device callbacks have been added to arsdk_ctrl") # Create the net backend cfg = od.struct_arsdkctrl_backend_net_cfg( ctypes.create_string_buffer(b"net_config")) cfg.stream_supported = 1 res = od.arsdkctrl_backend_net_new(arsdk_ctrl, ctypes.pointer(cfg), ctypes.byref(backend_net)) if res != 0: raise RuntimeError("arsdkctrl_backend_net_new: {}".format(res)) self.logger.debug("New net backend has been created") backend_net_socket_callback = od.arsdkctrl_backend_net_socket_cb_t( lambda *args: self._socket_cb(*args)) res_set_socket = od.arsdkctrl_backend_net_set_socket_cb( backend_net, backend_net_socket_callback, self.userdata) if res_set_socket != 0: raise RuntimeError( "arsdkctrl_backend_net_set_socket_cb: {}".format(res)) self.logger.debug("Set backend socket callback OK") return ( arsdk_ctrl, arsdk_ctrl_device_cbs, backend_net, backend_net_socket_callback, )
def _destroy(self): res = od.vbuf_pool_destroy(self.yuv_packed_buffer_pool) if res != 0: self.logging.logE("Cannot destroy yuv packed buffer pool") self.yuv_packed_buffer_pool = od.POINTER_T(od.struct_vbuf_pool)() if self.pdraw: res = od.pdraw_destroy(self.pdraw) if res != 0: self.logging.logE("Cannot destroy pdraw object") self.pdraw = od.POINTER_T(od.struct_pdraw)() self.logging.logI("pdraw destroyed") return True
def _pop_stream_buffer(self, id_): frame_type = self.streams[id_]['frame_type'] mbuf_video_frame = od.POINTER_T( self.video_sink_vt[frame_type].mbuf_video_frame_type)() res = self.video_sink_vt[frame_type].queue_pop( self.streams[id_]['video_queue'], ctypes.byref(mbuf_video_frame)) if res < 0: if res not in (-errno.EAGAIN, -errno.ENOENT): self.logger.error( f"mbuf_coded_video_frame_queue_pop returned error {res}") mbuf_video_frame = od.POINTER_T( self.video_sink_vt[frame_type].mbuf_video_frame_type)() elif not mbuf_video_frame: self.logger.error('mbuf_coded_video_frame_queue_pop returned NULL') return mbuf_video_frame
def _media_removed(self, pdraw, media_info, userdata): id_ = media_info.contents.id if id_ not in self.streams: self.logging.error( 'Received removed event from unknown ID {}'.format(id_)) return self.logging.info("_media_removed called id : {}".format(id_)) # FIXME: Workaround media_removed called with destroyed media if not self.pdraw: self.logging.error( "_media_removed called with a destroyed pdraw id : {}".format( id_)) return with self.streams[id_]['video_sink_lock']: if self.streams[id_]['video_queue_event']: self.callbacks_thread_loop.remove_event_from_loop( self.streams[id_]['video_queue_event']) self.streams[id_]['video_queue_event'] = None if not self.streams[id_]['video_sink']: self.logging.error( 'pdraw_video_sink for media_id {} has already been stopped' .format(id_)) return res = od.pdraw_stop_video_sink(pdraw, self.streams[id_]['video_sink']) if res < 0: self.logging.error('pdraw_stop_video_sink() returned %s' % res) self.streams[id_]['video_queue'] = None self.streams[id_]['video_sink'] = od.POINTER_T( od.struct_pdraw_video_sink)()
def _get_pdraw_video_frame(self): if self._yuv_packed_video_frame: return self._yuv_packed_video_frame if self._pdraw_video_frame: return self._pdraw_video_frame res = od.vbuf_metadata_get( self._buf, self._stream['video_sink'], od.POINTER_T(ctypes.c_uint32)(), od.POINTER_T(ctypes.c_uint64)(), ctypes.byref(self._pdraw_video_frame)) if res < 0: self.logging.logE( 'vbuf_metadata_get returned error {}'.format(res)) self._pdraw_video_frame = od.POINTER_T(ctypes.c_ubyte)() return self._pdraw_video_frame self._pdraw_video_frame = ctypes.cast( self._pdraw_video_frame, od.POINTER_T(od.struct_pdraw_video_frame)) if self._stream['type'] == od.PDRAW_VIDEO_MEDIA_FORMAT_H264: return self._pdraw_video_frame if not self._yuv_packed_buffer: res = od.vbuf_pool_get( self._yuv_packed_buffer_pool, 0, ctypes.byref(self._yuv_packed_buffer) ) if res < 0: self.logging.logE( 'vbuf_pool_get returned error {}'.format(res)) return self._yuv_packed_video_frame self._yuv_packed_video_frame = ctypes.pointer( self._yuv_packed_video_frame_storage) res = od.pdraw_pack_yuv_frame( self._pdraw_video_frame, self._yuv_packed_video_frame, self._yuv_packed_buffer) if res < 0: self._yuv_packed_video_frame = od.POINTER_T( od.struct_pdraw_video_frame)() self.logging.logE( 'pdraw_pack_yuv_frame returned error {}'.format(res)) return self._yuv_packed_video_frame
def __init__(self, logging, buf, media_id, stream, yuv_packed_buffer_pool, session_metadata): self.logging = logging self._buf = buf self._media_id = media_id self._stream = stream self._yuv_packed_buffer_pool = yuv_packed_buffer_pool self._session_metadata = session_metadata self._pdraw_video_frame = od.POINTER_T(ctypes.c_ubyte)() self._frame_pointer = ctypes.POINTER(ctypes.c_ubyte)() self._frame_size = 0 self._frame_array = None self._yuv_packed_buffer = od.POINTER_T(od.struct_vbuf_buffer)() self._yuv_packed_video_frame_storage = od.struct_pdraw_video_frame() self._yuv_packed_video_frame = od.POINTER_T( od.struct_pdraw_video_frame)() self._frame_info = None self._metadata_pointers = []
def _on_close_resp_done(self, close_resp_future): if close_resp_future.cancelled(): # FIXME: workaround pdraw closing timeout # This random issue is quiet hard to reproduce self.logging.error("Closing Pdraw timedout") if self.pdraw: self.pdraw_thread_loop.run_later(od.pdraw_destroy, self.pdraw) self.pdraw = od.POINTER_T(od.struct_pdraw)() self.state = PdrawState.Error self.logging.error("Pdraw has been closed")
def __init__(self, logger, mbuf_video_frame, media_id, stream, session_metadata): self.logger = logger self._mbuf_video_frame = mbuf_video_frame self._media_id = media_id self._stream = stream self._session_metadata = session_metadata self._mbuf = self._mbuf_vt[self._stream["frame_type"]] self._frame_pointer = ctypes.c_void_p() self._frame_size = ctypes.c_size_t() self._frame_array = None self._packed_buffer = od.POINTER_T(od.struct_mbuf_mem)() self._packed_video_frame = od.POINTER_T(self._mbuf.frame_type)() self._frame_info = None self._vmeta_frame = od.POINTER_T(od.struct_vmeta_frame)() self._metadata_pointers = [] self._pdraw_video_frame_storage = od.struct_pdraw_video_frame()
def __init__(self, backend, ip_addr, device_types=None): super().__init__(backend=backend) if device_types is None: device_types = DEVICE_TYPE_LIST self._device_types = device_types ctypes_device_type_list = (ctypes.c_int * len(device_types))(*device_types) self.discovery_cfg = od.struct_arsdk_discovery_cfg( ctypes.cast(ctypes_device_type_list, od.POINTER_T(od.arsdk_device_type)), len(ctypes_device_type_list), ) self.ip_addr = ip_addr
def _create_discovery(self): discovery = od.POINTER_T(od.struct_arsdk_discovery)() backendparent = od.arsdkctrl_backend_net_get_parent(self._backend._backend_net) res = od.arsdk_discovery_new( b"netraw", backendparent, self._backend._arsdk_ctrl, ctypes.byref(discovery) ) if res != 0: raise RuntimeError(f"Unable to create raw discovery:{res}") return discovery
def StreamFactory(): return { 'id': None, 'id_userdata': ctypes.c_void_p(), 'type': od.PDRAW_VIDEO_MEDIA_FORMAT_UNKNOWN, 'h264_header': None, 'video_sink': od.POINTER_T(od.struct_pdraw_video_sink)(), 'video_sink_lock': threading.RLock(), 'video_queue': None, 'video_queue_event': None, }
def _destroy(self): if self.pdraw: self.logging.info("destroying pdraw...") res = od.pdraw_destroy(self.pdraw) if res != 0: self.logging.error("cannot destroy pdraw {}".format(res)) else: self.logging.info("pdraw destroyed") if self.yuv_packed_buffer_pool: self.logging.info("destroying yuv buffer pool...") res = od.vbuf_pool_destroy(self.yuv_packed_buffer_pool) if res != 0: self.logging.error( "cannot destroy yuv packed buffer pool: {}".format(res)) else: self.logging.info("yuv buffer pool destroyed") self.yuv_packed_buffer_pool = od.POINTER_T(od.struct_vbuf_pool)() self.pdraw = od.POINTER_T(od.struct_pdraw)() if self.pdraw_thread_loop.stop(): self.logging.info("pdraw thread loop stopped") return True
def _pdraw_new(self): res = od.pdraw_new( self.pomp_loop, self.pdraw_cbs, ctypes.cast(ctypes.pointer(ctypes.py_object(self)), ctypes.c_void_p), ctypes.byref(self.pdraw)) if res != 0: self.logger.error(f"Error while creating pdraw interface: {res}") self.pdraw = od.POINTER_T(od.struct_pdraw)() return False else: self.logger.info("Pdraw interface has been created") return True
def _on_close_resp_done(self, close_resp_future): if close_resp_future.cancelled(): # FIXME: workaround pdraw closing timeout # This random issue is quiet hard to reproduce self.logging.logE("Closing Pdraw timedout") if self.pdraw: res = od.pdraw_destroy(self.pdraw) if res != 0: self.logging.logE("Cannot destroy pdraw object") self.pdraw = od.POINTER_T(od.struct_pdraw)() self._state = State.Closed self.logging.logE("Pdraw has been closed")
def init(self, *, pdraw, media_id=0): self._pdraw = pdraw self._media_id = media_id self._pdraw_renderer = od.POINTER_T(od.struct_pdraw_video_renderer)() self._render_zone = od.struct_pdraw_rect(0, 0, self.width, self.height) self._renderer_params = od.struct_pdraw_video_renderer_params.bind({ "fill_mode": od.PDRAW_VIDEO_RENDERER_FILL_MODE_FIT_PAD_BLUR_EXTEND, "enable_transition_flags": od.PDRAW_VIDEO_RENDERER_TRANSITION_FLAG_ALL, "enable_hmd_distortion_correction": 0, "video_scale_factor": 1.0, "enable_overexposure_zebras": 0, "overexposure_zebras_threshold": 1.0, "enable_histograms": 0, "video_texture_width": self.width, "video_texture_dar_width": self.width, "video_texture_dar_height": self.height, }) self._media_infos = dict() self._renderer_cbs = od.struct_pdraw_video_renderer_cbs.bind({ "media_added": self._media_added_cb, "media_removed": self._media_removed_cb, "render_ready": self._render_ready_cb, # explicitly set to NULL is important here # to disable external texture loading "load_texture": None, "render_overlay": None, }) od.pdraw_video_renderer_new( self._pdraw.pdraw, self._media_id, self._render_zone, self._renderer_params, self._renderer_cbs, None, ctypes.byref(self._pdraw_renderer), )
def _destroy_pdraw(self): ret = True if self.pdraw: self.logger.info("destroying pdraw...") res = od.pdraw_destroy(self.pdraw) if res != 0: self.logger.error("cannot destroy pdraw {}".format(res)) ret = False else: self.logger.info("pdraw destroyed") if self.yuv_packed_buffer_pool: self.logger.info("destroying yuv buffer pool...") res = od.vbuf_pool_destroy(self.yuv_packed_buffer_pool) if res != 0: ret = False self.logger.error( "cannot destroy yuv packed buffer pool: {}".format(res)) else: self.logger.info("yuv buffer pool destroyed") self.yuv_packed_buffer_pool = od.POINTER_T(od.struct_vbuf_pool)() self.pdraw = od.POINTER_T(od.struct_pdraw)() return ret
def StreamFactory(): return { 'id': None, 'id_userdata': ctypes.c_void_p(), 'frame_type': od.VDEF_FRAME_TYPE_UNKNOWN, 'h264_header': None, 'track_id': None, 'metadata_track_id': None, 'video_sink': None, 'video_sink_cbs': None, 'video_sink_lock': threading.RLock(), 'video_queue': None, 'video_queue_event': od.POINTER_T(od.struct_pomp_evt)(), }
def from_arsdk_peer(cls, arsdk_peer): peer_info = od.POINTER_T(od.struct_arsdk_peer_info)() res = od.arsdk_peer_get_info(arsdk_peer, ctypes.byref(peer_info)) if res < 0 or not peer_info: raise RuntimeError(f"Failed to get peer info: {res}") peer_info = peer_info.contents return cls( ctrl_name=od.string_cast(peer_info.ctrl_name), ctrl_type=od.string_cast(peer_info.ctrl_type), ctrl_addr=od.string_cast(peer_info.ctrl_addr), device_id=od.string_cast(peer_info.device_id), proto_v=int(peer_info.proto_v), json=od.string_cast(peer_info.json), arsdk_peer=arsdk_peer, )
def __init__(self, name=None, dcport=44444, drone_type=0, proto_v_min=1, proto_v_max=3): self._logger_scope = "device" self._dcport = dcport self._peer = None self._publisher_net = od.POINTER_T(od.struct_arsdk_publisher_net)() self._listening = False super().__init__(name=name, drone_type=drone_type, proto_v_min=1, proto_v_max=3)
def _pdraw_new(self): res = od.pdraw_new( self.pomp_loop, self.cbs, ctypes.cast(ctypes.pointer(ctypes.py_object(self)), ctypes.c_void_p), ctypes.byref(self.pdraw) ) if res != 0: msg = "Error while creating pdraw interface: {}".format(res) self.logging.logE(msg) self.pdraw = od.POINTER_T(od.struct_pdraw)() return False else: self.logging.logI("Pdraw interface has been created") return True
def _unrecoverable_error(self, pdraw, demuxer, userdata): self.logger.error("_unrecoverable_error() -> pdraw teardown...") # remove every video sinks for id_ in self.streams: self._video_sink_flush_impl(id_) self._media_removed_impl(id_) # demuxer.close -> demuxer.destroy if self.pdraw and self.pdraw_demuxer: od.pdraw_demuxer_close(self.pdraw, self.pdraw_demuxer) # the demuxer will be destroyed in close_resp self.pdraw_demuxer = od.POINTER_T(od.struct_pdraw_demuxer)() self.logger.error("_unrecoverable_error() -> pdraw teardown done") # we should be good to go again with a Pdraw.play() self._state = PdrawState.Created
def _open(self, filepath): mux = od.POINTER_T(od.struct_mp4_mux)() now = ctypes.c_uint64(int(time.time())) res = od.mp4_mux_open( od.char_pointer_cast(filepath), PDRAW_TIMESCALE, now, now, ctypes.byref(mux) ) if res != 0: raise RuntimeError(f"mp4_mux_open returned {res}") res = od.mp4_mux_add_file_metadata( mux, od.char_pointer_cast("com.parrot.olympe.version"), od.char_pointer_cast(__version__), ) if res != 0: self.logger.error(f"mp4_mux_add_file_metadata returned {res}") return mux
def _create_discovery(self): """ Start net discovery in order to detect devices """ discovery = od.POINTER_T(od.struct_arsdk_discovery_net)() res = od.arsdk_discovery_net_new( self._backend._arsdk_ctrl, self._backend._backend_net, ctypes.pointer(self.discovery_cfg), od.char_pointer_cast(self.ip_addr), ctypes.byref(discovery), ) if res != 0: self._logging.error("arsdk_discovery_net_new: {}".format(res)) return None return discovery
def _close_resp(self, pdraw, status, userdata): self._close_output_files() if status != 0: self.logging.error("_close_resp called {}".format(status)) self._close_resp_future.set_result(False) self.state = PdrawState.Error else: self.logging.info("_close_resp called {}".format(status)) self.state = PdrawState.Closed self._close_resp_future.set_result(True) if self.pdraw: res = od.pdraw_destroy(self.pdraw) if res != 0: self.logging.error("Cannot destroy pdraw object") self.pdraw = od.POINTER_T(od.struct_pdraw)() self._close_resp_future.set_result(True)
def _create_command_interface(self, peer): """ Create a command interface to send command to the device """ cmd_itf = od.POINTER_T(od.struct_arsdk_cmd_itf)() res = od.arsdk_peer_create_cmd_itf(peer, self._cmd_itf_cbs, ctypes.pointer(cmd_itf)) if res != 0: self.logger.error(f"Error while creating command interface: {res}") cmd_itf = None else: self.logger.info("Command interface has been created") return cmd_itf
def _close_resp(self, pdraw, demuxer, status, userdata): self._close_output_files() if status != 0: self.logger.error(f"_close_resp called {status}") self._close_resp_future.set_result(False) self.state = PdrawState.Error else: self.logger.debug(f"_close_resp called {status}") self.state = PdrawState.Closed self._close_resp_future.set_result(True) if not self._open_resp_future.done(): self._open_resp_future.set_result(False) if demuxer == self.pdraw_demuxer: self.pdraw_demuxer = od.POINTER_T(od.struct_pdraw_demuxer)() res = od.pdraw_demuxer_destroy(pdraw, demuxer) if res != 0: self.logger.error(f"pdraw_demuxer_destroy: {res}") else: self.logger.debug(f"pdraw_demuxer_destroy: {res}")