static void configure_with(struct state_decompress *decompressor, struct video_desc desc) { enum dxt_type type; #ifndef HAVE_MACOSX printf("[RTDXT] Trying OpenGL 3.1 context first.\n"); decompressor->gl_context = glx_init(MK_OPENGL_VERSION(3,1)); decompressor->legacy = FALSE; if(!decompressor->gl_context) { fprintf(stderr, "[RTDXT] OpenGL 3.1 profile failed to initialize, falling back to legacy profile.\n"); decompressor->gl_context = glx_init(OPENGL_VERSION_UNSPECIFIED); decompressor->legacy = TRUE; } glx_validate(decompressor->gl_context); #else decompressor->gl_context = NULL; if(get_mac_kernel_version_major() >= 11) { printf("[RTDXT] Mac 10.7 or latter detected. Trying OpenGL 3.2 Core profile first.\n"); decompressor->gl_context = mac_gl_init(MAC_GL_PROFILE_3_2); if(!decompressor->gl_context) { fprintf(stderr, "[RTDXT] OpenGL 3.2 Core profile failed to initialize, falling back to legacy profile.\n"); } else { decompressor->legacy = FALSE; } } if(!decompressor->gl_context) { decompressor->gl_context = mac_gl_init(MAC_GL_PROFILE_LEGACY); decompressor->legacy = TRUE; } #endif if(!decompressor->gl_context) { fprintf(stderr, "[RTDXT decompress] Failed to create GL context."); exit_uv(128); decompressor->compressed_len = 0; return; } if(desc.color_spec == DXT5) { type = DXT_TYPE_DXT5_YCOCG; } else if(desc.color_spec == DXT1) { type = DXT_TYPE_DXT1; } else if(desc.color_spec == DXT1_YUV) { type = DXT_TYPE_DXT1_YUV; } else { fprintf(stderr, "Wrong compressiong to decompress.\n"); return; } decompressor->desc = desc; decompressor->decoder = dxt_decoder_create(type, desc.width, desc.height, decompressor->out_codec == RGBA ? DXT_FORMAT_RGBA : DXT_FORMAT_YUV422, decompressor->legacy); assert(decompressor->decoder != NULL); decompressor->compressed_len = dxt_get_size(desc.width, desc.height, type); decompressor->configured = TRUE; }
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 * 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 int configure_with(struct compress_jpeg_state *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; /* TODO: enable (we need R10k -> RGB) * case R10k: s->decoder = (decoder_t) vc_copyliner10k; s->rgb = TRUE; 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; if(s->rgb) { s->encoder_param.interleaved = 0; s->encoder_param.restart_interval = 8; /* 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 = 2; /* 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); vf_get_tile(s->out[frame_idx], x)->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; }