In [3]: x = np.array([[1, 2], [2, 3]]
In [4]: y = np.array([[3], [4]])
In [9]: z = np.hstack([x, y])
In [10]: z
Out[10]:
array([[1, 2, 3],
[2, 3, 4]])
In [11]: z[:,:1]
array([[1],
[2]])
После еще нескольких экспериментов с GStreamer и библиотекой RTSP-сервера ситуация с обработкой ошибок усложняется.
Канонический способ увидеть ошибки в конвейере GStreamer - добавить наблюдателя к шине конвейера и прослушивать сообщения об ошибках.
def watcher(bus, message, *user_data);
if message.type == Gst.MessageType.ERROR:
error, message = message.parse_error()
# TODO: Do something with the error
my_pipeline.get_bus().add_watch(
GLib.PRIORITY_DEFAULT,
watcher,
None)
Однако вы не можете сделать это с конвейерами, которые вы поставляете в GstRtspServer. Это связано с тем, что GstRtspServer ожидает установки собственного наблюдателя на шину конвейера, и только один наблюдатель может быть подключен к шине одновременно. Это особенно прискорбно, потому что это мешает нам слушать любые события в конвейере, а не только ошибки.
Мы можем разделить конвейер на две части: одна отвечает за подверженный ошибкам процесс соединения с исходным и декодирующим кадрами, а другая отвечает за кодирование получаемых кадров. и загрузка их для GstRtspServer. Затем мы можем использовать плагин intervideo для связи между ними.
Например, допустим, вы пытаетесь выполнить потоковую передачу из файла в формате VP8. Наш первый конвейер, отвечающий за чтение и декодирование кадров, будет выглядеть следующим образом:
filesrc location="{filepath}" ! decodebin ! intervideosink channel="file-channel"
... а наш второй конвейер, который отвечает за кодирование и загрузку кадра, будет выглядеть так:
[ 112]Ключевым моментом здесь является то, что GstRtspServer должен управлять только вторым конвейером, поскольку именно этот конвейер предоставляет полезные данные. Первый управляется нами, и мы можем прикрепить к нему нашего собственного наблюдателя, который разумно реагирует на ошибки и делает все остальное, что нам нужно. Конечно, это не идеальное решение, потому что мы не можем реагировать на ошибки, связанные с кодированием и полезной нагрузкой, но мы получили возможность получать ошибки, связанные с чтением файла и его декодированием. Теперь мы также можем выполнять другие задачи, связанные с сообщениями, например, перехватывать сообщение конца потока для зацикливания видеофайла.