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]; }
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 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 vidcap_testcard_init(const struct vidcap_params *params, void **state) { struct testcard_state *s; char *filename; const char *strip_fmt = NULL; FILE *in = NULL; unsigned int i, j; unsigned int rect_size = COL_NUM; codec_t codec = RGBA; int aligned_x; char *save_ptr = NULL; if (vidcap_params_get_fmt(params) == NULL || strcmp(vidcap_params_get_fmt(params), "help") == 0) { printf("testcard options:\n"); printf("\t-t testcard:<width>:<height>:<fps>:<codec>[:filename=<filename>][:p][:s=<X>x<Y>][:i|:sf][:still][:pattern=bars|blank|noise]\n"); printf("\t<filename> - use file named filename instead of default bars\n"); printf("\tp - pan with frame\n"); printf("\ts - split the frames into XxY separate tiles\n"); printf("\ti|sf - send as interlaced or segmented frame (if none of those is set, progressive is assumed)\n"); printf("\tstill - send still image\n"); printf("\tpattern - pattern to use\n"); show_codec_help("testcard", codecs_8b, codecs_10b); return VIDCAP_INIT_NOERR; } s = new testcard_state(); if (!s) return VIDCAP_INIT_FAIL; s->frame = vf_alloc(1); char *fmt = strdup(vidcap_params_get_fmt(params)); char *tmp; int h_align = 0; double bpp = 0; if (strlen(fmt) == 0) { free(fmt); fmt = strdup(DEFAULT_FORMAT); } tmp = strtok_r(fmt, ":", &save_ptr); if (!tmp) { fprintf(stderr, "Wrong format for testcard '%s'\n", fmt); goto error; } vf_get_tile(s->frame, 0)->width = atoi(tmp); tmp = strtok_r(NULL, ":", &save_ptr); if (!tmp) { fprintf(stderr, "Wrong format for testcard '%s'\n", fmt); goto error; } vf_get_tile(s->frame, 0)->height = atoi(tmp); tmp = strtok_r(NULL, ":", &save_ptr); if (!tmp) { fprintf(stderr, "Wrong format for testcard '%s'\n", fmt); goto error; } s->frame->fps = atof(tmp); tmp = strtok_r(NULL, ":", &save_ptr); if (!tmp) { fprintf(stderr, "Wrong format for testcard '%s'\n", fmt); goto error; } codec = get_codec_from_name(tmp); if (codec == VIDEO_CODEC_NONE) { fprintf(stderr, "Unknown codec '%s'\n", tmp); goto error; } { const codec_t *sets[] = {codecs_8b, codecs_10b}; bool supported = false; for (int i = 0; i < 2; ++i) { const codec_t *it = sets[i]; while (*it != VIDEO_CODEC_NONE) { if (codec == *it++) { supported = true; } } } if (!supported) { log_msg(LOG_LEVEL_ERROR, "Unsupported codec '%s'\n", tmp); goto error; } } h_align = get_halign(codec); bpp = get_bpp(codec); s->frame->color_spec = codec; s->still_image = FALSE; if(bpp == 0) { fprintf(stderr, "Unsupported codec '%s'\n", tmp); goto error; } aligned_x = vf_get_tile(s->frame, 0)->width; if (h_align) { aligned_x = (aligned_x + h_align - 1) / h_align * h_align; } rect_size = (vf_get_tile(s->frame, 0)->width + rect_size - 1) / rect_size; s->frame_linesize = aligned_x * bpp; s->frame->interlacing = PROGRESSIVE; s->size = aligned_x * vf_get_tile(s->frame, 0)->height * bpp; filename = NULL; tmp = strtok_r(NULL, ":", &save_ptr); while (tmp) { if (strcmp(tmp, "p") == 0) { s->pan = 48; } else if (strncmp(tmp, "filename=", strlen("filename=")) == 0) { filename = tmp + strlen("filename="); in = fopen(filename, "r"); if (!in) { perror("fopen"); goto error; } fseek(in, 0L, SEEK_END); long filesize = ftell(in); assert(filesize >= 0); fseek(in, 0L, SEEK_SET); s->data = (char *) malloc(s->size * bpp * 2); if (s->size != filesize) { fprintf(stderr, "Error wrong file size for selected " "resolution and codec. File size %ld, " "computed size %d\n", filesize, s->size); goto error; } if (!in || fread(s->data, filesize, 1, in) == 0) { fprintf(stderr, "Cannot read file %s\n", filename); goto error; } fclose(in); in = NULL; memcpy(s->data + s->size, s->data, s->size); vf_get_tile(s->frame, 0)->data = s->data; } else if (strncmp(tmp, "s=", 2) == 0) { strip_fmt = tmp; } else if (strcmp(tmp, "i") == 0) { s->frame->interlacing = INTERLACED_MERGED; } else if (strcmp(tmp, "sf") == 0) { s->frame->interlacing = SEGMENTED_FRAME; } else if (strcmp(tmp, "still") == 0) { s->still_image = TRUE; } else if (strncmp(tmp, "pattern=", strlen("pattern=")) == 0) { const char *pattern = tmp + strlen("pattern="); if (strcmp(pattern, "bars") == 0) { s->pattern = image_pattern::BARS; } else if (strcmp(pattern, "blank") == 0) { s->pattern = image_pattern::BLANK; } else if (strcmp(pattern, "noise") == 0) { s->pattern = image_pattern::NOISE; } else { fprintf(stderr, "[testcard] Unknown pattern!\n");; goto error; } } else { fprintf(stderr, "[testcard] Unknown option: %s\n", tmp); goto error; } tmp = strtok_r(NULL, ":", &save_ptr); } if (!filename) { struct testcard_rect r; int col_num = 0; s->pixmap.w = aligned_x; s->pixmap.h = vf_get_tile(s->frame, 0)->height * 2; int pixmap_len = s->pixmap.w * s->pixmap.h * 4; // maximal size (RGBA/r10k - has 4 bpp) s->pixmap.data = malloc(pixmap_len); if (s->pattern == image_pattern::BLANK) { memset(s->pixmap.data, 0, pixmap_len); } else if (s->pattern == image_pattern::NOISE) { uint8_t *sample = (uint8_t *) s->pixmap.data; for (int i = 0; i < pixmap_len; ++i) { *sample++ = rand() % 0xff; } } else { assert (s->pattern == image_pattern::BARS); for (j = 0; j < vf_get_tile(s->frame, 0)->height; j += rect_size) { int grey = 0xff010101; if (j == rect_size * 2) { r.w = vf_get_tile(s->frame, 0)->width; r.h = rect_size / 4; r.x = 0; r.y = j; testcard_fillRect(&s->pixmap, &r, 0xffffffff); r.h = rect_size - (rect_size * 3 / 4); r.y = j + rect_size * 3 / 4; testcard_fillRect(&s->pixmap, &r, 0xff000000); } for (i = 0; i < vf_get_tile(s->frame, 0)->width; i += rect_size) { r.w = rect_size; r.h = rect_size; r.x = i; r.y = j; printf("Fill rect at %d,%d\n", r.x, r.y); if (j != rect_size * 2) { testcard_fillRect(&s->pixmap, &r, rect_colors[col_num]); col_num = (col_num + 1) % COL_NUM; } else { r.h = rect_size / 2; r.y += rect_size / 4; testcard_fillRect(&s->pixmap, &r, grey); grey += 0x00010101 * (255 / COL_NUM); } } } } s->data = (char *) s->pixmap.data; if (codec == UYVY || codec == v210) { rgb2yuv422((unsigned char *) s->data, aligned_x, vf_get_tile(s->frame, 0)->height); } if (codec == v210) { s->data = (char *)tov210((unsigned char *) s->data, aligned_x, aligned_x, vf_get_tile(s->frame, 0)->height, bpp); free(s->pixmap.data); } if (codec == R10k) { toR10k((unsigned char *) s->data, vf_get_tile(s->frame, 0)->width, vf_get_tile(s->frame, 0)->height); } if(codec == RGB) { s->data = (char *)toRGB((unsigned char *) s->data, vf_get_tile(s->frame, 0)->width, vf_get_tile(s->frame, 0)->height); free(s->pixmap.data); } tmp = filename; vf_get_tile(s->frame, 0)->data = (char *) malloc(2 * s->size); memcpy(vf_get_tile(s->frame, 0)->data, s->data, s->size); memcpy(vf_get_tile(s->frame, 0)->data + s->size, vf_get_tile(s->frame, 0)->data, s->size); free(s->data); s->data = vf_get_tile(s->frame, 0)->data; } s->count = 0; s->last_frame_time = std::chrono::steady_clock::now(); printf("Testcard capture set to %dx%d, bpp %f\n", vf_get_tile(s->frame, 0)->width, vf_get_tile(s->frame, 0)->height, bpp); vf_get_tile(s->frame, 0)->data_len = s->size; if(strip_fmt != NULL) { if(configure_tiling(s, strip_fmt) != 0) { goto error; } } if(vidcap_params_get_flags(params) & VIDCAP_FLAG_AUDIO_EMBEDDED) { s->grab_audio = TRUE; if(configure_audio(s) != 0) { s->grab_audio = FALSE; fprintf(stderr, "[testcard] Disabling audio output. " "SDL-mixer missing, running on Mac or other problem.\n"); } } else { s->grab_audio = FALSE; } free(fmt); *state = s; return VIDCAP_INIT_OK; error: free(fmt); free(s->data); vf_free(s->frame); if (in) fclose(in); delete s; return VIDCAP_INIT_FAIL; }
static int configure_with(struct state_video_compress_rtdxt *s, struct video_frame *frame) { unsigned int x; enum dxt_format format; int i; for (i = 0; i < 2; ++i) { s->out[i] = vf_alloc(frame->tile_count); } for (x = 0; x < frame->tile_count; ++x) { if (vf_get_tile(frame, x)->width != vf_get_tile(frame, 0)->width || vf_get_tile(frame, x)->width != vf_get_tile(frame, 0)->width) { fprintf(stderr,"[RTDXT] Requested to compress tiles of different size!"); //exit_uv(128); return FALSE; } } for (i = 0; i < 2; ++i) { s->out[i]->fps = frame->fps; s->out[i]->color_spec = s->color_spec; for (x = 0; x < frame->tile_count; ++x) { vf_get_tile(s->out[i], x)->width = vf_get_tile(frame, 0)->width; vf_get_tile(s->out[i], x)->height = vf_get_tile(frame, 0)->height; } } switch (frame->color_spec) { case RGB: s->decoder = (decoder_t) memcpy; format = DXT_FORMAT_RGB; break; case RGBA: s->decoder = (decoder_t) memcpy; format = DXT_FORMAT_RGBA; break; case R10k: s->decoder = (decoder_t) vc_copyliner10k; format = DXT_FORMAT_RGBA; break; case YUYV: s->decoder = (decoder_t) vc_copylineYUYV; format = DXT_FORMAT_YUV422; break; case UYVY: case Vuy2: case DVS8: s->decoder = (decoder_t) memcpy; format = DXT_FORMAT_YUV422; break; case v210: s->decoder = (decoder_t) vc_copylinev210; format = DXT_FORMAT_YUV422; break; case DVS10: s->decoder = (decoder_t) vc_copylineDVS10; format = DXT_FORMAT_YUV422; break; case DPX10: s->decoder = (decoder_t) vc_copylineDPX10toRGBA; format = DXT_FORMAT_RGBA; break; default: fprintf(stderr, "[RTDXT] Unknown codec: %d\n", frame->color_spec); //exit_uv(128); return FALSE; } /* We will deinterlace the output frame */ if(frame->interlacing == INTERLACED_MERGED) { for (i = 0; i < 2; ++i) { s->out[i]->interlacing = PROGRESSIVE; } s->interlaced_input = TRUE; fprintf(stderr, "[DXT compress] Enabling automatic deinterlacing.\n"); } else { for (i = 0; i < 2; ++i) { s->out[i]->interlacing = frame->interlacing; } s->interlaced_input = FALSE; } int data_len = 0; s->encoder = malloc(frame->tile_count * sizeof(struct dxt_encoder *)); if(s->out[0]->color_spec == DXT1) { for(int i = 0; i < (int) frame->tile_count; ++i) { s->encoder[i] = dxt_encoder_create(DXT_TYPE_DXT1, s->out[0]->tiles[0].width, s->out[0]->tiles[0].height, format, s->gl_context.legacy); } data_len = dxt_get_size(s->out[0]->tiles[0].width, s->out[0]->tiles[0].height, DXT_TYPE_DXT1); } else if(s->out[0]->color_spec == DXT5){ for(int i = 0; i < (int) frame->tile_count; ++i) { s->encoder[i] = dxt_encoder_create(DXT_TYPE_DXT5_YCOCG, s->out[0]->tiles[0].width, s->out[0]->tiles[0].height, format, s->gl_context.legacy); } data_len = dxt_get_size(s->out[0]->tiles[0].width, s->out[0]->tiles[0].height, DXT_TYPE_DXT5_YCOCG); } for(int i = 0; i < (int) frame->tile_count; ++i) { if(s->encoder[i] == NULL) { fprintf(stderr, "[RTDXT] Unable to create decoder.\n"); //exit_uv(128); return FALSE; } } s->encoder_input_linesize = s->out[0]->tiles[0].width; switch(format) { case DXT_FORMAT_RGBA: s->encoder_input_linesize *= 4; break; case DXT_FORMAT_RGB: s->encoder_input_linesize *= 3; break; case DXT_FORMAT_YUV422: s->encoder_input_linesize *= 2; break; case DXT_FORMAT_YUV: /* not used - just not compilator to complain */ abort(); break; } assert(data_len > 0); assert(s->encoder_input_linesize > 0); for (i = 0; i < 2; ++i) { for (x = 0; x < frame->tile_count; ++x) { vf_get_tile(s->out[i], x)->data_len = data_len; vf_get_tile(s->out[i], x)->data = (char *) malloc(data_len); } } s->decoded = malloc(4 * s->out[0]->tiles[0].width * s->out[0]->tiles[0].height); s->configured = TRUE; return TRUE; }
struct video_frame * vidcap_aggregate_grab(void *state, struct audio_frame **audio) { struct vidcap_aggregate_state *s = (struct vidcap_aggregate_state *) state; struct audio_frame *audio_frame; struct video_frame *frame = NULL; int i; while(!frame) { frame = vidcap_grab(s->devices[0], &audio_frame); } s->frame->color_spec = frame->color_spec; s->frame->interlacing = frame->interlacing; s->frame->fps = frame->fps; vf_get_tile(s->frame, 0)->width = vf_get_tile(frame, 0)->width; vf_get_tile(s->frame, 0)->height = vf_get_tile(frame, 0)->height; vf_get_tile(s->frame, 0)->data_len = vf_get_tile(frame, 0)->data_len; vf_get_tile(s->frame, 0)->data = vf_get_tile(frame, 0)->data; if(audio_frame) { *audio = audio_frame; } else { *audio = NULL; } for(i = 1; i < s->devices_cnt; ++i) { while(!frame) { frame = vidcap_grab(s->devices[0], &audio_frame); } if(frame->color_spec != s->frame->color_spec || frame->fps != s->frame->fps || frame->interlacing != s->frame->interlacing) { fprintf(stderr, "[aggregate] Different format detected: "); if(frame->color_spec != s->frame->color_spec) fprintf(stderr, "codec"); if(frame->interlacing != s->frame->interlacing) fprintf(stderr, "interlacing"); if(frame->fps != s->frame->fps) fprintf(stderr, "FPS"); fprintf(stderr, "\n"); return NULL; } vf_get_tile(s->frame, i)->width = vf_get_tile(frame, 0)->width; vf_get_tile(s->frame, i)->height = vf_get_tile(frame, 0)->height; vf_get_tile(s->frame, i)->data_len = vf_get_tile(frame, 0)->data_len; vf_get_tile(s->frame, i)->data = vf_get_tile(frame, 0)->data; } s->frames++; gettimeofday(&s->t, NULL); double seconds = tv_diff(s->t, s->t0); if (seconds >= 5) { float fps = s->frames / seconds; fprintf(stderr, "[aggregate cap.] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps); s->t0 = s->t; s->frames = 0; } return s->frame; }
static void *display_sage_init(struct module *parent, const char *fmt, unsigned int flags) { UNUSED(fmt); UNUSED(flags); UNUSED(parent); struct state_sage *s; s = (struct state_sage *) calloc(1, sizeof(struct state_sage)); assert(s != NULL); s->confName = NULL; if(fmt) { if(strcmp(fmt, "help") == 0) { printf("SAGE usage:\n"); printf("\tuv -t sage[:config=<config_file>|:fs=<fsIP>][:codec=<fcc>][:d]\n"); printf("\t <config_file> - SAGE app config file, default \"ultragrid.conf\"\n"); printf("\t <fsIP> - FS manager IP address\n"); printf("\t <fcc> - FourCC of codec that will be used to transmit to SAGE\n"); printf("\t Supported options are UYVY, RGBA, RGB or DXT1\n"); printf("\t d - deinterlace output\n"); return &display_init_noerr; } else { char *tmp, *parse_str; tmp = parse_str = strdup(fmt); char *save_ptr = NULL; char *item; while((item = strtok_r(parse_str, ":", &save_ptr))) { parse_str = NULL; if(strncmp(item, "config=", strlen("config=")) == 0) { s->confName = item + strlen("config="); } else if(strncmp(item, "codec=", strlen("codec=")) == 0) { uint32_t fourcc; if(strlen(item + strlen("codec=")) != sizeof(fourcc)) { fprintf(stderr, "Malformed FourCC code (wrong length).\n"); free(s); return NULL; } memcpy((void *) &fourcc, item + strlen("codec="), sizeof(fourcc)); s->requestedDisplayCodec = get_codec_from_fcc(fourcc); if(s->requestedDisplayCodec == VIDEO_CODEC_NONE) { fprintf(stderr, "Codec not found according to FourCC.\n"); free(s); return NULL; } if(s->requestedDisplayCodec != UYVY && s->requestedDisplayCodec != RGBA && s->requestedDisplayCodec != RGB && s->requestedDisplayCodec != DXT1 #ifdef SAGE_NATIVE_DXT5YCOCG && s->requestedDisplayCodec != DXT5 #endif // SAGE_NATIVE_DXT5YCOCG ) { fprintf(stderr, "Entered codec is not nativelly supported by SAGE.\n"); free(s); return NULL; } } else if(strcmp(item, "tx") == 0) { s->is_tx = true; } else if(strncmp(item, "fs=", strlen("fs=")) == 0) { s->fsIP = item + strlen("fs="); } else if(strcmp(item, "d") == 0) { s->deinterlace = true; } else { fprintf(stderr, "[SAGE] unrecognized configuration: %s\n", item); free(s); return NULL; } } free(tmp); } } if (!s->is_tx) { // read config file only if we are in dispaly mode (not sender mode) struct stat sb; if(s->confName) { if(stat(s->confName, &sb)) { perror("Unable to use SAGE config file"); free(s); return NULL; } } else if(stat("ultragrid.conf", &sb) == 0) { s->confName = "ultragrid.conf"; } if(s->confName) { printf("[SAGE] Using config file %s.\n", s->confName); } } if(s->confName == NULL && s->fsIP == NULL) { fprintf(stderr, "[SAGE] Unable to locate FS manager address. " "Set either in config file or from command line.\n"); free(s); return NULL; } s->magic = MAGIC_SAGE; gettimeofday(&s->t0, NULL); s->frames = 0; s->frame = vf_alloc(1); s->tile = vf_get_tile(s->frame, 0); /* sage init */ //FIXME sem se musi propasovat ty spravne parametry argc argv s->appID = 0; s->nodeID = 1; s->sage_state = NULL; /* thread init */ sem_init(&s->semaphore, 0, 0); s->buffer_writable = 1; s->grab_waiting = 1; pthread_mutex_init(&s->buffer_writable_lock, 0); pthread_cond_init(&s->buffer_writable_cond, NULL); /*if (pthread_create (&(s->thread_id), NULL, display_thread_sage, (void *)s) != 0) { perror("Unable to create display thread\n"); return NULL; }*/ debug_msg("Window initialized %p\n", s); return (void *)s; }
static struct video_frame * vidcap_aggregate_grab(void *state, struct audio_frame **audio) { struct vidcap_aggregate_state *s = (struct vidcap_aggregate_state *) state; struct audio_frame *audio_frame = NULL; struct video_frame *frame = NULL; for (int i = 0; i < s->devices_cnt; ++i) { VIDEO_FRAME_DISPOSE(s->captured_frames[i]); } *audio = NULL; for (int i = 0; i < s->devices_cnt; ++i) { frame = NULL; while(!frame) { frame = vidcap_grab(s->devices[i], &audio_frame); } if (i == 0) { s->frame->color_spec = frame->color_spec; s->frame->interlacing = frame->interlacing; s->frame->fps = frame->fps; } if (s->audio_source_index == -1 && audio_frame != NULL) { fprintf(stderr, "[aggregate] Locking device #%d as an audio source.\n", i); s->audio_source_index = i; } if (s->audio_source_index == i) { *audio = audio_frame; } if (frame->color_spec != s->frame->color_spec || frame->fps != s->frame->fps || frame->interlacing != s->frame->interlacing) { fprintf(stderr, "[aggregate] Different format detected: "); if(frame->color_spec != s->frame->color_spec) fprintf(stderr, "codec"); if(frame->interlacing != s->frame->interlacing) fprintf(stderr, "interlacing"); if(frame->fps != s->frame->fps) fprintf(stderr, "FPS (%.2f and %.2f)", frame->fps, s->frame->fps); fprintf(stderr, "\n"); return NULL; } vf_get_tile(s->frame, i)->width = vf_get_tile(frame, 0)->width; vf_get_tile(s->frame, i)->height = vf_get_tile(frame, 0)->height; vf_get_tile(s->frame, i)->data_len = vf_get_tile(frame, 0)->data_len; vf_get_tile(s->frame, i)->data = vf_get_tile(frame, 0)->data; s->captured_frames[i] = frame; } 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, "[aggregate cap.] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps); s->t0 = s->t; s->frames = 0; } return s->frame; }
static int configure_with(struct state_video_compress_jpeg *s, struct video_frame *frame) { unsigned int x; int frame_idx; s->saved_desc.width = frame->tiles[0].width; s->saved_desc.height = frame->tiles[0].height; s->saved_desc.color_spec = frame->color_spec; s->saved_desc.fps = frame->fps; s->saved_desc.interlacing = frame->interlacing; s->saved_desc.tile_count = frame->tile_count; for (frame_idx = 0; frame_idx < 2; frame_idx++) { s->out[frame_idx] = vf_alloc(frame->tile_count); } for (x = 0; x < frame->tile_count; ++x) { if (vf_get_tile(frame, x)->width != vf_get_tile(frame, 0)->width || vf_get_tile(frame, x)->width != vf_get_tile(frame, 0)->width) { fprintf(stderr,"[JPEG] Requested to compress tiles of different size!"); //exit_uv(129); return FALSE; } } for (frame_idx = 0; frame_idx < 2; frame_idx++) { for (x = 0; x < frame->tile_count; ++x) { vf_get_tile(s->out[frame_idx], x)->width = vf_get_tile(frame, 0)->width; vf_get_tile(s->out[frame_idx], x)->height = vf_get_tile(frame, 0)->height; } s->out[frame_idx]->interlacing = frame->interlacing; s->out[frame_idx]->fps = frame->fps; s->out[frame_idx]->color_spec = s->color_spec; s->out[frame_idx]->color_spec = JPEG; } switch (frame->color_spec) { case RGB: s->decoder = (decoder_t) memcpy; s->rgb = TRUE; break; case RGBA: s->decoder = (decoder_t) vc_copylineRGBAtoRGB; s->rgb = TRUE; break; case BGR: s->decoder = (decoder_t) vc_copylineBGRtoRGB; s->rgb = TRUE; break; /* TODO: enable (we need R10k -> RGB) * case R10k: s->decoder = (decoder_t) vc_copyliner10k; s->rgb = TRUE; break;*/ case YUYV: s->decoder = (decoder_t) vc_copylineYUYV; s->rgb = FALSE; break; case UYVY: case Vuy2: case DVS8: s->decoder = (decoder_t) memcpy; s->rgb = FALSE; break; case v210: s->decoder = (decoder_t) vc_copylinev210; s->rgb = FALSE; break; case DVS10: s->decoder = (decoder_t) vc_copylineDVS10; s->rgb = FALSE; break; case DPX10: s->decoder = (decoder_t) vc_copylineDPX10toRGB; s->rgb = TRUE; break; default: fprintf(stderr, "[JPEG] Unknown codec: %d\n", frame->color_spec); //exit_uv(128); return FALSE; } s->encoder_param.verbose = 0; s->encoder_param.segment_info = 1; if(s->rgb) { s->encoder_param.interleaved = 0; s->encoder_param.restart_interval = s->restart_interval == -1 ? 8 : s->restart_interval; /* LUMA */ s->encoder_param.sampling_factor[0].horizontal = 1; s->encoder_param.sampling_factor[0].vertical = 1; /* Cb and Cr */ s->encoder_param.sampling_factor[1].horizontal = 1; s->encoder_param.sampling_factor[1].vertical = 1; s->encoder_param.sampling_factor[2].horizontal = 1; s->encoder_param.sampling_factor[2].vertical = 1; } else { s->encoder_param.interleaved = 1; s->encoder_param.restart_interval = s->restart_interval == -1 ? 2 : s->restart_interval; /* LUMA */ s->encoder_param.sampling_factor[0].horizontal = 2; s->encoder_param.sampling_factor[0].vertical = 1; /* Cb and Cr */ s->encoder_param.sampling_factor[1].horizontal = 1; s->encoder_param.sampling_factor[1].vertical = 1; s->encoder_param.sampling_factor[2].horizontal = 1; s->encoder_param.sampling_factor[2].vertical = 1; } struct gpujpeg_image_parameters param_image; gpujpeg_image_set_default_parameters(¶m_image); param_image.width = s->out[0]->tiles[0].width; param_image.height = s->out[0]->tiles[0].height; param_image.comp_count = 3; if(s->rgb) { param_image.color_space = GPUJPEG_RGB; param_image.sampling_factor = GPUJPEG_4_4_4; } else { param_image.color_space = GPUJPEG_YCBCR_BT709; param_image.sampling_factor = GPUJPEG_4_2_2; } s->encoder = gpujpeg_encoder_create(&s->encoder_param, ¶m_image); for (frame_idx = 0; frame_idx < 2; frame_idx++) { for (x = 0; x < frame->tile_count; ++x) { vf_get_tile(s->out[frame_idx], x)->data = (char *) malloc(s->out[frame_idx]->tiles[0].width * s->out[frame_idx]->tiles[0].height * 3); } } s->encoder_input_linesize = s->out[frame_idx]->tiles[0].width * (param_image.color_space == GPUJPEG_RGB ? 3 : 2); if(!s->encoder) { fprintf(stderr, "[DXT GLSL] Failed to create encoder.\n"); //exit_uv(128); return FALSE; } s->decoded = malloc(4 * s->out[0]->tiles[0].width * s->out[0]->tiles[0].height); return TRUE; }
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; }
void *fastdxt_init(char *num_threads_str) { /* This function does the following: * 1. Allocate memory for buffers * 2. Spawn compressor threads */ int x; int i; struct video_compress *compress; if(num_threads_str && strcmp(num_threads_str, "help") == 0) { printf("FastDXT usage:\n"); printf("\t-FastDXT[:<num_threads>]\n"); printf("\t\t<num_threads> - count of compress threads (default %d)\n", NUM_THREADS_DEFAULT); return NULL; } compress = calloc(1, sizeof(struct video_compress)); /* initial values */ compress->num_threads = 0; if(num_threads_str == NULL) compress->num_threads = NUM_THREADS_DEFAULT; else compress->num_threads = atoi(num_threads_str); assert (compress->num_threads >= 1 && compress->num_threads <= MAX_THREADS); for(i = 0; i < 2; ++i) { compress->out[i] = vf_alloc(1); compress->tile[i] = vf_get_tile(compress->out[i], 0); } for(i = 0; i < 2; ++i) { compress->tile[i]->width = 0; compress->tile[i]->height = 0; } compress->thread_count = 0; if (pthread_mutex_init(&(compress->lock), NULL)) { perror("Error initializing mutex!"); return NULL; } for (x = 0; x < compress->num_threads; x++) { platform_sem_init(&compress->thread_compress[x], 0, 0); platform_sem_init(&compress->thread_done[x], 0, 0); } pthread_mutex_lock(&(compress->lock)); for (x = 0; x < compress->num_threads; x++) { if (pthread_create (&(compress->thread_ids[x]), NULL, (void *)compress_thread, (void *)compress)) { perror("Unable to create compressor thread!"); exit_uv(x); return NULL; } } pthread_mutex_unlock(&(compress->lock)); while(compress->num_threads != compress->thread_count) /* wait for all threads online */ ; fprintf(stderr, "All compression threads are online.\n"); return compress; }
int reconfigure_compress(struct video_compress *compress, int width, int height, codec_t codec, enum interlacing_t interlacing, double fps) { int x; int i; fprintf(stderr, "Compression reinitialized for %ux%u video.\n", width, height); /* Store original attributes to allow format change detection */ for(i = 0; i < 2; ++i) { compress->tile[i]->width = width; compress->tile[i]->height = height; compress->out[i]->color_spec = codec; compress->out[i]->fps = fps; if(interlacing == INTERLACED_MERGED) { fprintf(stderr, "[FastDXT] Warning: deinterlacing input prior to compress!\n"); compress->out[i]->interlacing = PROGRESSIVE; } else { compress->out[i]->interlacing = interlacing; } } compress->tx_color_spec = codec; compress->interlacing_source = interlacing; compress->dxt_height = (compress->tile[0]->height + 3) / 4 * 4; switch (codec) { case RGB: compress->decoder = (decoder_t) vc_copylineRGBtoRGBA; compress->rgb = TRUE; break; case RGBA: compress->decoder = (decoder_t) memcpy; compress->rgb = TRUE; break; case R10k: compress->decoder = (decoder_t) vc_copyliner10k; compress->rgb = TRUE; break; case UYVY: case Vuy2: case DVS8: compress->decoder = (decoder_t) memcpy; compress->rgb = FALSE; break; case v210: compress->decoder = (decoder_t) vc_copylinev210; compress->rgb = FALSE; break; case DVS10: compress->decoder = (decoder_t) vc_copylineDVS10; compress->rgb = FALSE; break; case DPX10: compress->decoder = (decoder_t) vc_copylineDPX10toRGBA; compress->rgb = FALSE; break; default: fprintf(stderr, "Unknown codec %d!", codec); exit_uv(128); return FALSE; } int h_align = 0; for(i = 0; codec_info[i].name != NULL; ++i) { if(codec == codec_info[i].codec) { h_align = codec_info[i].h_align; } } assert(h_align != 0); for(i = 0; i < 2; ++i) { compress->tile[i]->linesize = vf_get_tile(compress->out[i], 0)->width * (compress->rgb ? 4 /*RGBA*/: 2/*YUV 422*/); if(compress->rgb) { compress->out[i]->color_spec = DXT1; } else { compress->out[i]->color_spec = DXT1_YUV; } } for (x = 0; x < compress->num_threads; x++) { int my_height = (compress->dxt_height / compress->num_threads) / 4 * 4; if(x == compress->num_threads - 1) { my_height = compress->dxt_height - my_height /* "their height" */ * x; } compress->buffer[x] = (unsigned char *)malloc(width * my_height * 4); } #ifdef HAVE_MACOSX compress->output_data = (unsigned char *)malloc(width * compress->dxt_height * 4); for(i = 0; i < 2; ++i) { compress->tile[i]->data = (char *)malloc(width * compress->dxt_height * 4); } #else /* * memalign doesn't exist on Mac OS. malloc always returns 16 * bytes aligned memory * * see: http://www.mythtv.org/pipermail/mythtv-dev/2006-January/044309.html */ compress->output_data = (unsigned char *)memalign(16, width * compress->dxt_height * 4); for(i = 0; i < 2; ++i) { compress->tile[i]->data = (char *)memalign(16, width * compress->dxt_height * 4); } #endif /* HAVE_MACOSX */ memset(compress->output_data, 0, width * compress->dxt_height * 4); for(i = 0; i < 2; ++i) { memset(compress->tile[i]->data, 0, width * compress->dxt_height * 4 / 8); } return TRUE; }
static void *display_deltacast_init(struct module *parent, const char *fmt, unsigned int flags) { UNUSED(parent); struct state_deltacast *s; ULONG Result,DllVersion,NbBoards,ChnType; ULONG BrdId = 0; s = (struct state_deltacast *)calloc(1, sizeof(struct state_deltacast)); s->magic = DELTACAST_MAGIC; s->frame = vf_alloc(1); s->tile = vf_get_tile(s->frame, 0); s->frames = 0; gettimeofday(&s->tv, NULL); s->initialized = FALSE; if(flags & DISPLAY_FLAG_AUDIO_EMBEDDED) { s->play_audio = TRUE; } else { s->play_audio = FALSE; } s->BoardHandle = s->StreamHandle = s->SlotHandle = NULL; s->audio_configured = FALSE; if(fmt && strcmp(fmt, "help") == 0) { show_help(); vf_free(s->frame); free(s); return &display_init_noerr; } if(fmt) { char *tmp = strdup(fmt); char *save_ptr = NULL; char *tok; tok = strtok_r(tmp, ":", &save_ptr); if(!tok) { free(tmp); show_help(); goto error; } if (strncasecmp(tok, "board=", strlen("board=")) == 0) { BrdId = atoi(tok + strlen("board=")); } else { fprintf(stderr, "Unknown option: %s\n\n", tok); free(tmp); show_help(); goto error; } free(tmp); } /* Query VideoMasterHD information */ Result = VHD_GetApiInfo(&DllVersion,&NbBoards); if (Result != VHDERR_NOERROR) { fprintf(stderr, "[DELTACAST] ERROR : Cannot query VideoMasterHD" " information. Result = 0x%08X\n", Result); goto error; } if (NbBoards == 0) { fprintf(stderr, "[DELTACAST] No DELTA board detected, exiting...\n"); goto error; } if(BrdId >= NbBoards) { fprintf(stderr, "[DELTACAST] Wrong index %d. Found %d cards.\n", BrdId, NbBoards); goto error; } /* Open a handle on first DELTA-hd/sdi/codec board */ Result = VHD_OpenBoardHandle(BrdId,&s->BoardHandle,NULL,0); if (Result != VHDERR_NOERROR) { fprintf(stderr, "[DELTACAST] ERROR : Cannot open DELTA board %u handle. Result = 0x%08X\n",BrdId,Result); goto error; } VHD_GetBoardProperty(s->BoardHandle, VHD_CORE_BP_TX0_TYPE, &ChnType); if((ChnType!=VHD_CHNTYPE_SDSDI)&&(ChnType!=VHD_CHNTYPE_HDSDI)&&(ChnType!=VHD_CHNTYPE_3GSDI)) { fprintf(stderr, "[DELTACAST] ERROR : The selected channel is not an SDI one\n"); goto bad_channel; } /* Disable RX0-TX0 by-pass relay loopthrough */ VHD_SetBoardProperty(s->BoardHandle,VHD_CORE_BP_BYPASS_RELAY_0,FALSE); /* Select a 1/1 clock system */ VHD_SetBoardProperty(s->BoardHandle,VHD_SDI_BP_CLOCK_SYSTEM,VHD_CLOCKDIV_1); pthread_mutex_init(&s->lock, NULL); return s; bad_channel: VHD_CloseBoardHandle(s->BoardHandle); error: vf_free(s->frame); free(s); return NULL; }