void vf_split(struct video_frame *out, struct video_frame *src, unsigned int x_count, unsigned int y_count, int preallocate) { unsigned int tile_idx, line_idx; struct tile *cur_tiles; unsigned int tile_line = 0; out->color_spec = src->color_spec; out->fps = src->fps; //out->aux = src->aux | AUX_TILED; assert(vf_get_tile(src, 0)->width % x_count == 0u && vf_get_tile(src, 0)->height % y_count == 0u); for(tile_idx = 0u; tile_idx < x_count * y_count; ++tile_idx) { out->tiles[tile_idx].width = vf_get_tile(src, 0)->width / x_count; out->tiles[tile_idx].height = vf_get_tile(src, 0)->height / y_count; out->tiles[tile_idx].linesize = vc_get_linesize(out->tiles[tile_idx].width, src->color_spec); out->tiles[tile_idx].data_len = out->tiles[tile_idx].linesize * out->tiles[tile_idx].height; } cur_tiles = &out->tiles[0]; for(line_idx = 0u; line_idx < vf_get_tile(src, 0)->height; ++line_idx, ++tile_line) { unsigned int cur_tile_idx; unsigned int byte = 0u; if (line_idx % (vf_get_tile(src, 0)->height / y_count) == 0u) /* next tiles*/ { tile_line = 0u; if (line_idx != 0u) cur_tiles += x_count; if (preallocate) { for (cur_tile_idx = 0u; cur_tile_idx < x_count; ++cur_tile_idx) { cur_tiles[cur_tile_idx].data = malloc(cur_tiles[cur_tile_idx]. data_len); } } } for(cur_tile_idx = 0u; cur_tile_idx < x_count; ++cur_tile_idx) { memcpy((void *) &cur_tiles[cur_tile_idx].data[ tile_line * cur_tiles[cur_tile_idx].linesize], (void *) &src->tiles[0].data[line_idx * src->tiles[0].linesize + byte], cur_tiles[cur_tile_idx].width * get_bpp(src->color_spec)); byte += cur_tiles[cur_tile_idx].width * get_bpp(src->color_spec); } } }
static void display_sage_run(void *arg) { struct state_sage *s = (struct state_sage *)arg; s->magic = MAGIC_SAGE; while (!s->should_exit) { display_sage_handle_events(); sem_wait(&s->semaphore); if (s->should_exit) break; if (s->deinterlace) { vc_deinterlace((unsigned char *) s->tile->data, vc_get_linesize(s->tile->width, s->frame->color_spec), s->tile->height); } s->sage_state->swapBuffer(SAGE_NON_BLOCKING); sageMessage msg; if (s->sage_state->checkMsg(msg, false) > 0) { switch (msg.getCode()) { case APP_QUIT: sage::printLog("Ultragrid: QUIT message"); exit_uv(1); break; } } s->tile->data = (char *) s->sage_state->getBuffer(); pthread_mutex_lock(&s->buffer_writable_lock); s->buffer_writable = 1; if(s->grab_waiting) { pthread_cond_broadcast(&s->buffer_writable_cond); } pthread_mutex_unlock(&s->buffer_writable_lock); s->frames++; gettimeofday(&s->t, NULL); double seconds = tv_diff(s->t, s->t0); if (seconds >= 5) { float fps = s->frames / seconds; log_msg(LOG_LEVEL_INFO, "[SAGE] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps); s->t0 = s->t; s->frames = 0; } } }
struct video_frame * dxt_glsl_compress(struct module *mod, struct video_frame * tx, int buffer_idx) { struct state_video_compress_rtdxt *s = (struct state_video_compress_rtdxt *) mod->priv_data; int i; unsigned char *line1, *line2; assert(buffer_idx >= 0 && buffer_idx < 2); unsigned int x; gl_context_make_current(&s->gl_context); if(!s->configured) { int ret; ret = configure_with(s, tx); if(!ret) return NULL; } for (x = 0; x < tx->tile_count; ++x) { struct tile *in_tile = vf_get_tile(tx, x); struct tile *out_tile = vf_get_tile(s->out[buffer_idx], x); line1 = (unsigned char *) in_tile->data; line2 = (unsigned char *) s->decoded; for (i = 0; i < (int) in_tile->height; ++i) { s->decoder(line2, line1, s->encoder_input_linesize, 0, 8, 16); line1 += vc_get_linesize(in_tile->width, tx->color_spec); line2 += s->encoder_input_linesize; } if(s->interlaced_input) vc_deinterlace((unsigned char *) s->decoded, s->encoder_input_linesize, in_tile->height); dxt_encoder_compress(s->encoder[x], (unsigned char *) s->decoded, (unsigned char *) out_tile->data); } gl_context_make_current(NULL); return s->out[buffer_idx]; }
static int display_sage_reconfigure(void *state, struct video_desc desc) { struct state_sage *s = (struct state_sage *)state; assert(s->magic == MAGIC_SAGE); assert(desc.color_spec == RGBA || desc.color_spec == RGB || desc.color_spec == UYVY || desc.color_spec == DXT1 #ifdef SAGE_NATIVE_DXT5YCOCG || desc.color_spec == DXT5 #endif // SAGE_NATIVE_DXT5YCOCG ); s->tile->width = desc.width; s->tile->height = desc.height; s->frame->fps = desc.fps; s->frame->interlacing = desc.interlacing; s->frame->color_spec = desc.color_spec; // SAGE fix - SAGE threads apparently do not process signals correctly so we temporarily // block all signals while creating SAGE sigset_t mask, old_mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGHUP); pthread_sigmask(SIG_BLOCK, &mask, &old_mask); if(s->sage_state) { s->sage_state->shutdown(); //delete s->sage_state; // this used to cause crashes } s->sage_state = initSage(s->confName, s->fsIP, s->appID, s->nodeID, s->tile->width, s->tile->height, desc.color_spec); // calling thread should be able to process signals afterwards pthread_sigmask(SIG_UNBLOCK, &old_mask, NULL); s->tile->data = (char *) s->sage_state->getBuffer(); s->tile->data_len = vc_get_linesize(s->tile->width, desc.color_spec) * s->tile->height; return TRUE; }
void vf_split_horizontal(struct video_frame *out, struct video_frame *src, unsigned int y_count) { unsigned int i; for(i = 0u; i < y_count; ++i) { //out->aux = src->aux | AUX_TILED; out->fps = src->fps; out->color_spec = src->color_spec; out->tiles[i].width = src->tiles[0].width; out->tiles[i].height = src->tiles[0].height / y_count; out->tiles[i].linesize = vc_get_linesize(out->tiles[i].width, out->color_spec); out->tiles[i].data_len = out->tiles[i].linesize * out->tiles[i].height; out->tiles[i].data = src->tiles[0].data + i * out->tiles[i].height * out->tiles[i].linesize; } }
static struct video_frame *filter(void *, struct video_frame *in) { if (in->color_spec != UYVY) { log_msg(LOG_LEVEL_WARNING, "Only supporte colorspace for mirror is currently UYVY!\n"); return in; } struct video_frame *out = vf_alloc_desc_data(video_desc_from_frame(in)); out->dispose = vf_free; unsigned char *in_data = (unsigned char *) in->tiles[0].data; unsigned char *out_data = (unsigned char *) out->tiles[0].data; int linesize = vc_get_linesize(in->tiles[0].width, in->color_spec); for (unsigned int y = 0; y < in->tiles[0].height; ++y) { mirror_line_UYVY(out_data + y * linesize, in_data + y * linesize, linesize); } VIDEO_FRAME_DISPOSE(in); return out; }
int main(int argc, char **argv) { int stop_at = 0; char *yuv_path; if (argc == 2) { yuv_path = argv[1]; } else if (argc == 3) { yuv_path = argv[1]; stop_at = atoi(argv[2]); } else { printf("usage: %s input [max frames]\n", argv[0]); return -1; } printf("[test] initializing streams list\n"); printf("[test] init_stream_list\n"); stream_list_t *streams = init_stream_list(); printf("[test] init_stream\n"); stream_data_t *stream = init_stream(VIDEO, OUTPUT, 0, ACTIVE, "i2catrocks"); printf("[test] set_stream_video_data\n"); printf("[test] add_stream\n"); add_stream(streams, stream); printf("[test] initializing transmitter\n"); transmitter_t *transmitter = init_transmitter(streams, 20.0); start_transmitter(transmitter); rtsp_serv_t *server; server = malloc(sizeof(rtsp_serv_t)); server->port = 8554; server->streams = streams; server->transmitter = transmitter; init_encoder(stream->video); c_start_server(server); c_update_server(server); // Stuff ... AVFormatContext *pformat_ctx = avformat_alloc_context(); AVCodecContext codec_ctx; int video_stream = -1; av_register_all(); int width = 1280; int height = 534; load_video(yuv_path, pformat_ctx, &codec_ctx, &video_stream); uint8_t *b1 = (uint8_t *)av_malloc(avpicture_get_size(codec_ctx.pix_fmt, codec_ctx.width, codec_ctx.height)*sizeof(uint8_t)); int counter = 0; struct timeval a, b; video_data_frame_t *decoded_frame; while(1) { gettimeofday(&a, NULL); int ret = read_frame(pformat_ctx, video_stream, &codec_ctx, b1); if (stop_at > 0 && counter == stop_at) { break; } if (ret == 0) { counter++; decoded_frame = curr_in_frame(stream->video->decoded_frames); if (decoded_frame == NULL){ continue; } decoded_frame->buffer_len = vc_get_linesize(width, RGB)*height; memcpy(decoded_frame->buffer, b1, decoded_frame->buffer_len); put_frame(stream->video->decoded_frames); } else { break; } gettimeofday(&b, NULL); long diff = (b.tv_sec - a.tv_sec)*1000000 + b.tv_usec - a.tv_usec; if (diff < 40000) { usleep(40000 - diff); } else { usleep(0); } } debug_msg(" deallocating resources and terminating threads\n"); av_free(pformat_ctx); av_free(b1); debug_msg(" done!\n"); stop_transmitter(transmitter); destroy_stream_list(streams); return 0; }
static struct video_frame *vidcap_testcard_grab(void *arg, struct audio_frame **audio) { struct testcard_state *state; state = (struct testcard_state *)arg; std::chrono::steady_clock::time_point curr_time = std::chrono::steady_clock::now(); if (std::chrono::duration_cast<std::chrono::duration<double>>(curr_time - state->last_frame_time).count() < 1.0 / (double)state->frame->fps) { return NULL; } state->last_frame_time = curr_time; state->count++; double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(curr_time - state->t0).count(); if (seconds >= 5.0) { float fps = state->count / seconds; log_msg(LOG_LEVEL_INFO, "[testcard] %d frames in %g seconds = %g FPS\n", state->count, seconds, fps); state->t0 = curr_time; state->count = 0; } if (state->grab_audio) { #ifdef HAVE_LIBSDL_MIXER state->audio.data = state->audio_data + state->audio_start; if(state->audio_start <= state->audio_end) { int tmp = state->audio_end; state->audio.data_len = tmp - state->audio_start; state->audio_start = tmp; } else { state->audio.data_len = AUDIO_BUFFER_SIZE - state->audio_start; state->audio_start = 0; } if(state->audio.data_len > 0) *audio = &state->audio; else *audio = NULL; #endif } else { *audio = NULL; } if(!state->still_image) { vf_get_tile(state->frame, 0)->data += state->frame_linesize; } if(vf_get_tile(state->frame, 0)->data > state->data + state->size) vf_get_tile(state->frame, 0)->data = state->data; /*char line[state->frame.src_linesize * 2 + state->pan]; unsigned int i; memcpy(line, state->frame.data, state->frame.src_linesize * 2 + state->pan); for (i = 0; i < state->frame.height - 3; i++) { memcpy(state->frame.data + i * state->frame.src_linesize, state->frame.data + (i + 2) * state->frame.src_linesize + state->pan, state->frame.src_linesize); } memcpy(state->frame.data + i * state->frame.src_linesize, state->frame.data + (i + 2) * state->frame.src_linesize + state->pan, state->frame.src_linesize - state->pan); memcpy(state->frame.data + (state->frame.height - 2) * state->frame.src_linesize - state->pan, line, state->frame.src_linesize * 2 + state->pan); #ifdef USE_EPILEPSY if(!(state->count % 2)) { unsigned int *p = state->frame.data; for(i=0; i < state->frame.src_linesize*state->frame.height/4; i++) { *p = *p ^ 0x00ffffffL; p++; } } #endif */ if (state->tiled) { /* update tile data instead */ int i; int count = state->tiled->tile_count; for (i = 0; i < count; ++i) { /* shift - for semantics of vars refer to configure_tiling*/ state->tiled->tiles[i].data += vc_get_linesize( state->tiled->tiles[i].width, state->tiled->color_spec); /* if out of data, move to beginning * keep in mind that we have two "pictures" for * every tile stored sequentially */ if(state->tiled->tiles[i].data >= state->tiles_data[i] + state->tiled->tiles[i].data_len * state->tiles_cnt_vertical) { state->tiled->tiles[i].data = state->tiles_data[i]; } } return state->tiled; } return state->frame; }
static int configure_tiling(struct testcard_state *s, const char *fmt) { char *tmp, *token, *saveptr = NULL; int tile_cnt; int x; int grid_w, grid_h; if(fmt[1] != '=') return 1; tmp = strdup(&fmt[2]); token = strtok_r(tmp, "x", &saveptr); grid_w = atoi(token); token = strtok_r(NULL, "x", &saveptr); grid_h = atoi(token); free(tmp); s->tiled = vf_alloc(grid_w * grid_h); s->tiles_cnt_horizontal = grid_w; s->tiles_cnt_vertical = grid_h; s->tiled->color_spec = s->frame->color_spec; s->tiled->fps = s->frame->fps; s->tiled->interlacing = s->frame->interlacing; tile_cnt = grid_w * grid_h; assert(tile_cnt >= 1); s->tiles_data = (char **) malloc(tile_cnt * sizeof(char *)); /* split only horizontally!!!!!! */ vf_split(s->tiled, s->frame, grid_w, 1, 1 /*prealloc*/); /* for each row, make the tile data correct. * .data pointers of same row point to same block, * but different row */ for(x = 0; x < grid_w; ++x) { int y; s->tiles_data[x] = s->tiled->tiles[x].data; s->tiled->tiles[x].width = s->frame->tiles[0].width/ grid_w; s->tiled->tiles[x].height = s->frame->tiles[0].height / grid_h; s->tiled->tiles[x].data_len = s->frame->tiles[0].data_len / (grid_w * grid_h); s->tiled->tiles[x].data = s->tiles_data[x] = (char *) realloc(s->tiled->tiles[x].data, s->tiled->tiles[x].data_len * grid_h * 2); memcpy(s->tiled->tiles[x].data + s->tiled->tiles[x].data_len * grid_h, s->tiled->tiles[x].data, s->tiled->tiles[x].data_len * grid_h); /* recopy tiles vertically */ for(y = 1; y < grid_h; ++y) { memcpy(&s->tiled->tiles[y * grid_w + x], &s->tiled->tiles[x], sizeof(struct tile)); /* make the pointers correct */ s->tiles_data[y * grid_w + x] = s->tiles_data[x] + y * s->tiled->tiles[x].height * vc_get_linesize(s->tiled->tiles[x].width, s->tiled->color_spec); s->tiled->tiles[y * grid_w + x].data = s->tiles_data[x] + y * s->tiled->tiles[x].height * vc_get_linesize(s->tiled->tiles[x].width, s->tiled->color_spec); } } return 0; }
struct video_frame * jpeg_compress(struct module *mod, struct video_frame * tx, int buffer_idx) { struct state_video_compress_jpeg *s = (struct state_video_compress_jpeg *) mod->priv_data; int i; unsigned char *line1, *line2; struct video_frame *out; unsigned int x; cudaSetDevice(cuda_devices[0]); if(!s->encoder) { int ret; ret = configure_with(s, tx); if(!ret) { return NULL; } } struct video_desc desc; desc = video_desc_from_frame(tx); // if format changed, reconfigure if(!video_desc_eq_excl_param(s->saved_desc, desc, PARAM_INTERLACING)) { cleanup_state(s); int ret; ret = configure_with(s, tx); if(!ret) { return NULL; } } out = s->out[buffer_idx]; for (x = 0; x < tx->tile_count; ++x) { struct tile *in_tile = vf_get_tile(tx, x); struct tile *out_tile = vf_get_tile(out, x); line1 = (unsigned char *) in_tile->data; line2 = (unsigned char *) s->decoded; for (i = 0; i < (int) in_tile->height; ++i) { s->decoder(line2, line1, s->encoder_input_linesize, 0, 8, 16); line1 += vc_get_linesize(in_tile->width, tx->color_spec); line2 += s->encoder_input_linesize; } line1 = (unsigned char *) out_tile->data + (in_tile->height - 1) * s->encoder_input_linesize; for( ; i < (int) out->tiles[0].height; ++i) { memcpy(line2, line1, s->encoder_input_linesize); line2 += s->encoder_input_linesize; } /*if(s->interlaced_input) vc_deinterlace((unsigned char *) s->decoded, s->encoder_input_linesize, s->out->tiles[0].height);*/ uint8_t *compressed; int size; int ret; struct gpujpeg_encoder_input encoder_input; gpujpeg_encoder_input_set_image(&encoder_input, (uint8_t *) s->decoded); ret = gpujpeg_encoder_encode(s->encoder, &encoder_input, &compressed, &size); if(ret != 0) return NULL; out_tile->data_len = size; memcpy(out_tile->data, compressed, size); } return out; }
struct video_frame * fastdxt_compress(void *args, struct video_frame *tx, int buffer_idx) { /* This thread will be called from main.c and handle the compress_threads */ struct video_compress *compress = (struct video_compress *)args; unsigned int x; unsigned char *line1, *line2; struct video_frame *out = compress->out[buffer_idx]; struct tile *out_tile = &out->tiles[0]; assert(tx->tile_count == 1); assert(vf_get_tile(tx, 0)->width % 4 == 0); pthread_mutex_lock(&(compress->lock)); if(vf_get_tile(tx, 0)->width != out_tile->width || vf_get_tile(tx, 0)->height != out_tile->height || tx->interlacing != compress->interlacing_source || tx->color_spec != compress->tx_color_spec) { int ret; ret = reconfigure_compress(compress, vf_get_tile(tx, 0)->width, vf_get_tile(tx, 0)->height, tx->color_spec, tx->interlacing, tx->fps); if(!ret) return NULL; } line1 = (unsigned char *) tx->tiles[0].data; line2 = compress->output_data; for (x = 0; x < out_tile->height; ++x) { int src_linesize = vc_get_linesize(out_tile->width, compress->tx_color_spec); compress->decoder(line2, line1, out_tile->linesize, 0, 8, 16); line1 += src_linesize; line2 += out_tile->linesize; } if(tx->interlacing != INTERLACED_MERGED && tx->interlacing != PROGRESSIVE) { fprintf(stderr, "Unsupported interlacing format.\n"); exit_uv(1); } if(tx->interlacing == INTERLACED_MERGED) { vc_deinterlace(compress->output_data, out_tile->linesize, out_tile->height); } compress->buffer_idx = buffer_idx; for (x = 0; x < (unsigned int) compress->num_threads; x++) { platform_sem_post(&compress->thread_compress[x]); } for (x = 0; x < (unsigned int) compress->num_threads; x++) { platform_sem_wait(&compress->thread_done[x]); } out_tile->data_len = out_tile->width * compress->dxt_height / 2; pthread_mutex_unlock(&(compress->lock)); return out; }