60#include <condition_variable>
61#include <libgpustitch/stitcher.hpp>
62#include <libgpustitch/config_utils.hpp>
71const static char *
log_str =
"[gpustitch] ";
77 return (deg / 180) * 3.14159265;
83 color_printf(
"Stitches a 360 degree panorama from multiple cameras\n");
85 color_printf(
TERM_BOLD TERM_FG_RED "\t-t gpustitch" TERM_FG_RESET ":rig_spec=<filepath>[:width=<w>][:blend_algo=<multiband|feather>][:multiband_levels=<n>][:feather_width=<w>][:tiled] -t <dev1_config> -t <dev2_config> ....\n");
103 struct timeval t,
t0;
122 struct CUstream_st *stream);
154 struct CUstream_st *stream);
163 *available_cards =
nullptr;
170 std::cerr <<
log_str <<
"Only frames with tile_count == 1 are supported" << std::endl;
174 unsigned int expected_w = gs->
width;
175 unsigned int expected_h = gs->
height;
180 std::cerr <<
log_str <<
"Wrong resolution for input " << i <<
"!"
181 <<
" Expected " << expected_w <<
"x" << expected_h
187 printf(
"New codec detected! RECONF\n");
214 size_t x_offset,
size_t y_offset,
size_t w,
size_t h,
219 unsigned int width = in_frame->
tiles[0].
width;
223 size_t offset_bytes = y_offset * in_line_size
231 (
unsigned char *)(in_frame->
tiles[0].
data) + offset_bytes,
236 std::cerr <<
"Error copying input image bitmap to CUDA buffer" << std::endl;
246 (
unsigned char*)(in_frame->
tiles[0].
data) + offset_bytes,
251 std::cerr <<
"Error copying RGBA image bitmap to CUDA buffer" << std::endl;
262 gs->
s->
stitcher.get_input_stream(i, &stream);
265 std::cerr << std::endl <<
"Failed to get input stream." << std::endl;
279 gpustitch::Src_mem_kind::Device);
285 const int order[] = {3, 1, 2, 0};
287 for(
int i = 0; i < 4; i++){
290 gs->
s->
stitcher.get_input_stream(i, &stream);
292 unsigned tile_height = gs->
height / 2;
293 unsigned tile_width = gs->
width / 2;
296 unsigned x_offset = (order[i] % 2) * tile_width;
297 unsigned y_offset = (order[i] / 2) * tile_height;
301 x_offset, y_offset, tile_width, tile_height,
307 unsigned char *src =
static_cast<unsigned char *
>(gs->
tmp_rgba_frame);
308 src += (order[i] % 2) * tile_line_len;
309 src += (order[i] / 2) * src_pitch * tile_height;
311 gs->
s->
stitcher.submit_input_image_async(i, src,
314 gpustitch::Src_mem_kind::Device);
323 std::unique_lock<std::mutex> stitch_lk(gs->
s->
stitched_mut, std::defer_lock);
324 std::unique_lock<std::mutex> grab_lk(gs->
grabbed_mut, std::defer_lock);
341 fprintf(stderr,
"[gpustitch] Unable to initialize device %d (%s:%s).\n",
401 assert(
false &&
"Unsupported output pixel format!");
405 cudaGetDeviceCount(&num_gpus);
407 int selected_gpu = -1;
409 for (
int gpu = 0; gpu < num_gpus; ++gpu)
412 cudaGetDeviceProperties(&prop, gpu);
415 if (prop.major > 5 || (prop.major == 5 && prop.minor >= 2))
421 if (selected_gpu == -1) {
425 cudaSetDevice(selected_gpu);
437 }
catch(
char const *exc){
451 s->
stitch_params.blend_algorithm = gpustitch::Blend_algorithm::Multiband;
459 char *tmp = strdup(
fmt);
460 char *init_fmt = tmp;
461 char *save_ptr = NULL;
463#define FMT_CMP(param) (strncmp(item, (param), strlen((param))) == 0)
464 while((
item = strtok_r(init_fmt,
":", &save_ptr))) {
468 }
else if(
FMT_CMP(
"blend_algo=")){
471 gpustitch::Blend_algorithm
algo;
473 {
"multiband", gpustitch::Blend_algorithm::Multiband},
474 {
"feather", gpustitch::Blend_algorithm::Feather},
477 const char *req = strchr(
item,
'=') + 1;
479 bool selected =
false;
480 for(
const auto& i : blend_algos){
481 if(strcmp(req, i.name) == 0){
491 }
else if(
FMT_CMP(
"feather_width=")){
493 }
else if(
FMT_CMP(
"multiband_levels=")){
495 }
else if(
FMT_CMP(
"rig_spec=")){
498 s->
fps = strtod(strchr(
item,
'=') + 1,
nullptr);
519 if(
worker.thread.joinable())
527 printf(
"vidcap_gpustitch_init\n");
535 printf(
"Unable to allocate gpustitch capture state\n");
540 gettimeofday(&s->
t0, NULL);
634 std::cerr <<
log_str <<
"Failed to allocate result frame" << std::endl;
644 std::cerr <<
log_str <<
"Failed to allocate tmp conv frame" << std::endl;
654 gpustitch::Image_cuda *output_image;
656 output_image = s->
stitcher.get_output_image();
658 std::cerr <<
log_str <<
"Failed to get output buffer" << std::endl;
662 size_t w = output_image->get_width();
663 size_t h = output_image->get_height();
671 void *src = output_image->data();
672 size_t src_pitch = output_image->get_pitch();
673 size_t row_bytes = output_image->get_row_bytes();
676 (
unsigned char *) src, src_pitch,
681 row_bytes = src_pitch;
690 cudaMemcpyDeviceToHost, out_stream) !=
cudaSuccess)
692 std::cerr <<
log_str <<
"Error copying output panorama from CUDA buffer" << std::endl;
701 gettimeofday(&s->t, NULL);
713 double fps = std::numeric_limits<double>::max();
715 std::unique_lock<std::mutex> lk(
worker.grabbed_mut);
728 std::cout << std::endl <<
"Failed to stitch." << std::endl;
732 cudaStream_t out_stream;
733 s->
stitcher.get_output_stream(&out_stream);
736 std::cerr <<
log_str <<
"Failed to get output stream" << std::endl;
740 std::unique_lock<std::mutex> stitch_lk(s->
stitched_mut);
750 if (cudaStreamSynchronize(out_stream) !=
cudaSuccess)
752 std::cerr <<
"Error synchronizing with the output CUDA stream" << std::endl;
struct video_frame * frame
struct audio_frame ** audio
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
int vc_get_linesize(unsigned int width, codec_t codec)
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
codec_t get_codec_from_name(const char *name)
This file contains definition of some common audio types.
int color_printf(const char *format,...)
void cuda_RGBA_to_UYVY(unsigned char *dst, size_t dstPitch, unsigned char *src, size_t srcPitch, size_t width, size_t height, CUstream_st *stream)
void cuda_UYVY_to_RGBA(unsigned char *dst, size_t dstPitch, unsigned char *src, size_t srcPitch, size_t width, size_t height, CUstream_st *stream)
void cuda_RGBA_to_RGB(unsigned char *dst, size_t dstPitch, unsigned char *src, size_t srcPitch, size_t width, size_t height, CUstream_st *stream)
void cuda_RGB_to_RGBA(unsigned char *dst, size_t dstPitch, unsigned char *src, size_t srcPitch, size_t width, size_t height, CUstream_st *stream)
#define cudaMemcpyHostToDevice
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_INFO
normal reporting
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_WARNING
less severe errors
static void vidcap_gpustitch_done(void *state)
static int vidcap_gpustitch_init(struct vidcap_params *params, void **state)
static void report_stats(vidcap_gpustitch_state *s)
static bool check_in_format(grab_worker_state *gs, video_frame *in, int i)
static void stop_grab_workers(vidcap_gpustitch_state *s)
static void vidcap_gpustitch_probe(device_info **available_cards, int *count, void(**deleter)(void *))
static const struct video_capture_info vidcap_gpustitch_info
static bool allocate_result_frame(vidcap_gpustitch_state *s, unsigned width, unsigned height)
static void upload_tiles(grab_worker_state *gs, video_frame *frame)
static double wait_for_frames(struct vidcap_gpustitch_state *s)
static bool upload_to_cuda_buf(grab_worker_state *gs, video_frame *in_frame, size_t x_offset, size_t y_offset, size_t w, size_t h, unsigned char *dst, unsigned dst_pitch, cudaStream_t stream)
static void result_data_delete(struct video_frame *buf)
static void parse_fmt(vidcap_gpustitch_state *s, const char *const fmt)
static bool upload_frame(grab_worker_state *gs, video_frame *in_frame, int i)
static struct video_frame * vidcap_gpustitch_grab(void *state, struct audio_frame **audio)
static const char * log_str
static bool init_stitcher(struct vidcap_gpustitch_state *s)
static bool download_stitched(vidcap_gpustitch_state *s, cudaStream_t out_stream)
static struct video_frame * stitch(struct vidcap_gpustitch_state *s)
static void show_help(void)
static void grab_worker(grab_worker_state *gs, vidcap_params *param, int id)
static double toRadian(double deg)
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
struct video_frame * vidcap_grab(struct vidcap *state, struct audio_frame **audio)
Grabs video frame. This function may block for a short period if waiting for incoming frame....
#define VIDCAP_NO_GENERIC_FPS_INDICATOR
int initialize_video_capture(struct module *parent, struct vidcap_params *param, struct vidcap **state)
Initializes video capture.
void vidcap_done(struct vidcap *state)
Destroys vidap state.
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
#define VIDCAP_INIT_AUDIO_NOT_SUPPORTED
card does not support audio
static struct @19 params[100]
@ LIBRARY_CLASS_VIDEO_CAPTURE
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
static void * worker(void *args)
#define PROFILE_DETAIL(name)
struct used to comunicate with audio capture/playback device
cudaStream_t tmp_in_frame_stream
vidcap_gpustitch_state * s
unsigned tmp_rgba_frame_pitch
void(* conv_func)(unsigned char *dst, size_t dstPitch, unsigned char *src, size_t srcPitch, size_t width, size_t height, struct CUstream_st *stream)
std::condition_variable grabbed_cv
unsigned char * tmp_in_frame
unsigned char * tmp_rgba_frame
char * data
Raw tile data. Pointer must be at least 4B aligned.
unsigned int data_len
length of the data
std::vector< gpustitch::Cam_params > cam_properties
unsigned char * conv_tmp_frame
std::vector< grab_worker_state > capture_workers
gpustitch::Stitcher_params stitch_params
std::condition_variable stitched_cv
struct video_frame * frame
void(* conv_func)(unsigned char *dst, size_t dstPitch, unsigned char *src, size_t srcPitch, size_t width, size_t height, struct CUstream_st *stream)
struct video_frame ** captured_frames
gpustitch::Stitcher stitcher
This struct represents video capture state.
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
void(* data_deleter)(struct video_frame *)
void(* recycle)(struct video_frame *)
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
struct video_frame_callbacks callbacks
double tv_diff(struct timeval curr_time, struct timeval prev_time)
@ RGB
RGB 8-bit (packed into 24-bit word)
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
@ VIDEO_CODEC_NONE
dummy color spec
@ RGBA
RGBA 8-bit, big-endian.
This is an umbrella header for video functions.
struct vidcap_params * vidcap_params_get_next(const struct vidcap_params *curr)
const char * vidcap_params_get_driver(const struct vidcap_params *params)
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY
int get_pf_block_bytes(codec_t codec)
returns codec_info_t::block_size_bytes
#define VIDEO_FRAME_DISPOSE(frame)