Example #1
0
void PhotoScaleUnit::process_package(LoadPackage *package)
{
	PhotoScalePackage *pkg = (PhotoScalePackage*)package;
	VFrame *input = server->plugin->get_input();
	int w = input->get_w();
	int h = input->get_h();

	
	switch(input->get_color_model())
	{
		case BC_RGB_FLOAT:
			SCAN_BORDER(float, 3, 0);
			break;
		case BC_RGBA_FLOAT:
			SCAN_BORDER(float, 4, 0);
			break;
		case BC_RGB888:
			SCAN_BORDER(unsigned char, 3, 0);
			break;
		case BC_YUV888:
			SCAN_BORDER(unsigned char, 3, 1);
			break;
		case BC_RGBA8888:
		case BC_YUVA8888:
			SCAN_BORDER(unsigned char, 4, 0);
			break;
	}
}
Example #2
0
static void read_function(png_structp png_ptr, 
	png_bytep data, 
	png_uint_32 length)
{
	VFrame *input = (VFrame*)png_get_io_ptr(png_ptr);

	memcpy(data, input->get_data() + input->get_compressed_size(), length);
	input->set_compressed_size(input->get_compressed_size() + length);
}
Example #3
0
void DeviceV4L2Base::run()
{
	Thread::disable_cancel();
	int min_buffers = total_buffers / 2;
	if( min_buffers > 3 ) min_buffers = 3;

// Read buffers continuously
	while( !done )
	{
		int retry = 0;
		int qbfrs = q_bfrs;
		while( !done && (!qbfrs || (!retry && qbfrs < min_buffers)) )
		{
			Thread::enable_cancel();
			Timer::delay(10);
			Thread::disable_cancel();
			++retry;  qbfrs = q_bfrs;
		}
		if( done ) break;
		struct v4l2_buffer buffer;
		memset(&buffer, 0, sizeof(buffer));
		buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buffer.memory = V4L2_MEMORY_MMAP;

// The driver returns the first buffer not queued, so only one buffer
// can be unqueued at a time.
		Thread::enable_cancel();
		qbfrs_lock->lock("DeviceV4L2Base::run");
		int result = vioctl(VIDIOC_DQBUF, &buffer);
		if( !result ) --q_bfrs;
		qbfrs_lock->unlock();
		Thread::disable_cancel();
		if(result < 0)
		{
			perror("DeviceV4L2Base::run VIDIOC_DQBUF");
			Thread::enable_cancel();
			Timer::delay(10);
			Thread::disable_cancel();
			continue;
		}

// Get output frame
		int bfr = buffer.index;
// Set output frame data size/time, queue video
		VFrame *frame = device_buffers[bfr];
		if(color_model == BC_COMPRESSED)
			frame->set_compressed_size(buffer.bytesused);
		struct timeval *tv = &buffer.timestamp;
		double bfr_time = tv->tv_sec + tv->tv_usec / 1000000.;
		frame->set_timestamp(bfr_time);
		if( !getq->q(bfr) ) video_lock->unlock();
	}
}
Example #4
0
static void write_function(png_structp png_ptr, png_bytep data, png_uint_32 length)
{
	VFrame *output = (VFrame*)png_get_io_ptr(png_ptr);

	if(output->get_compressed_allocated() < output->get_compressed_size() + length)
		output->allocate_compressed_data((output->get_compressed_allocated() + length) * 2);
	memcpy(output->get_data() + output->get_compressed_size(), data, length);
	output->set_compressed_size(output->get_compressed_size() + length);
}
BC_Bitmap::BC_Bitmap(BC_WindowBase *parent_window, unsigned char *png_data)
{
// Decompress data into a temporary vframe
    VFrame frame;

    frame.read_png(png_data);

// Initialize the bitmap
    initialize(parent_window,
               frame.get_w(),
               frame.get_h(),
               parent_window->get_color_model(),
               0);

// Copy the vframe to the bitmap
    read_frame(&frame, 0, 0, w, h);
}
Example #6
0
int RecVideoOverlay::
overlay(VFrame *out)
{
	VFrame *in = vframe;
	int xx = x * scale, yy = y * scale;
	int w = in->get_w(), h = in->get_h();
	int ww = w * scale, hh = h * scale;
	BC_WindowBase::get_cmodels()->transfer(out->get_rows(), in->get_rows(),
		out->get_y(), out->get_u(), out->get_v(),
		in->get_y(), in->get_u(), in->get_v(),
		0, 0, w, h, xx, yy, ww, hh,
		in->get_color_model(), out->get_color_model(), 0,
		in->get_bytes_per_line(), out->get_bytes_per_line());
	return ticks > 0 && --ticks == 0 ? 1 : 0;
}
Example #7
0
void BC_Toggle::calculate_extents(BC_WindowBase *gui, 
	VFrame **images,
	int bottom_justify,
	int *text_line,
	int *w,
	int *h,
	int *toggle_x,
	int *toggle_y,
	int *text_x,
	int *text_y, 
	int *text_w,
	int *text_h, 
	const char *caption)
{
	BC_Resources *resources = get_resources();
	VFrame *frame = images[0];
	*w = frame->get_w();
	*h = frame->get_h();
	*toggle_x = 0;
	*toggle_y = 0;
	*text_x = *w + 5;
	*text_y = 0;
	*text_w = 0;
	*text_h = 0;

	if(caption)
	{
		*text_w = gui->get_text_width(MEDIUMFONT, caption);
		*text_h = gui->get_text_height(MEDIUMFONT);

		if(resources->toggle_highlight_bg)
		{
			*text_w += resources->toggle_text_margin * 2;
			*text_h = MAX(*text_h, resources->toggle_highlight_bg->get_h());
		}

		if(*text_h > *h)
		{
			*toggle_y = (*text_h - *h) >> 1;
			*h = *text_h;
		}
		else
Example #8
0
int FileList::write_frames(VFrame ***frames, int len)
{
	return_value = 0;

//printf("FileList::write_frames 1\n");
	if(frames[0][0]->get_color_model() == BC_COMPRESSED)
	{
		for(int i = 0; i < asset->layers && !return_value; i++)
		{
			for(int j = 0; j < len && !return_value; j++)
			{
				VFrame *frame = frames[i][j];
				char *path = create_path(frame->get_number());
//printf("FileList::write_frames %d " _LD "\n", __LINE__, frame->get_number());


				FILE *fd = fopen(path, "wb");
				if(fd)
				{
					return_value = !fwrite(frames[i][j]->get_data(),
						frames[i][j]->get_compressed_size(),
						1,
						fd);

					fclose(fd);
				}
				else
				{
					eprintf("Error while opening \"%s\" for writing. \n%m\n", asset->path);
					return_value++;
				}
			}
		}
	}
	else
	{
//printf("FileList::write_frames 2\n");
		writer->write_frames(frames, len);
//printf("FileList::write_frames 100\n");
	}
	return return_value;
}
Example #9
0
int FileYUV::read_frame(VFrame *frame)
{
	int result;
	VFrame *input = frame;

	// short cut for direct copy routines
	if (frame->get_color_model() == BC_COMPRESSED) {
		long frame_size = (long) // w*h + w*h/4 + w*h/4
			(stream->get_height() *	stream->get_width() * 1.5); 
		frame->allocate_compressed_data(frame_size);
		frame->set_compressed_size(frame_size);
		return stream->read_frame_raw(frame->get_data(), frame_size);
	}
	

	// process through a temp frame if necessary
	if (! cmodel_is_planar(frame->get_color_model()) ||
	    (frame->get_w() != stream->get_width()) ||
	    (frame->get_h() != stream->get_height())) 
	{
		ensure_temp(stream->get_width(), stream->get_height());
		input = temp;
	}

	uint8_t *yuv[3];
	yuv[0] = input->get_y();
	yuv[1] = input->get_u();
	yuv[2] = input->get_v();
	result = stream->read_frame(yuv);
	if (result) return result;

	// transfer from the temp frame to the real one
	if (input != frame) 
	{
		FFMPEG::convert_cmodel(input, frame);
	}
	
	return 0;
}
Example #10
0
void EXROStream::write(const char c[], int n)
{
	if(position + n > data->get_compressed_allocated())
		data->allocate_compressed_data(MAX(position + n, data->get_compressed_allocated() * 2));

	memcpy(data->get_data() + position, c, n);
	position += n;
	data->set_compressed_size(MAX(position, data->get_compressed_size()));
}
Example #11
0
int OilEffect::process_realtime(VFrame *input, VFrame *output)
{
    need_reconfigure |= load_configuration();



//printf("OilEffect::process_realtime %f %d\n", config.radius, config.use_intensity);
    this->input = input;
    this->output = output;

    if(EQUIV(config.radius, 0))
    {
        if(input->get_rows()[0] != output->get_rows()[0])
            output->copy_from(input);
    }
    else
    {
        if(input->get_rows()[0] == output->get_rows()[0])
        {
            if(!temp_frame) temp_frame = new VFrame(0,
                                                        -1,
                                                        input->get_w(),
                                                        input->get_h(),
                                                        input->get_color_model(),
                                                        -1);
            temp_frame->copy_from(input);
            this->input = temp_frame;
        }


        if(!engine)
        {
            engine = new OilServer(this, (PluginClient::smp + 1));
        }

        engine->process_packages();
    }



    return 0;
}
Example #12
0
void InterpolateVideo::average()
{
	VFrame *frame = get_output();
	int w = frame->get_w();
	int h = frame->get_h();

	switch(frame->get_color_model())
	{
		case BC_RGB_FLOAT:
			AVERAGE(float, float, 3, 1);
			break;
		case BC_RGB888:
		case BC_YUV888:
			AVERAGE(unsigned char, int, 3, 0xff);
			break;
		case BC_RGBA_FLOAT:
			AVERAGE(float, float, 4, 1);
			break;
		case BC_RGBA8888:
		case BC_YUVA8888:
			AVERAGE(unsigned char, int, 4, 0xff);
			break;
	}
}
Example #13
0
int FileYUV::write_frames(VFrame ***layers, int len)
{
	int result;

	// only one layer supported
	VFrame **frames = layers[0];
	VFrame *frame;

	for (int n = 0; n < len; n++) 
	{
		frame = frames[n];

		// short cut for direct copy routines
		if (frame->get_color_model() == BC_COMPRESSED) 
		{
			long frame_size = frame->get_compressed_size();
			if (incoming_asset->format == FILE_YUV) 
				return stream->write_frame_raw(frame->get_data(), frame_size);

			// decode and write an encoded frame
			if (FFMPEG::codec_id(incoming_asset->vcodec) != CODEC_ID_NONE) 
			{
				if (! ffmpeg) 
				{
					ffmpeg = new FFMPEG(incoming_asset);
					ffmpeg->init(incoming_asset->vcodec);
				}
				
				ensure_temp(incoming_asset->width, incoming_asset->height); 
				int result = ffmpeg->decode(frame->get_data(), frame_size, temp);

				// some formats are decoded one frame later
				if (result == FFMPEG_LATENCY) 
				{
					// remember to write the last frame
					pipe_latency++;
					return 0;
				}

				if (result) 
				{
					delete ffmpeg;
					ffmpeg = 0;
					return 1;
				}


				uint8_t *yuv[3];
				yuv[0] = temp->get_y();
				yuv[1] = temp->get_u();
				yuv[2] = temp->get_v();
				return stream->write_frame(yuv);
			}
		}

		// process through a temp frame only if necessary
		if (! cmodel_is_planar(frame->get_color_model()) ||
		    (frame->get_w() != stream->get_width()) ||
		    (frame->get_h() != stream->get_height())) 
		{
			ensure_temp(asset->width, asset->height);
			FFMPEG::convert_cmodel(frame, temp);
			frame = temp;
		}

		uint8_t *yuv[3];
		yuv[0] = frame->get_y();
		yuv[1] = frame->get_u();
		yuv[2] = frame->get_v();
		result = stream->write_frame(yuv);
		if (result) return result;
	}

	return 0;
}
Example #14
0
int FileFork::handle_command()
{
	int64_t result = 0;
	const int debug = 0;

	if(debug) printf("FileFork::handle_command %d (pid=%d) this=%p command=%d\n", 
		__LINE__, getpid(), this, command_token);
// to grab this task in the debugger
	//static int zbug = 1;  volatile int bug = zbug;
	//while( bug ) usleep(10000);

	switch(command_token)
	{
		case OPEN_FILE:
		{
			file = new File;
			file->is_fork = 1;


// Read file modes
			int offset = 0;
			int rd = *(int*)(command_data + offset);
			offset += sizeof(int);
			int wr = *(int*)(command_data + offset);
			offset += sizeof(int);
			file->cpus = *(int*)(command_data + offset);
			offset += sizeof(int);
			file->white_balance_raw = *(int*)(command_data + offset);
			offset += sizeof(int);
			file->interpolate_raw = *(int*)(command_data + offset);
			offset += sizeof(int);
			file->playback_subtitle = *(int*)(command_data + offset);
			offset += sizeof(int);
			file->current_program = *(int*)(command_data + offset);
			offset += sizeof(int);

// Read asset from socket
			BC_Hash table;
			table.load_string((char*)command_data + offset);
			Asset *new_asset = new Asset;
			new_asset->load_defaults(&table, "", 1, 1, 1, 1, 1);
			if(debug)
			{
				printf("FileFork::handle_command %d\n%s\n", 
				__LINE__, 
				command_data + offset);
				new_asset->dump();
			}


// printf("FileFork::handle_command %d\n", __LINE__);
// table.dump();
//printf("FileFork::handle_command %d server=%p\n", __LINE__, server);
//printf("FileFork::handle_command %d server->preferences=%p\n", __LINE__, server->preferences);
			result = file->open_file(
				server->preferences, 
				new_asset, 
				rd, 
				wr);
			new_asset->Garbage::remove_user();
			if(debug) printf("FileFork::handle_command %d result=" _LD "\n", 
				__LINE__, result);



// Send updated asset
			file->asset->save_defaults(&table, "", 1, 1, 1, 1, 1);
			char *string = 0;
			table.save_string(string);
			int buffer_size = strlen(string) + 1;
			send_result(result, (unsigned char*)string, buffer_size);
			free(string);
			break;
		}

		case SET_PROCESSORS:
			file->set_processors(*(int*)command_data);
			send_result(0, 0, 0);
			break;


		case SET_PRELOAD:
			file->set_preload(*(int64_t*)command_data);
			send_result(0, 0, 0);
			break;

		case SET_SUBTITLE:
			file->set_subtitle(*(int*)command_data);
			send_result(0, 0, 0);
			break;

		case SET_INTERPOLATE_RAW:
			file->set_interpolate_raw(*(int*)command_data);
			send_result(0, 0, 0);
			break;

		case SET_WHITE_BALANCE_RAW:
			file->set_white_balance_raw(*(int*)command_data);
			send_result(0, 0, 0);
			break;

		case CLOSE_FILE:
		{
			unsigned char result_buffer[sizeof(int64_t) * 2];
			int64_t *rbfr = (int64_t *)result_buffer;
			file->close_file(0);
			rbfr[0] = file->asset->audio_length;
			rbfr[1] = file->asset->video_length;
// printf("FileFork::handle_command %d " _LD " " _LD "\n", 
// __LINE__, 
// file->asset->audio_length, 
// file->asset->video_length);
			send_result(0, result_buffer, sizeof(int64_t) * 2);
			done = 1;
			break;
		}

		case GET_INDEX:
			result = file->get_index((char*)command_data);
			send_result(result, 0, 0);
			break;


		case START_AUDIO_THREAD:
		{
			int buffer_size = *(int*)command_data;
			int ring_buffers = *(int*)(command_data + sizeof(int));
			result = file->start_audio_thread(buffer_size, ring_buffers);
// Send buffer information back to server here
			int result_bytes = ring_buffers * 
				Samples::filefork_size() * 
				file->asset->channels;
			unsigned char result_buffer[result_bytes];
			for(int i = 0; i < ring_buffers; i++)
			{
				Samples **samples = file->audio_thread->audio_buffer[i];
				for(int j = 0; j < file->asset->channels; j++)
				{
					samples[j]->to_filefork(result_buffer +
						i * Samples::filefork_size() * file->asset->channels +
						j * Samples::filefork_size());
				}
			}

			send_result(result, result_buffer, result_bytes);
			break;
		}

		case START_VIDEO_THREAD:
		{
			int buffer_size = *(int*)command_data;
			int color_model = *(int*)(command_data + sizeof(int));
			int ring_buffers = *(int*)(command_data + sizeof(int) * 2);
			int compressed = *(int*)(command_data + sizeof(int) * 3);
// allocate buffers here
			result = file->start_video_thread(buffer_size, 
				color_model,
				ring_buffers,
				compressed);

// Send buffer information back to server here
			int result_bytes = ring_buffers *
				file->asset->layers *
				buffer_size *
				VFrame::filefork_size();
			unsigned char result_buffer[result_bytes];

			for(int i = 0; i < ring_buffers; i++)
			{
				VFrame ***frames = file->video_thread->video_buffer[i];
				for(int j = 0; j < file->asset->layers; j++)
				{
					for(int k = 0; k < buffer_size; k++)
					{
//printf("FileFork::handle_command %d j=%d k=%d %p %p\n", __LINE__, j, k, frames[j][k], frames[j][k]->get_shmid()));
						frames[j][k]->to_filefork(result_buffer +
							i * file->asset->layers *
								buffer_size *
								VFrame::filefork_size() +
							j * buffer_size *
								VFrame::filefork_size() +
							k * VFrame::filefork_size());
					}
				}
			}

			send_result(result, result_buffer, result_bytes);
			break;
		}


		case START_VIDEO_DECODE_THREAD:
			result = file->start_video_decode_thread();
			send_result(result, 0, 0);
			break;


		case STOP_AUDIO_THREAD:
			result = file->stop_audio_thread();
			send_result(result, 0, 0);
			break;

		case STOP_VIDEO_THREAD:
			result = file->stop_video_thread();
			send_result(result, 0, 0);
			break;

		case SET_CHANNEL:
			result = file->set_channel(*(int*)command_data);
			send_result(result, 0, 0);
			break;

		case SET_LAYER:
			result = file->set_layer(*(int*)command_data, 0);
			send_result(result, 0, 0);
			break;

		case GET_AUDIO_LENGTH:
			result = file->get_audio_length();
			send_result(result, 0, 0);
			break;

		case GET_VIDEO_LENGTH:
			result = file->get_video_length();
			send_result(result, 0, 0);
			break;

		case GET_VIDEO_POSITION:
			result = file->get_video_position();
			send_result(result, 0, 0);
			break;

		case GET_AUDIO_POSITION:
			result = file->get_audio_position();
			send_result(result, 0, 0);
			break;

		case SET_AUDIO_POSITION:
			result = file->set_audio_position(*(int64_t*)command_data);
			send_result(result, 0, 0);
			break;

		case SET_VIDEO_POSITION:
			result = file->set_video_position(*(int64_t*)command_data, 0);
			send_result(result, 0, 0);
			break;

		case WRITE_SAMPLES:
		{
			int entry_size = Samples::filefork_size();
			Samples **samples = new Samples*[file->asset->channels];
			for(int i = 0; i < file->asset->channels; i++)
			{
				samples[i] = new Samples;
				samples[i]->from_filefork(
					command_data + entry_size * i);
			}
			int64_t len = *(int64_t*)(command_data + 
				entry_size * file->asset->channels);

			result = file->write_samples(samples, len);
			send_result(result, 0, 0);

			for(int i = 0; i < file->asset->channels; i++)
			{
				delete samples[i];
			}
			delete [] samples;
			break;
		}

		case WRITE_FRAMES:
		{
//PRINT_TRACE
			int entry_size = VFrame::filefork_size();
//PRINT_TRACE
			VFrame ***frames = new VFrame**[file->asset->layers];
//printf("FileFork::handle_command %d %d\n", __LINE__, file->asset->layers);
			int len = *(int*)command_data;
//printf("FileFork::handle_command %d %d %d\n", __LINE__, file->asset->layers, len);

			for(int i = 0; i < file->asset->layers; i++)
			{
				frames[i] = new VFrame*[len];
				for(int j = 0; j < len; j++)
				{
					frames[i][j] = new VFrame;
//PRINT_TRACE
					frames[i][j]->from_filefork(command_data +
						sizeof(int) + 
						entry_size * len * i +
						entry_size * j);
// printf("FileFork::handle_command %d color_model=%d\n", 
// __LINE__, 
// frames[i][j]->get_color_model(),
// frames[i][j]->get_compressed_size());

//PRINT_TRACE
				}
			}

//PRINT_TRACE
			result = file->write_frames(frames, len);
//PRINT_TRACE

			send_result(result, 0, 0);
			for(int i = 0; i < file->asset->layers; i++)
			{
				for(int j = 0; j < len; j++)
				{
					delete frames[i][j];
				}
				delete [] frames[i];
			}
			delete [] frames;
			break;
		}


		case WRITE_AUDIO_BUFFER:
			result = file->write_audio_buffer(*(int64_t*)command_data);
			send_result(result, 0, 0);
			break;

		case WRITE_VIDEO_BUFFER:
		{
//printf("FileFork::handle_command %d\n", __LINE__);
			int len = *(int64_t*)command_data;
			VFrame ***video_buffer = file->video_thread->get_last_video_buffer();
			for(int i = 0; i < file->asset->layers; i++)
			{
				for(int j = 0; j < len; j++)
				{
// Copy memory state
//printf("FileFork::handle_command %d i=%d j=%d %p %p\n", __LINE__, i, j, video_buffer[i][j], video_buffer[i][j]->get_shmid());
					video_buffer[i][j]->from_filefork(command_data +
						sizeof(int64_t) +
						VFrame::filefork_size() * (len * i + j));
//printf("FileFork::handle_command %d %p " _LD "\n", __LINE__, video_buffer[i][j]->get_shmid(), video_buffer[i][j]->get_number());

				}
			}
		
			result = file->write_video_buffer(len);
			send_result(result, 0, 0);
//printf("FileFork::handle_command %d\n", __LINE__);
			break;
		}

		case GET_AUDIO_BUFFER:
		{
// 			int entry_size = Samples::filefork_size();
// 			int result_bytes = entry_size * file->asset->channels;
// 			unsigned char result_buffer[sizeof(int)];
// 			
// Make it swap buffers
//			Samples **samples = file->get_audio_buffer();
// 			for(int i = 0; i < file->asset->channels; i++)
// 			{
// 				samples[i]->to_filefork(result_buffer + 
// 					i * Samples::filefork_size());
// 			}

			file->get_audio_buffer();
			send_result(file->audio_thread->current_buffer, 0, 0);
			break;
		}

		case GET_VIDEO_BUFFER:
		{
// 			int entry_size = VFrame::filefork_size();
// 			int layers = file->asset->layers;
// 			int buffer_size = file->video_thread->buffer_size;
// 			int result_size = entry_size * 
// 				layers *
// 				buffer_size +
// 				sizeof(int);
// 			unsigned char result_buffer[result_size];
// 			*(int*)(result_buffer + entry_size * 
// 				layers *
// 				buffer_size) = buffer_size;
//printf("FileFork::handle_command %d layers=%d\n", __LINE__, layers);

//			VFrame ***frames = file->get_video_buffer();
// 			for(int i = 0; i < layers; i++)
// 			{
// 				for(int j = 0; j < buffer_size; j++)
// 				{
// 					frames[i][j]->to_filefork(result_buffer +
// 						entry_size * i * buffer_size +
// 						entry_size * j);
// 				}
// 			}

			file->get_video_buffer();
			send_result(file->video_thread->current_buffer, 0, 0);
//printf("FileFork::handle_command %d\n", __LINE__);
			break;
		}

		case READ_SAMPLES:
		{
			if(debug) PRINT_TRACE
			int len = *(int64_t*)(command_data + Samples::filefork_size());
			if(debug) PRINT_TRACE
			Samples *samples = new Samples;
			samples->from_filefork(command_data);
			if(debug) PRINT_TRACE

			result = file->read_samples(samples, len);
			if(debug) PRINT_TRACE
			send_result(result, 0, 0);
			if(debug) PRINT_TRACE

			delete samples;
			if(debug) PRINT_TRACE
			break;
		}

		case READ_FRAME:
		{
			VFrame *frame = new VFrame;
			frame->from_filefork(command_data);
			int allocated_data = frame->get_compressed_allocated();
			
			
// printf("FileFork::handle_command %d file=%p\n", 
// __LINE__, 
// file);
// frame->dump();
			result = file->read_frame(frame, 0);


// printf("FileFork::handle_command %d size=%d\n", 
// __LINE__, 
// frame->get_compressed_size());


// Send compressed data through socket only if data allocation changed.
			if(frame->get_color_model() == BC_COMPRESSED &&
				allocated_data != frame->get_compressed_allocated())
			{
				int result_size = sizeof(int) * 2 + frame->get_compressed_size();
				unsigned char *result_data = new unsigned char[result_size];
				*(int*)result_data = frame->get_compressed_size();
				*(int*)(result_data + sizeof(int)) = frame->get_keyframe();
				memcpy(result_data + sizeof(int) * 2, 
					frame->get_data(), 
					frame->get_compressed_size());
				send_result(result, 
					result_data, 
					result_size);
				delete [] result_data;
			}
			else
			{
				int result_size = sizeof(int) * 2;
				unsigned char *result_data = new unsigned char[result_size];
				*(int*)result_data = frame->get_compressed_size();
				*(int*)(result_data + sizeof(int)) = frame->get_keyframe();
				send_result(result, result_data, result_size);
				delete [] result_data;
			}


// printf("FileFork::handle_command %d size=%d\n", 
// __LINE__, 
// frame->get_compressed_size());
			delete frame;

// printf("FileFork::handle_command %d size=%d\n", 
// __LINE__, 
// frame->get_compressed_size());
			break;
		}

		case CAN_COPY_FROM:
		{
			FileXML xml;
			int64_t position = *(int64_t*)(command_data);
			int output_w = *(int*)(command_data + sizeof(int64_t));
			int output_h = *(int*)(command_data + sizeof(int64_t) + sizeof(int));
			xml.read_from_string((char*)command_data + 
				sizeof(int64_t) + 
				sizeof(int) * 2);
			xml.read_tag();
// Asset doesn't read the XML path.
			Asset *new_asset = new Asset(xml.tag.get_property("SRC"));
			new_asset->read(&xml, 1);
			result = file->can_copy_from(new_asset, 
				position, 
				output_w, 
				output_h);
			send_result(result, 0, 0);
			new_asset->Garbage::remove_user();
			break;
		}

		case COLORMODEL_SUPPORTED:
		{
			int colormodel = *(int*)command_data;
			result = file->colormodel_supported(colormodel);
			send_result(result, 0, 0);
			break;
		}

		case FILE_MEMORY_USAGE:
			result = file->file_memory_usage();
			send_result(result, 0, 0);
			break;

		case SET_PROGRAM:
		{
			int no = *(int*)command_data;
			result = file->set_program(no);
			send_result(result, 0, 0);
			break;
		}

		case GET_CELL_TIME:
		{
			double time;
			int no = *(int*)command_data;
			result = file->get_cell_time(no, time);
			send_result(result, (unsigned char *)&time, sizeof(time));
			break;
		}

		case GET_STT_TIME:
		{
			int64_t tm;
			result = file->get_system_time(tm);
			send_result(result, (unsigned char *)&tm, sizeof(tm));
			break;
		}

		case GET_AUDIO4VIDEO:
		{
			int64_t channel_mask = 0;
			int vstream = *(int*)command_data;
			int astream = *(int*)(command_data + sizeof(int));
			result = file->get_audio_for_video(vstream, astream, channel_mask);
			send_result(result, (unsigned char *)&channel_mask, sizeof(channel_mask));
			break;
		}

		case GET_VIDEO_PID:
		{
			int track = *(int*)command_data;
			result = file->get_video_pid(track);
			send_result(result, 0, 0);
			break;
		}

		case GET_VIDEO_INFO:
		{
			int width=0, height=0;  double framerate=0;
			char title[BCTEXTLEN];  title[0]=0;
			int track = *(int*)command_data;
			result = file->get_video_info(track, pid,
				framerate, width, height, title);
			unsigned char data[sizeof(framerate)+sizeof(pid)+
				sizeof(width)+sizeof(height)+sizeof(title)];
			unsigned char *bp = data;
			*(double *)bp = framerate;  bp += sizeof(framerate);
			*(int *)bp = pid;     bp += sizeof(pid);
			*(int *)bp = width;   bp += sizeof(width);
			*(int *)bp = height;  bp += sizeof(height);
			for( char *cp=title; (*bp++=*cp)!=0; ++cp );
			send_result(result, data, bp-data);
			break;
		}
		case SELECT_VIDEO_STREAM:
		{
			Asset *asset = new Asset;
			int vstream = *(int*)command_data;
			result = file->select_video_stream(asset, vstream);
			unsigned char data[sizeof(asset->frame_rate)+sizeof(asset->video_length)+
				sizeof(asset->width)+sizeof(asset->height)];
			unsigned char *bp = data;
			*(double *)bp = asset->frame_rate; bp += sizeof(asset->frame_rate);
			*(int *)bp = asset->video_length;  bp += sizeof(asset->video_length);
			*(int *)bp = asset->width;         bp += sizeof(asset->width);
			*(int *)bp = asset->height;        bp += sizeof(asset->height);
			delete asset;
			send_result(result, data, bp-data);
			break;
		}
		case SELECT_AUDIO_STREAM:
		{
			Asset *asset = new Asset;
			int astream = *(int*)command_data;
			result = file->select_audio_stream(asset, astream);
			unsigned char data[sizeof(asset->channels)+sizeof(asset->sample_rate)+
				sizeof(asset->audio_length)];
			unsigned char *bp = data;
			*(int *)bp = asset->channels;      bp += sizeof(asset->channels);
			*(int *)bp = asset->sample_rate;   bp += sizeof(asset->sample_rate);
			*(int *)bp = asset->audio_length;  bp += sizeof(asset->audio_length);
			delete asset;
			send_result(result, data, bp-data);
			break;
		}
	}

	return result;
}
Example #15
0
int FileDB::read_frame(VFrame *frame)
{
	int sw, sh;
	mdb->attachDb();
	int result = seq_no < clip_size ? 0 : 1;
	if( !result ) {
		int n = seq_no++;
		if( !n ) { frame_id = -1; }
		else if( n >= prefix_size ) n += suffix_offset;
		result = mdb->get_sequences(clip_id, n);
		if( !result && mdb->timeline_sequence_no() == n )
			frame_id = mdb->timeline_frame_id();
	}
	VFrame *fp = frame->get_w() == swidth && frame->get_h() == sheight &&
			frame->get_color_model() == BC_YUV420P ? frame :
		!vframe ? (vframe = new VFrame(swidth,sheight,BC_YUV420P)) :
		vframe;
	if( !result ) {
		if( frame_id < 0 )
			memset(fp->get_y(), 0, swidth*sheight);
		else
			result = mdb->get_image(frame_id, fp->get_y(), sw,sh);
	}
//printf("seq_no=%d, result=%d\n",seq_no,result);
	mdb->detachDb();
	if( !result ) {
		memset(fp->get_u(),0x80,swidth/2 * sheight/2);
		memset(fp->get_v(),0x80,swidth/2 * sheight/2);
	}
	if( !result && fp == vframe ) {
		BC_CModels::transfer(frame->get_rows(), fp->get_rows(),
			frame->get_y(), frame->get_u(), frame->get_v(),
			fp->get_y(), fp->get_u(), fp->get_v(),
			0, 0, fp->get_w(), fp->get_h(),
			0, 0, frame->get_w(), frame->get_h(),
			fp->get_color_model(), frame->get_color_model(), 0,
			fp->get_bytes_per_line(), swidth);
	}
	return result;
}
Example #16
0
void MaskUnit::process_package(LoadPackage *package)
{
	MaskPackage *ptr = (MaskPackage*)package;

	int start_row = SHRT_MIN;         // part for which mask exists
	int end_row;
	if(engine->recalculate)
	{
		VFrame *mask;
		if(engine->feather > 0) 
			mask = engine->temp_mask;
		else
			mask = engine->mask;

SET_TRACE
// Generated oversampling frame
		int mask_w = mask->get_w();
		int mask_h = mask->get_h();
		int mask_color_model = mask->get_color_model();
		int oversampled_package_w = mask_w * OVERSAMPLE;
		int oversampled_package_h = (ptr->row2 - ptr->row1) * OVERSAMPLE;
//printf("MaskUnit::process_package 1\n");

SET_TRACE

		int local_first_nonempty_rowspan = SHRT_MIN;
		int local_last_nonempty_rowspan = SHRT_MIN;

		if (!row_spans || row_spans_h != mask_h * OVERSAMPLE) {
			int i;	
			if (row_spans) {   /* size change */
				for (i = 0; i < row_spans_h; i++) 
					free(row_spans[i]);
				delete [] row_spans;
			}
			row_spans_h = mask_h * OVERSAMPLE;
			row_spans = new short *[mask_h * OVERSAMPLE]; 
			for (i= 0; i<mask_h * OVERSAMPLE; i++) {
				/* we use malloc so we can use realloc */
				row_spans[i] = (short *)malloc(sizeof(short) * NUM_SPANS);
				/* [0] is initialized later */
				row_spans[i][1] = NUM_SPANS;
			}
		}

SET_TRACE
//printf("MaskUnit::process_package 1 %d\n", engine->point_sets.total);

SET_TRACE

// Draw bezier curves onto span buffer
//struct timeval start_time;
//gettimeofday(&start_time, 0);

		for(int k = 0; k < engine->point_sets.total; k++)
		{
			int old_x, old_y;
			old_x = SHRT_MIN; // sentinel
			ArrayList<MaskPoint*> *points = engine->point_sets.values[k];

			if(points->total < 2) continue;
//printf("MaskUnit::process_package 2 %d %d\n", k, points->total);
			for (int i = ptr->row1 * OVERSAMPLE; i < ptr->row2 * OVERSAMPLE; i++) 
				row_spans[i][0] = 2; /* initialize to zero */ 
			(ptr->row1*OVERSAMPLE, ptr->row2*OVERSAMPLE); // init just my rows
			for(int i = 0; i < points->total; i++)
			{
				MaskPoint *point1 = points->values[i];
				MaskPoint *point2 = (i >= points->total - 1) ? 
					points->values[0] : 
					points->values[i + 1];

				float x0 = point1->x;
				float y0 = point1->y;
				float x1 = point1->x + point1->control_x2;
				float y1 = point1->y + point1->control_y2;
				float x2 = point2->x + point2->control_x1;
				float y2 = point2->y + point2->control_y1;
				float x3 = point2->x;
				float y3 = point2->y;

				// possible optimization here... since these coordinates are bounding box for curve
				// we can continue with next curve if they are out of our range

				// forward differencing bezier curves implementation taken from GPL code at
				// http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3

				float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;

				// [-1 +3 -3 +1]
				// [+3 -6 +3  0]
				// [-3 +3  0  0]
				// [+1  0  0  0]

		 		cx3 = (-  x0 + 3*x1 - 3*x2 + x3) * OVERSAMPLE;
				cx2 = ( 3*x0 - 6*x1 + 3*x2) * OVERSAMPLE;
				cx1 = (-3*x0 + 3*x1) * OVERSAMPLE;
				cx0 = (   x0) * OVERSAMPLE;

				cy3 = (-  y0 + 3*y1 - 3*y2 + y3) * OVERSAMPLE;
				cy2 = ( 3*y0 - 6*y1 + 3*y2) * OVERSAMPLE;
				cy1 = (-3*y0 + 3*y1) * OVERSAMPLE;
				cy0 = (   y0 - ptr->row1) * OVERSAMPLE;

				float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
				float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);

				float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
				float h = 1.0;

				if(maxaccel > 8.0 * OVERSAMPLE) h = sqrt((8.0 * OVERSAMPLE) / maxaccel);

				for(float t = 0.0; t < 1.0; t += h)
				{
					int x = (int) (cx0 + t*(cx1 + t*(cx2 + t*cx3)));
					int y = (int) (cy0 + t*(cy1 + t*(cy2 + t*cy3)));

					if (old_x != SHRT_MIN) 
						draw_line_clamped(old_x, old_y, x, y, oversampled_package_w, oversampled_package_h, ptr->row1 * OVERSAMPLE);
					old_x = x;
					old_y = y;
				}

				int x = (int)(x3 * OVERSAMPLE);
				int y = (int)((y3 - ptr->row1) * OVERSAMPLE);
				draw_line_clamped(old_x, old_y, x, y, oversampled_package_w, oversampled_package_h, ptr->row1 * OVERSAMPLE);
				old_x = (int)x;
				old_y = (int)y;
		
			}
//printf("MaskUnit::process_package 1\n");

			// Now we have ordered spans ready!
			//printf("Segment : %i , row1: %i\n", oversampled_package_h, ptr->row1);
			uint16_t value;
			if (mask_color_model == BC_A8)
				value = (int)((float)engine->value / 100 * 0xff);
			else
				value = (int)((float)engine->value / 100 * 0xffff);	// also for BC_A_FLOAT

			/* Scaneline sampling, inspired by Graphics gems I, page 81 */
			for (int i = ptr->row1; i < ptr->row2; i++) 
			{
				short min_x = SHRT_MAX;
				short max_x = SHRT_MIN;
				int j; 				/* universal counter for 0..OVERSAMPLE-1 */
				short *span;			/* current span - set inside loops with j */
				short span_p[OVERSAMPLE];	/* pointers to current positions in spans */
				#define P (span_p[j])		/* current span pointer */
				#define MAXP (span[0])		/* current span length */
				int num_empty_spans = 0;
				/* get the initial span pointers ready */
				for (j = 0; j < OVERSAMPLE; j++)
				{	
					span = row_spans[j + i * OVERSAMPLE];
					P = 2;              /* starting pointers to spans */
						/* hypotetical hypotetical fix goes here: take care that there is maximum one empty span for every subpixel */ 
					if (MAXP != 2) {                                        /* if span is not empty */
						if (span[2] < min_x) min_x = span[2];           /* take start of the first span */
						if (span[MAXP-1] > max_x) max_x = span[MAXP-1]; /* and end of last */
					} else              
					{	/* span is empty */
						num_empty_spans ++;	
					}	
				}
				if (num_empty_spans == OVERSAMPLE)
					continue; /* no work for us here */
				else 
				{       /* if we have engaged first nonempty rowspan...	remember it to speed up mask applying */
					if (local_first_nonempty_rowspan < 0 || i < local_first_nonempty_rowspan) 
						local_first_nonempty_rowspan = i;  
					if (i > local_last_nonempty_rowspan) local_last_nonempty_rowspan = i;
				}
				/* we have some pixels to fill, do coverage calculation for span */

				void *output_row = (unsigned char*)mask->get_rows()[i];
				min_x = min_x / OVERSAMPLE;
				max_x = (max_x + OVERSAMPLE - 1) / OVERSAMPLE;
				
				/* printf("row %i, pixel range: %i %i, spans0: %i\n", i, min_x, max_x, row_spans[i*OVERSAMPLE][0]-2); */

				/* this is not a full loop, since we jump trough h if possible */
				for (int h = min_x; h <= max_x; h++) 
				{
					short pixelleft = h * OVERSAMPLE;  /* leftmost subpixel of pixel*/
					short pixelright = pixelleft + OVERSAMPLE - 1; /* rightmost subpixel of pixel */
					uint32_t coverage = 0;
					int num_left = 0;               /* number of spans that have start left of the next pixel */
					short right_end = SHRT_MAX;     /* leftmost end of any span - right end of a full scanline */
					short right_start = SHRT_MAX;   /* leftmost start of any span - left end of empty scanline */

					for (j=0; j< OVERSAMPLE; j++) 
					{	
						char chg = 1;
						span = row_spans[j + i * OVERSAMPLE];
						while (P < MAXP && chg)
						{
						//	printf("Sp: %i %i\n", span[P], span[P+1]);
							if (span[P] == span[P+1])           /* ignore empty spans */
							{
								P +=2;
								continue;
							}
							if (span[P] <= pixelright)          /* if span start is before the end of pixel */
								coverage += MIN(span[P+1], pixelright)  /* 'clip' the span to pixel */
		                                                          - MAX(span[P], pixelleft) + 1;
							if (span[P+1] <= pixelright) 
								P += 2;
							else 
								chg = 0;
						} 
						if (P == MAXP) 
							num_left = -OVERSAMPLE; /* just take care that num_left cannot equal OVERSAMPLE or zero again */
						else	
						{ 
							if (span[P] <= pixelright)  /* if span starts before subpixel in the pixel on the right */
							{    /* useful for determining filled space till next non-fully-filled pixel */
								num_left ++;						
								if (span[P+1] < right_end) right_end = span[P+1]; 
							} else 
							{    /* useful for determining empty space till next non-empty pixel */
								if (span[P] < right_start) right_start = span[P]; 
							}
						}
					}
					// calculate coverage
					coverage *= value;
					coverage /= OVERSAMPLE * OVERSAMPLE;

					// when we have multiple masks the highest coverage wins
					switch (mask_color_model)
					{
					case BC_A8:
						if (((unsigned char *) output_row)[h] < coverage)
							((unsigned char*)output_row)[h] = coverage;
						break;
					case BC_A16:
						if (((uint16_t *) output_row)[h] < coverage)
							((uint16_t *) output_row)[h] = coverage;
						break;
					case BC_A_FLOAT:
						if (((float *) output_row)[h] < coverage/float(0xffff))
							((float *) output_row)[h] = coverage/float(0xffff);
						break;
					}
					/* possible optimization: do joining of multiple masks by span logics, not by bitmap logics*/
					
					if (num_left == OVERSAMPLE) 
					{
						/* all current spans start more left than next pixel */
						/* this means we can probably (if lucky) draw a longer horizontal line */
						right_end = (right_end / OVERSAMPLE) - 1; /* last fully covered pixel */
						if (right_end > h)
						{
							if (mask_color_model == BC_A8) 
								memset((char *)output_row + h + 1, value, right_end - h);
							else {
								/* we are f****d, since there is no 16bit memset */
								if (mask_color_model == BC_A16) {
									for (int z = h +1; z <= right_end; z++)
										((uint16_t *) output_row)[z] =  value;
								} else {
									for (int z = h +1; z <= right_end; z++)
										((float *) output_row)[z] =  value/float(0xffff);
								}
							}
							h = right_end;  
						}
					} else 
					if (num_left == 0) 
					{
						/* all current spans start right of next pixel */ 
						/* this means we can probably (if lucky) skip some pixels */
						right_start = (right_start / OVERSAMPLE) - 1; /* last fully empty pixel */
						if (right_start > h)
						{
							h = right_start;
						}
					}
				}
			}
		}
		engine->protect_data.lock();
		if (local_first_nonempty_rowspan < engine->first_nonempty_rowspan)
			engine->first_nonempty_rowspan = local_first_nonempty_rowspan;
		if (local_last_nonempty_rowspan > engine->last_nonempty_rowspan)
			engine->last_nonempty_rowspan = local_last_nonempty_rowspan;
		engine->protect_data.unlock();
	

//		int64_t dif= get_difference(&start_time);
//		printf("diff: %lli\n", dif);
	}	/* END OF RECALCULATION! */
Example #17
0
void BluebananaUnit::process_package(LoadPackage *package){
  BluebananaPackage *pkg = (BluebananaPackage*)package;
  BluebananaEngine *engine = (BluebananaEngine*)pkg->engine;

  VFrame *frame = engine->data;
  int w = frame->get_w();
  int h = frame->get_h();
  int ant = plugin->ants_counter;
  int gui_open = plugin->gui_open();
  int show_ants = plugin->config.mark && gui_open;
  int j;

  int active = plugin->config.active;
  int use_mask = plugin->config.use_mask;
  int capture_mask = plugin->config.capture_mask;
  int invert_selection = plugin->config.invert_selection;

  float *Hl = (plugin->config.Hsel_active &&
               (plugin->config.Hsel_lo!=0 ||
                plugin->config.Hsel_hi!=360)) ? plugin->hue_select_alpha_lookup : NULL;
  float *Sl = (plugin->config.Ssel_active &&
               (plugin->config.Ssel_lo!=0  ||
                plugin->config.Ssel_hi!=100)) ? plugin->sat_select_alpha_lookup : NULL;
  float *Vl = (plugin->config.Vsel_active &&
               (plugin->config.Vsel_lo!=0 ||
                plugin->config.Vsel_hi!=100)) ? plugin->val_select_alpha_lookup : NULL;

  float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;

  float *Sal = (plugin->config.Sadj_active &&
                (plugin->config.Sadj_lo!=0 ||
                 plugin->config.Sadj_hi!=100 ||
                 plugin->config.Sadj_gamma!=1)) ? plugin->sat_adj_lookup : NULL;
  float *Val = (plugin->config.Vadj_active &&
                (plugin->config.Vadj_lo!=0 ||
                 plugin->config.Vadj_hi!=100 ||
                 plugin->config.Vadj_gamma!=1)) ? plugin->val_adj_lookup : NULL;
  float *Ral = (plugin->config.Radj_active &&
                (plugin->config.Radj_lo!=0 ||
                 plugin->config.Radj_hi!=100 ||
                 plugin->config.Radj_gamma!=1)) ? plugin->red_adj_lookup : NULL;
  float *Gal = (plugin->config.Gadj_active &&
                (plugin->config.Gadj_lo!=0 ||
                 plugin->config.Gadj_hi!=100 ||
                 plugin->config.Gadj_gamma!=1)) ? plugin->green_adj_lookup : NULL;
  float *Bal = (plugin->config.Badj_active &&
                (plugin->config.Badj_lo!=0 ||
                 plugin->config.Badj_hi!=100 ||
                 plugin->config.Badj_gamma!=1)) ? plugin->blue_adj_lookup : NULL;

  float Sas = plugin->sat_adj_toe_slope;
  float Vas = plugin->val_adj_toe_slope;
  float Ras = plugin->red_adj_toe_slope;
  float Gas = plugin->green_adj_toe_slope;
  float Bas = plugin->blue_adj_toe_slope;

  float Aal = plugin->config.Oadj_active ? plugin->config.Oadj_val*.01 : 1.f;

  float Vscale = (plugin->config.Vadj_hi-plugin->config.Vadj_lo) / 100.f;
  float Vshift = plugin->config.Vadj_lo / 100.f;
  float Vgamma = plugin->config.Vadj_gamma;

  int doRGB = Ral || Gal || Bal;

  int doHSV = (Hal!=0) || Sal || Val;

  int doSEL = ( Hl || Sl || Vl ) && (active || show_ants);

  int shaping = plugin->config.Fsel_active && doSEL &&
    (plugin->config.Fsel_lo || plugin->config.Fsel_hi || plugin->config.Fsel_over);

  int byte_advance=0;
  int have_alpha=1;

#define SPLIT 128

  int tasks = engine->get_total_packages()*16;
  int taski,rowi,coli;

  /* do as much work entirely local to thread memory as possible */
  unsigned char row_fragment[SPLIT*16];
  float *selection_fullframe=NULL;
  float  selection[SPLIT];

  float Rvec[SPLIT];
  float Gvec[SPLIT];
  float Bvec[SPLIT];

  float Avec[SPLIT];
  float Hvec[SPLIT];
  float Svec[SPLIT];
  float Vvec[SPLIT];

  float *Rhist = pkg->Rhist;
  float *Ghist = pkg->Ghist;
  float *Bhist = pkg->Bhist;
  float *Hhist = pkg->Hhist;
  float *Shist = pkg->Shist;
  float *Vhist = pkg->Vhist;
  float Htotal=0.f;
  float Hweight=0.f;

  float *Hhr = pkg->Hhr;
  float *Hhg = pkg->Hhg;
  float *Hhb = pkg->Hhb;
  float *Shr = pkg->Shr;
  float *Shg = pkg->Shg;
  float *Shb = pkg->Shb;
  float *Vhr = pkg->Vhr;
  float *Vhg = pkg->Vhg;
  float *Vhb = pkg->Vhb;

  memset(Rhist,0,sizeof(pkg->Rhist));
  memset(Ghist,0,sizeof(pkg->Ghist));
  memset(Bhist,0,sizeof(pkg->Bhist));
  memset(Hhist,0,sizeof(pkg->Hhist));
  memset(Shist,0,sizeof(pkg->Shist));
  memset(Vhist,0,sizeof(pkg->Vhist));

  memset(Hhr,0,sizeof(pkg->Hhr));
  memset(Hhg,0,sizeof(pkg->Hhg));
  memset(Hhb,0,sizeof(pkg->Hhb));
  memset(Shr,0,sizeof(pkg->Shr));
  memset(Shg,0,sizeof(pkg->Shg));
  memset(Shb,0,sizeof(pkg->Shb));
  memset(Vhr,0,sizeof(pkg->Vhr));
  memset(Vhg,0,sizeof(pkg->Vhg));
  memset(Vhb,0,sizeof(pkg->Vhb));

  /* If we're doing fill shaping, we need to compute base selection
     for the entire frame before shaping. */

  if(shaping){
    engine->set_task(tasks*2,"shaping_even");
    while ( (taski = engine->next_task()) >= 0){

    /* operate on discontinuous, interleaved sections of the source
       buffer in two passes.  Although we could take extra steps to
       make cache contention across cores completely impossible, the
       extra locking and central join required isn't worth it.  It's
       preferable to make contention merely highly unlikely. */

      int start_row, end_row;
      if(taski<tasks){
        start_row = (taski*2)*h/(tasks*2);
        end_row = (taski*2+1)*h/(tasks*2);
      }else{
        start_row = ((taski-tasks)*2+1)*h/(tasks*2);
        end_row = ((taski-tasks)*2+2)*h/(tasks*2);
      }

      for(rowi = start_row; rowi<end_row; rowi++){
        unsigned char *row = frame->get_rows()[rowi];

        for(coli=0;coli<w;coli+=SPLIT){

          int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
          float *A = engine->selection_workA+w*rowi+coli;

          switch(frame->get_color_model()) {
          case BC_RGB888:
            rgb8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
            row += todo*3;
            break;
          case BC_RGBA8888:
            rgba8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
            row += todo*4;
            break;
          case BC_RGB_FLOAT:
            rgbF_to_RGB((float *)row,Rvec,Gvec,Bvec,todo);
            row += todo*12;
            break;
          case BC_RGBA_FLOAT:
            rgbaF_to_RGBA((float *)row,Rvec,Gvec,Bvec,Avec,todo);
            row += todo*16;
            break;
          case BC_YUV888:
            yuv8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
            row += todo*3;
            break;
          case BC_YUVA8888:
            yuva8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
            row += todo*4;
            break;
          }

          for(j = 0; j < todo; j++)
            RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);

          if(Hl)
            for(j = 0; j < todo; j++)
              selection[j]=sel_lookup(Hvec[j]*.166666667f,Hl);
          else
            for(j = 0; j < todo; j++)
              selection[j]=1.f;

          if(Sl)
            for(j = 0; j < todo; j++)
              selection[j]*=sel_lookup(Svec[j],Sl);

          if(Vl)
            for(j = 0; j < todo; j++)
              selection[j]*=sel_lookup(Vvec[j],Vl);

          /* lock the memcpy to prevent pessimal cache coherency
             interleave across cores. */
          pthread_mutex_lock(&engine->copylock);
          memcpy(A,selection,sizeof(*selection)*todo);
          pthread_mutex_unlock(&engine->copylock);
        }
      }
    }

    /* Perform fill shaping on the selection */
    selection_fullframe = plugin->fill_selection(engine->selection_workA,
                                                 engine->selection_workB, w, h, engine);
  }

  /* row-by-row color modification and histogram feedback */
  engine->set_task(tasks*2,"modification_even");
  while((taski = engine->next_task())>=0){

    /* operate on discontinuous, interleaved sections of the source
       buffer in two passes.  Although we could take extra steps to
       make cache contention across cores completely impossible, the
       extra locking and central join required isn't worth it.  It's
       preferable to make contention merely highly unlikely. */

    int start_row, end_row;
    if(taski<tasks){
      start_row = (taski*2)*h/(tasks*2);
      end_row = (taski*2+1)*h/(tasks*2);
    }else{
      start_row = ((taski-tasks)*2+1)*h/(tasks*2);
      end_row = ((taski-tasks)*2+2)*h/(tasks*2);
    }

    for(rowi = start_row; rowi<end_row; rowi++){
      unsigned char *row = frame->get_rows()[rowi];

      for(int coli=0;coli<w;coli+=SPLIT){
        int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
        int have_selection = 0;

        /* convert from pipeline color format */
        if(active || show_ants || (use_mask && capture_mask && have_alpha)){

          switch(frame->get_color_model()) {
          case BC_RGB888:
            pthread_mutex_lock(&engine->copylock);
            memcpy(row_fragment,row,todo*3);
            pthread_mutex_unlock(&engine->copylock);
            rgb8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
            byte_advance = todo*3;
            have_alpha=0;
            break;

          case BC_RGBA8888:
            pthread_mutex_lock(&engine->copylock);
            memcpy(row_fragment,row,todo*4);
            pthread_mutex_unlock(&engine->copylock);
            rgba8_to_RGBA(row_fragment,Rvec,Gvec,Bvec,Avec,todo);
            byte_advance = todo*4;
            have_alpha=1;
            break;

          case BC_RGB_FLOAT:
            pthread_mutex_lock(&engine->copylock);
            memcpy(row_fragment,row,todo*12);
            pthread_mutex_unlock(&engine->copylock);
            rgbF_to_RGB((float *)row_fragment,Rvec,Gvec,Bvec,todo);
            byte_advance = todo*12;
            have_alpha=0;
            break;

          case BC_RGBA_FLOAT:
            pthread_mutex_lock(&engine->copylock);
            memcpy(row_fragment,row,todo*16);
            pthread_mutex_unlock(&engine->copylock);
            rgbaF_to_RGBA((float *)row_fragment,Rvec,Gvec,Bvec,Avec,todo);
            byte_advance = todo*16;
            have_alpha=1;
            break;

          case BC_YUV888:
            pthread_mutex_lock(&engine->copylock);
            memcpy(row_fragment,row,todo*3);
            pthread_mutex_unlock(&engine->copylock);
            yuv8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
            byte_advance = todo*3;
            have_alpha=0;
            break;

          case BC_YUVA8888:
            pthread_mutex_lock(&engine->copylock);
            memcpy(row_fragment,row,todo*4);
            pthread_mutex_unlock(&engine->copylock);
            yuva8_to_RGBA(row,Rvec,Gvec,Bvec,Avec,todo);
            byte_advance = todo*4;
            have_alpha=1;
            break;
          }

          if(doSEL)
            /* generate initial HSV values [if selection active] */
            for(j = 0; j < todo; j++)
              RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);


          float selection_test=todo;

          if(selection_fullframe){

            /* get the full-frame selection data we need into thread-local storage */
            /* the full-frame data is read-only at this point, no need to lock */
            float *sf = selection_fullframe + rowi*w + coli;
            selection_test=0.f;
            for(j = 0; j < todo; j++)
              selection_test += selection[j] = sf[j];
            have_selection=1;

          }else{

            /* selection computation when no full-frame shaping */
            if(Hl){
              selection_test=0.f;
              for(j = 0; j < todo; j++)
                selection_test += selection[j] = sel_lookup(Hvec[j]*.166666667f,Hl);
              have_selection=1;
            }

            if(Sl){
              if(have_selection){
                if(selection_test>SELECT_THRESH){
                  selection_test=0.f;
                  for(j = 0; j < todo; j++)
                    selection_test += selection[j] *= sel_lookup(Svec[j],Sl);
                }
              }else{
                selection_test=0.f;
                for(j = 0; j < todo; j++)
                  selection_test += selection[j] = sel_lookup(Svec[j],Sl);
                have_selection=1;
              }
            }

            if(Vl){
              if(have_selection){
                if(selection_test>SELECT_THRESH){
                  selection_test=0.f;
                  for(j = 0; j < todo; j++)
                    selection_test += selection[j] *= sel_lookup(Vvec[j],Vl);
                }
              }else{
                selection_test=0.f;
                for(j = 0; j < todo; j++)
                  selection_test += selection[j] = sel_lookup(Vvec[j],Vl);
                have_selection=1;
              }
            }
          }

          /* selection modification according to config */
          if(use_mask && have_alpha){
            if(!have_selection){
              /* selection consists only of mask */
              selection_test=0.;
              for(j = 0; j < todo; j++)
                selection_test += selection[j] = Avec[j];
              have_selection=1;
            }else{
              if(invert_selection){
                if(selection_test < SELECT_THRESH){
                  /* fully selected after invert, clip to mask */
                  selection_test=0.f;
                  for(j = 0; j < todo; j++)
                    selection_test += selection[j] = Avec[j];
                }else if (selection_test >= todo-SELECT_THRESH){
                  /* fully deselected after invert */
                  selection_test=0.;
                }else{
                  /* partial selection after invert, clip to mask */
                  selection_test=0.f;
                  for(j = 0; j < todo; j++)
                    selection_test += selection[j] = Avec[j]*(1.f-selection[j]);
                }
              }else{
                if(selection_test < SELECT_THRESH){
                  /* fully deselected */
                }else if (selection_test >= todo-SELECT_THRESH){
                  /* fully selected, clip to mask */
                  selection_test=0.f;
                  for(j = 0; j < todo; j++)
                    selection_test += selection[j] = Avec[j];
                }else{
                  /* partial selection, clip to mask */
                  selection_test=0.f;
                  for(j = 0; j < todo; j++)
                    selection_test += selection[j] *= Avec[j];
                }
              }
            }
            if(selection_test < SELECT_THRESH){
              /* skip processing this fragment */
              /* we're using a mask; if the mask is set to capture, we
                 need to restore alpha before skipping */
              if(capture_mask){
                switch(frame->get_color_model()) {
                case BC_RGBA8888:
                  unmask_rgba8(row_fragment,todo);
                  break;
                case BC_RGBA_FLOAT:
                  unmask_rgbaF((float *)row_fragment,todo);
                  break;
                case BC_YUVA8888:
                  unmask_yuva8(row_fragment,todo);
                  break;
                }
                pthread_mutex_lock(&engine->copylock);
                memcpy(row,row_fragment,byte_advance);
                pthread_mutex_unlock(&engine->copylock);
              }

              row+=byte_advance;
              continue;
            }
            if(selection_test > todo-SELECT_THRESH)
              have_selection=0; // fully selected
          }else{
            if(have_selection){
              if(invert_selection){
                if(selection_test < SELECT_THRESH){
                  /* fully selected after inversion */
                  selection_test=todo;
                }else if (selection_test >= todo-SELECT_THRESH){
                  /* fully deselected after invert, skip fragment */
                  row+=byte_advance;
                  continue;
                }else{
                  /* partial selection */
                  selection_test=0.f;
                  for(j = 0; j < todo; j++)
                    selection_test += selection[j] = (1.f-selection[j]);
                }
              }else{
                if(selection_test < SELECT_THRESH){
                  /* fully deselected, skip fragment */
                  row+=byte_advance;
                  continue;
                }else if (selection_test >= todo-SELECT_THRESH){
                  /* fully selected */
                  selection_test=todo;
                }else{
                  /* partial selection; already calculated */
                }
              }
              if(selection_test < SELECT_THRESH){
                  row+=byte_advance;
                  continue; // inactive fragment
              }
              if(selection_test > todo-SELECT_THRESH)
                have_selection=0; // fully selected
            }else{
              if(invert_selection){
                  row+=byte_advance;
                  continue;
              }
            }
          }
        }

        if(active){

          /* red adjust */
          if(Ral) {
            if(have_selection){
              for(j = 0; j < todo; j++)
                if(selection[j]>SELECT_THRESH) Rvec[j]=adj_lookup(Rvec[j],Ral,Ras);
            }else{
              for(j = 0; j < todo; j++)
                Rvec[j] = adj_lookup(Rvec[j],Ral,Ras);
            }
          }
          /* red histogram */
          if(gui_open){
            if(have_selection){
              for(j = 0; j < todo; j++)
                if(selection[j]>SELECT_THRESH) Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
            }else{
              for(j = 0; j < todo; j++)
                Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
            }
          }

          /* green adjust */
          if(Gal) {
            if(have_selection){
              for(j = 0; j < todo; j++)
                if(selection[j]>SELECT_THRESH) Gvec[j]=adj_lookup(Gvec[j],Gal,Gas);
            }else{
              for(j = 0; j < todo; j++)
                Gvec[j] = adj_lookup(Gvec[j],Gal,Gas);
            }
          }
          /* green histogram */
          if(gui_open){
            if(have_selection){
              for(j = 0; j < todo; j++)
                if(selection[j]>SELECT_THRESH) Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
            }else{
              for(j = 0; j < todo; j++)
                Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
            }
          }

          /* blue adjust */
          if(Bal) {
            if(have_selection){
              for(j = 0; j < todo; j++)
                if(selection[j]>SELECT_THRESH) Bvec[j]=adj_lookup(Bvec[j],Bal,Bas);
            }else{
              for(j = 0; j < todo; j++)
                Bvec[j] = adj_lookup(Bvec[j],Bal,Bas);
            }
          }
          /* blue histogram */
          if(gui_open){
            if(have_selection){
              for(j = 0; j < todo; j++)
                if(selection[j]>SELECT_THRESH) Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
            }else{
              for(j = 0; j < todo; j++)
                Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
            }
          }

          /* compute HSV values or update values from earlier selection work if
             they've changed */
          if( (!doSEL || doRGB) && // not yet computed, or since modified
              (doHSV || gui_open) ) // needed for HSV mod and/or histograms
            for(j = 0; j < todo; j++)
              RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);

          if(doHSV){
            /* H modification */
            /* don't bother checking selection, H adj is lightweight */
            if(Hal){
              for(j = 0; j < todo; j++){
                Hvec[j] += Hal;
                if(Hvec[j]<0.f)Hvec[j]+=6.f;
                if(Hvec[j]>=6.f)Hvec[j]-=6.f;
              }
            }
            /* H histogram */
            /* this is pre-shift RGB data; shift hue later to save an HSV->RGB transform */
            if(gui_open){
              if(have_selection){
                for(j = 0; j < todo; j++){
                  if(selection[j]>SELECT_THRESH){
                    float weight = selection[j]*Svec[j];
                    int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
                    Htotal += selection[j];
                    Hweight += weight;
                    Hhist[bin] += weight;
                    Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
                    Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
                    Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
                  }
                }
              }else{
                for(j = 0; j < todo; j++){
                  float weight = Svec[j];
                  int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
                  Htotal += 1.f;
                  Hweight += weight;
                  Hhist[bin] += weight;
                  Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
                  Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
                  Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
                }
              }
            }

            /* S modification */
            if(Sal) {
              if(have_selection){
                for(j = 0; j < todo; j++)
                  if(selection[j]>SELECT_THRESH) Svec[j] = adj_lookup(Svec[j],Sal,Sas);
              }else{
                for(j = 0; j < todo; j++)
                  Svec[j] = adj_lookup(Svec[j],Sal,Sas);
              }
            }

            /* This is unrolled a few times below...
               Although we're using HSV, we don't want hue/saturation
               changes to have a strong effect on apparent brightness.
               Apply a correction to V (not Y!) based on luma change. */
            /* Calculate new RGB values at same time */
            if(Hal || Sal){
              if(have_selection){
                for(j = 0; j < todo; j++){
                  if(selection[j]>SELECT_THRESH){
                    HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
                    /* run S histogram at the same time as we've got
                       the RGB data */
                    if(gui_open){
                      int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
                      Shist[bin] += selection[j];
                      Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
                      Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
                      Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
                    }
                  }
                }
              }else{
                for(j = 0; j < todo; j++){
                  HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
                  if(gui_open){
                    int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
                    Shist[bin] += 1.f;
                    Shr[bin>>HRGBSHIFT] += Rvec[j];
                    Shg[bin>>HRGBSHIFT] += Gvec[j];
                    Shb[bin>>HRGBSHIFT] += Bvec[j];
                  }
                }
              }
            }else{
              if(gui_open){
                if(have_selection){
                  for(j = 0; j < todo; j++){
                    if(selection[j]>SELECT_THRESH){
                      int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
                      Shist[bin] += selection[j];
                      Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
                      Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
                      Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
                    }
                  }
                }else{
                  for(j = 0; j < todo; j++){
                    int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
                    Shist[bin] += 1.f;
                    Shr[bin>>HRGBSHIFT] += Rvec[j];
                    Shg[bin>>HRGBSHIFT] += Gvec[j];
                    Shb[bin>>HRGBSHIFT] += Bvec[j];
                  }
                }
              }
Example #18
0
int TimeFrontMain::process_buffer(VFrame **frame,
		int64_t start_position,
		double frame_rate)
//int TimeFrontMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
{
	VFrame **outframes = frame;
	VFrame *(framelist[1024]);
	framelist[0] = new VFrame (
		outframes[0]->get_w(),
		outframes[0]->get_h(),
		outframes[0]->get_color_model());
	read_frame(framelist[0],
		0,
		start_position,
		frame_rate);
	this->input = framelist[0];
	this->output = outframes[0];
	need_reconfigure |= load_configuration();
	if (config.shape == TimeFrontConfig::OTHERTRACK)
	{
//		this->output = frame[1];
		if (get_total_buffers() != 2) 
		{
			// FIXME, maybe this should go to some other notification area?
			printf("ERROR: TimeFront plugin - If you are using another track for timefront, you have to have it under shared effects\n");
			return 0;
		}
		if (outframes[0]->get_w() != outframes[1]->get_w() || outframes[0]->get_h() != outframes[1]->get_h())
		{
			printf("Sizes of master track and timefront track do not match\n");
			return 0;
		}
	}

// Generate new gradient
	if(need_reconfigure)
	{
		need_reconfigure = 0;

		if(!gradient) gradient = new VFrame(
			outframes[0]->get_w(),
			outframes[0]->get_h(),
			BC_A8);

			
		if (config.shape != TimeFrontConfig::OTHERTRACK &&
		    config.shape != TimeFrontConfig::ALPHA)
		{
			if(!engine) engine = new TimeFrontServer(this,
				get_project_smp() + 1,
				get_project_smp() + 1);
			engine->process_packages();
		}
		
	}
	if (config.shape == TimeFrontConfig::ALPHA)
	{
		if(!gradient) gradient = new VFrame(
			outframes[0]->get_w(),
			outframes[0]->get_h(),
			BC_A8);
		VFrame *tfframe = framelist[0];
		switch (tfframe->get_color_model())
		{
			case BC_YUVA8888:
			case BC_RGBA8888:
				GRADIENTFROMCHANNEL(unsigned char, 4, 255, 3);


				break;
			case BC_RGBA_FLOAT:
				GRADIENTFROMCHANNEL(float, 4, 1.0f, 3);
				break;
			
			default:
				{
					printf("TimeFront plugin error: ALPHA used, but project color model does not have alpha\n");
					return 1;
					break;
				}
		}

	} else
	if (config.shape == TimeFrontConfig::OTHERTRACK)
Example #19
0
void SceneNode::render(VFrame *frame, int do_camera)
{
	const int debug = 0;
	if(debug) printf("SceneNode::render %d this=%p title=%s image=%p x=%f y=%f frame=%p do_camera=%d\n", 
		__LINE__, 
		this,
		title,
		image,
		this->x,
		this->y,
		frame,
		do_camera);

	VFrame *temp = 0;
	VFrame *temp2 = 0;
	if(image)
	{
		float x = this->x;
		float y = this->y;
		float sx = this->sx;
		float sy = this->sy;
		float ry = this->ry;
		if(parent) 
			parent->transform_coord(&x, &y, &sx, &sy, &ry);

		if(do_camera) scene->transform_camera(frame, 
			&x, 
			&y, 
			&sx, 
			&sy, 
			get_flip());

		if(debug) printf("SceneNode::render %d at_y=%f\n", 
			__LINE__, 
			((SceneCamera*)scene->cameras.get(0))->at_y);

// Render everything into a temporary, then overlay the temporary
// 		if(!EQUIV(ry, 0) || get_flip())
// 		{
		temp = new VFrame(image->get_w(), 
			image->get_h(), 
			image->get_color_model());
//		}
		if(debug) printf("SceneNode::render %d\n", __LINE__);


// 1st comes our image
		temp->copy_from(image);

// Then come the subnodes without camera transforms
		if(debug) printf("SceneNode::render %d this=%p nodes=%d\n", __LINE__, this, nodes.size());
		for(int i = 0; i < nodes.size(); i++)
			nodes.get(i)->render(temp, 0);



		if(debug) printf("SceneNode::render %d\n", __LINE__);

// Then comes rotation into temp2
		VFrame *src = temp;
		if(!EQUIV(ry, 0))
		{
			src = temp2 = new VFrame(image->get_w(), 
				image->get_h(), 
				image->get_color_model());
			if(!scene->affine) scene->affine = 
				new AffineEngine(scene->cpus, scene->cpus);
			scene->affine->rotate(temp2,
				temp,
				ry);
			if(debug) printf("SceneNode::render %d ry=%f\n", __LINE__, ry);
		}

// Then comes flipping
		if(get_flip())
			src->flip_horiz();

		if(debug) printf("SceneNode::render %d src=%p x=%f y=%f sx=%f sy=%f\n", 
			__LINE__, 
			src,
			x,
			y,
			sx,
			sy);

// Overlay on the output frame
		if(!scene->overlayer) scene->overlayer = new OverlayFrame(scene->cpus);

		if(get_flip())
		{
			scene->overlayer->overlay(frame, 
				src, 
				0, 
				0, 
				image->get_w(), 
				image->get_h(), 
				frame->get_w() - x - image->get_w() * sx, 
				y, 
				frame->get_w() - x, 
				y + image->get_h() * sy, 
				1,
				TRANSFER_NORMAL,
				NEAREST_NEIGHBOR);
		}
		else
		{
			if(debug) printf("SceneNode::render %d image=%p src=%p frame=%p\n", 
				__LINE__, 
				image,
				src,
				frame);
			scene->overlayer->overlay(frame, 
				src, 
				0, 
				0, 
				image->get_w(), 
				image->get_h(), 
				x, 
				y, 
				x + image->get_w() * sx, 
				y + image->get_h() * sy, 
				1,
				TRANSFER_NORMAL,
				NEAREST_NEIGHBOR);
		}

		if(debug) printf("SceneNode::render %d\n", __LINE__);

	}
	else
	{
		for(int i = 0; i < nodes.size(); i++)
			nodes.get(i)->render(frame, 1);
	}

	if(debug) printf("SceneNode::render %d this=%p title=%s\n", __LINE__, this, title);

	if(temp) delete temp;
	if(temp2) delete temp2;
}
Example #20
0
int Overlay::handle_opengl()
{
#ifdef HAVE_GL
	static const char *get_pixels_frag =
		"uniform sampler2D src_tex;\n"
		"uniform sampler2D dst_tex;\n"
		"uniform vec2 dst_tex_dimensions;\n"
		"uniform vec3 chroma_offset;\n"
		"void main()\n"
		"{\n"
		"	vec4 result_color;\n"
		"	vec4 dst_color = texture2D(dst_tex, gl_FragCoord.xy / dst_tex_dimensions);\n"
		"	vec4 src_color = texture2D(src_tex, gl_TexCoord[0].st);\n"
		"	src_color.rgb -= chroma_offset;\n"
		"	dst_color.rgb -= chroma_offset;\n";

	static const char *put_pixels_frag =
		"	result_color.rgb += chroma_offset;\n"
		"	result_color.rgb = mix(dst_color.rgb, result_color.rgb, src_color.a);\n"
		"	result_color.a = max(src_color.a, dst_color.a);\n"
		"	gl_FragColor = result_color;\n"
		"}\n";

	static const char *blend_add_frag =
		"	result_color.rgb = dst_color.rgb + src_color.rgb;\n";

	static const char *blend_max_frag =
		"	result_color.r = max(abs(dst_color.r, src_color.r);\n"
		"	result_color.g = max(abs(dst_color.g, src_color.g);\n"
		"	result_color.b = max(abs(dst_color.b, src_color.b);\n";

	static const char *blend_min_frag =
		"	result_color.r = min(abs(dst_color.r, src_color.r);\n"
		"	result_color.g = min(abs(dst_color.g, src_color.g);\n"
		"	result_color.b = min(abs(dst_color.b, src_color.b);\n";

	static const char *blend_subtract_frag =
		"	result_color.rgb = dst_color.rgb - src_color.rgb;\n";


	static const char *blend_multiply_frag =
		"	result_color.rgb = dst_color.rgb * src_color.rgb;\n";

	static const char *blend_divide_frag =
		"	result_color.rgb = dst_color.rgb / src_color.rgb;\n"
		"	if(src_color.r == 0.0) result_color.r = 1.0;\n"
		"	if(src_color.g == 0.0) result_color.g = 1.0;\n"
		"	if(src_color.b == 0.0) result_color.b = 1.0;\n";


	VFrame *src = temp;
	VFrame *dst = get_output(output_layer);

	dst->enable_opengl();
	dst->init_screen();

	const char *shader_stack[] = { 0, 0, 0 };
	int current_shader = 0;




// Direct copy layer
	if(config.mode == TRANSFER_REPLACE)
	{
		src->to_texture();
		src->bind_texture(0);
		dst->enable_opengl();
		dst->init_screen();

// Multiply alpha
		glDisable(GL_BLEND);
		src->draw_texture();
	}
	else
	if(config.mode == TRANSFER_NORMAL)
	{
		dst->enable_opengl();
		dst->init_screen();

// Move destination to screen
		if(dst->get_opengl_state() != VFrame::SCREEN)
		{
			dst->to_texture();
			dst->bind_texture(0);
			dst->draw_texture();
		}

		src->to_texture();
		src->bind_texture(0);
		dst->enable_opengl();
		dst->init_screen();

		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		src->draw_texture();
	}
	else
	{
// Read destination back to texture
		dst->to_texture();

		src->enable_opengl();
		src->init_screen();
		src->to_texture();

		dst->enable_opengl();
		dst->init_screen();
		src->bind_texture(0);
		dst->bind_texture(1);


		shader_stack[current_shader++] = get_pixels_frag;

		switch(config.mode)
		{
			case TRANSFER_ADDITION:
				shader_stack[current_shader++] = blend_add_frag;
				break;
			case TRANSFER_SUBTRACT:
				shader_stack[current_shader++] = blend_subtract_frag;
				break;
			case TRANSFER_MULTIPLY:
				shader_stack[current_shader++] = blend_multiply_frag;
				break;
			case TRANSFER_DIVIDE:
				shader_stack[current_shader++] = blend_divide_frag;
				break;
			case TRANSFER_MAX:
				shader_stack[current_shader++] = blend_max_frag;
				break;
			case TRANSFER_MIN:
				shader_stack[current_shader++] = blend_min_frag;
				break;
		}

		shader_stack[current_shader++] = put_pixels_frag;

		unsigned int shader_id = 0;
		shader_id = VFrame::make_shader(0,
			shader_stack[0],
			shader_stack[1],
			shader_stack[2],
			0);

		glUseProgram(shader_id);
		glUniform1i(glGetUniformLocation(shader_id, "src_tex"), 0);
		glUniform1i(glGetUniformLocation(shader_id, "dst_tex"), 1);
		if(BC_CModels::is_yuv(dst->get_color_model()))
			glUniform3f(glGetUniformLocation(shader_id, "chroma_offset"), 0.0, 0.5, 0.5);
		else
			glUniform3f(glGetUniformLocation(shader_id, "chroma_offset"), 0.0, 0.0, 0.0);
		glUniform2f(glGetUniformLocation(shader_id, "dst_tex_dimensions"),
			(float)dst->get_texture_w(),
			(float)dst->get_texture_h());

		glDisable(GL_BLEND);
		src->draw_texture();
		glUseProgram(0);
	}

	glDisable(GL_BLEND);
	glActiveTexture(GL_TEXTURE1);
	glDisable(GL_TEXTURE_2D);
	glActiveTexture(GL_TEXTURE0);
	glDisable(GL_TEXTURE_2D);

	dst->set_opengl_state(VFrame::SCREEN);
#endif
	return 0;
}
void BrightnessUnit::process_package(LoadPackage *package)
{
	BrightnessPackage *pkg = (BrightnessPackage*)package;


	VFrame *output = plugin->output;
	VFrame *input = plugin->input;
	




#define DO_BRIGHTNESS(max, type, components, is_yuv) \
{ \
	type **input_rows = (type**)input->get_rows(); \
	type **output_rows = (type**)output->get_rows(); \
	int row1 = pkg->row1; \
	int row2 = pkg->row2; \
	int width = output->get_w(); \
	int r, g, b; \
 \
	if(!EQUIV(plugin->config.brightness, 0)) \
	{ \
		int offset = (int)(plugin->config.brightness / 100 * max); \
/*printf("DO_BRIGHTNESS offset=%d\n", offset);*/ \
 \
		for(int i = row1; i < row2; i++) \
		{ \
			type *input_row = input_rows[i]; \
			type *output_row = output_rows[i]; \
 \
			for(int j = 0; j < width; j++) \
			{ \
				r = input_row[j * components] + offset; \
 \
 				if(!is_yuv) \
				{ \
					g = input_row[j * components + 1] + offset; \
					b = input_row[j * components + 2] + offset; \
				} \
 \
				CLAMP(r, 0, max); \
				if(!is_yuv) \
				{ \
					CLAMP(g, 0, max); \
					CLAMP(b, 0, max); \
				} \
 \
				output_row[j * components] = r; \
 \
 				if(!is_yuv) \
				{ \
					output_row[j * components + 1] = g; \
					output_row[j * components + 2] = b; \
				} \
				else \
				{ \
					output_row[j * components + 1] = input_row[j * components + 1]; \
					output_row[j * components + 2] = input_row[j * components + 2]; \
				} \
 \
 				if(components == 4)  \
					output_row[j * components + 3] = input_row[j * components + 3]; \
			} \
		} \
 \
/* Data to be processed is now in the output buffer */ \
		input_rows = output_rows; \
	} \
 \
	if(!EQUIV(plugin->config.contrast, 0)) \
	{ \
		float contrast = (plugin->config.contrast < 0) ?  \
			(plugin->config.contrast + 100) / 100 :  \
			(plugin->config.contrast + 25) / 25; \
/*printf("DO_BRIGHTNESS contrast=%f\n", contrast);*/ \
 \
		int scalar = (int)(contrast * 0x100); \
		int offset = (max << 8) / 2 - max * scalar / 2; \
		int y, u, v; \
 \
		for(int i = row1; i < row2; i++) \
		{ \
			type *input_row = input_rows[i]; \
			type *output_row = output_rows[i]; \
 \
 			if(plugin->config.luma) \
			{ \
				for(int j = 0; j < width; j++) \
				{ \
					if(is_yuv) \
					{ \
						y = input_row[j * components]; \
					} \
					else \
					{ \
						r = input_row[j * components]; \
						g = input_row[j * components + 1]; \
						b = input_row[j * components + 2]; \
						if(max == 0xff) \
						{ \
							BrightnessMain::yuv.rgb_to_yuv_8( \
								r,  \
								g,  \
								b,  \
								y,  \
								u,  \
								v); \
						} \
						else \
						{ \
							BrightnessMain::yuv.rgb_to_yuv_16( \
								r,  \
								g,  \
								b,  \
								y,  \
								u,  \
								v); \
						} \
	 \
					} \
	 \
					y = (y * scalar + offset) >> 8; \
					CLAMP(y, 0, max); \
	 \
	 \
 					if(is_yuv) \
					{ \
						output_row[j * components] = y; \
						output_row[j * components + 1] = input_row[j * components + 1]; \
						output_row[j * components + 2] = input_row[j * components + 2]; \
					} \
					else \
					{ \
						if(max == 0xff) \
						{ \
							BrightnessMain::yuv.yuv_to_rgb_8( \
								r,  \
								g,  \
								b,  \
								y,  \
								u,  \
								v); \
						} \
						else \
						{ \
							BrightnessMain::yuv.yuv_to_rgb_16( \
								r,  \
								g,  \
								b,  \
								y,  \
								u,  \
								v); \
						} \
						input_row[j * components] = r; \
						input_row[j * components + 1] = g; \
						input_row[j * components + 2] = b; \
					} \
	 \
 					if(components == 4)  \
						output_row[j * components + 3] = input_row[j * components + 3]; \
				} \
			} \
			else \
			{ \
				for(int j = 0; j < width; j++) \
				{ \
					r = input_row[j * components]; \
					g = input_row[j * components + 1]; \
					b = input_row[j * components + 2]; \
 \
					r = (r * scalar + offset) >> 8; \
					g = (g * scalar + offset) >> 8; \
					b = (b * scalar + offset) >> 8; \
 \
					CLAMP(r, 0, max); \
					CLAMP(g, 0, max); \
					CLAMP(b, 0, max); \
 \
					output_row[j * components] = r; \
					output_row[j * components + 1] = g; \
					output_row[j * components + 2] = b; \
 \
 					if(components == 4)  \
						output_row[j * components + 3] = input_row[j * components + 3]; \
				} \
			} \
		} \
	} \
}



#define DO_BRIGHTNESS_F(components) \
{ \
	float **input_rows = (float**)input->get_rows(); \
	float **output_rows = (float**)output->get_rows(); \
	int row1 = pkg->row1; \
	int row2 = pkg->row2; \
	int width = output->get_w(); \
	float r, g, b; \
 \
	if(!EQUIV(plugin->config.brightness, 0)) \
	{ \
		float offset = plugin->config.brightness / 100; \
 \
		for(int i = row1; i < row2; i++) \
		{ \
			float *input_row = input_rows[i]; \
			float *output_row = output_rows[i]; \
 \
			for(int j = 0; j < width; j++) \
			{ \
				r = input_row[j * components] + offset; \
				g = input_row[j * components + 1] + offset; \
				b = input_row[j * components + 2] + offset; \
 \
				output_row[j * components] = r; \
				output_row[j * components + 1] = g; \
				output_row[j * components + 2] = b; \
 				if(components == 4)  \
					output_row[j * components + 3] = input_row[j * components + 3]; \
			} \
		} \
 \
/* Data to be processed is now in the output buffer */ \
		input_rows = output_rows; \
	} \
 \
	if(!EQUIV(plugin->config.contrast, 0)) \
	{ \
		float contrast = (plugin->config.contrast < 0) ?  \
			(plugin->config.contrast + 100) / 100 :  \
			(plugin->config.contrast + 25) / 25; \
 \
/* Shift black level down so shadows get darker instead of lighter */ \
		float offset = 0.5 - contrast / 2; \
		float y, u, v; \
 \
		for(int i = row1; i < row2; i++) \
		{ \
			float *input_row = input_rows[i]; \
			float *output_row = output_rows[i]; \
 \
 			if(plugin->config.luma) \
			{ \
				for(int j = 0; j < width; j++) \
				{ \
					r = input_row[j * components]; \
					g = input_row[j * components + 1]; \
					b = input_row[j * components + 2]; \
					YUV::rgb_to_yuv_f( \
						r,  \
						g,  \
						b,  \
						y,  \
						u,  \
						v); \
 \
					y = y * contrast + offset; \
 \
 \
					YUV::yuv_to_rgb_f( \
						r,  \
						g,  \
						b,  \
						y,  \
						u,  \
						v); \
					input_row[j * components] = r; \
					input_row[j * components + 1] = g; \
					input_row[j * components + 2] = b; \
 \
 					if(components == 4)  \
						output_row[j * components + 3] = input_row[j * components + 3]; \
				} \
			} \
			else \
			{ \
				for(int j = 0; j < width; j++) \
				{ \
					r = input_row[j * components]; \
					g = input_row[j * components + 1]; \
					b = input_row[j * components + 2]; \
 \
					r = r * contrast + offset; \
					g = g * contrast + offset; \
					b = b * contrast + offset; \
 \
					output_row[j * components] = r; \
					output_row[j * components + 1] = g; \
					output_row[j * components + 2] = b; \
 \
 					if(components == 4)  \
						output_row[j * components + 3] = input_row[j * components + 3]; \
				} \
			} \
		} \
	} \
}


	switch(input->get_color_model())
	{
		case BC_RGB888:
			DO_BRIGHTNESS(0xff, unsigned char, 3, 0)
			break;

		case BC_RGB_FLOAT:
			DO_BRIGHTNESS_F(3)
			break;

		case BC_YUV888:
			DO_BRIGHTNESS(0xff, unsigned char, 3, 1)
			break;

		case BC_RGBA8888:
			DO_BRIGHTNESS(0xff, unsigned char, 4, 0)
			break;

		case BC_RGBA_FLOAT:
			DO_BRIGHTNESS_F(4)
			break;

		case BC_YUVA8888:
			DO_BRIGHTNESS(0xff, unsigned char, 4, 1)
			break;

		case BC_RGB161616:
			DO_BRIGHTNESS(0xffff, uint16_t, 3, 0)
			break;

		case BC_YUV161616:
			DO_BRIGHTNESS(0xffff, uint16_t, 3, 1)
			break;

		case BC_RGBA16161616:
			DO_BRIGHTNESS(0xffff, uint16_t, 4, 0)
			break;

		case BC_YUVA16161616:
			DO_BRIGHTNESS(0xffff, uint16_t, 4, 1)
			break;
	}









}
Example #22
0
void ThresholdUnit::render_data(LoadPackage *package)
{
	const ThresholdPackage *pkg = (ThresholdPackage*)package;
	const ThresholdConfig *config = & server->plugin->config;
	VFrame *data = server->data;
	const int min = (int)(config->min * 0xffff);
	const int max = (int)(config->max * 0xffff);
	const int w = data->get_w();
	const int h = data->get_h();
	
	const TYPE r_low = scale_to_range<TYPE>(config->low_color.r);
	const TYPE g_low = scale_to_range<TYPE>(config->low_color.g);
	const TYPE b_low = scale_to_range<TYPE>(config->low_color.b);
	const TYPE a_low = scale_to_range<TYPE>(config->low_color.a);
	
	const TYPE r_mid = scale_to_range<TYPE>(config->mid_color.r);
	const TYPE g_mid = scale_to_range<TYPE>(config->mid_color.g);
	const TYPE b_mid = scale_to_range<TYPE>(config->mid_color.b);
	const TYPE a_mid = scale_to_range<TYPE>(config->mid_color.a);
	
	const TYPE r_high = scale_to_range<TYPE>(config->high_color.r);
	const TYPE g_high = scale_to_range<TYPE>(config->high_color.g);
	const TYPE b_high = scale_to_range<TYPE>(config->high_color.b);
	const TYPE a_high = scale_to_range<TYPE>(config->high_color.a);

	TYPE y_low,  u_low,  v_low;
	TYPE y_mid,  u_mid,  v_mid;
	TYPE y_high, u_high, v_high;

	if (USE_YUV)
	{
		rgb_to_yuv(*server->yuv, r_low,  g_low,  b_low,  y_low,  u_low,  v_low);
		rgb_to_yuv(*server->yuv, r_mid,  g_mid,  b_mid,  y_mid,  u_mid,  v_mid);
		rgb_to_yuv(*server->yuv, r_high, g_high, b_high, y_high, u_high, v_high);
	}

	for(int i = pkg->start; i < pkg->end; i++)
	{
		TYPE *in_row = (TYPE*)data->get_rows()[i];
		TYPE *out_row = in_row;
		for(int j = 0; j < w; j++)
		{
			if (USE_YUV)
			{
				const int y = get_component(in_row[0]);
				if (y < min)
				{
					*out_row++ = y_low;
					*out_row++ = u_low;
					*out_row++ = v_low;
					if(COMPONENTS == 4) *out_row++ = a_low;
				}
				else if (y < max)
				{
					*out_row++ = y_mid;
					*out_row++ = u_mid;
					*out_row++ = v_mid;
					if(COMPONENTS == 4) *out_row++ = a_mid;
				}
				else
				{
					*out_row++ = y_high;
					*out_row++ = u_high;
					*out_row++ = v_high;
					if(COMPONENTS == 4) *out_row++ = a_high;
				}
			}
			else
			{
				const int r = get_component(in_row[0]);
				const int g = get_component(in_row[1]);
				const int b = get_component(in_row[2]);
				const int y = (r * 76 + g * 150 + b * 29) >> 8;
				if (y < min)
				{
					*out_row++ = r_low;
					*out_row++ = g_low;
					*out_row++ = b_low;
					if(COMPONENTS == 4) *out_row++ = a_low;
				}
				else if (y < max)
				{
					*out_row++ = r_mid;
					*out_row++ = g_mid;
					*out_row++ = b_mid;
					if(COMPONENTS == 4) *out_row++ = a_mid;
				}
				else
				{
					*out_row++ = r_high;
					*out_row++ = g_high;
					*out_row++ = b_high;
					if(COMPONENTS == 4) *out_row++ = a_high;
				}
			}
			in_row += COMPONENTS;
		}
	}
}
Example #23
0
void HistogramUnit::process_package(LoadPackage *package)
{
	HistogramPackage *pkg = (HistogramPackage*)package;
	HistogramEngine *server = (HistogramEngine*)get_server();


#define HISTOGRAM_HEAD(type) \
{ \
	for(int i = pkg->start; i < pkg->end; i++) \
	{ \
		type *row = (type*)data->get_rows()[i]; \
		for(int j = 0; j < w; j++) \
		{

#define HISTOGRAM_TAIL(components) \
			v = (r * 76 + g * 150 + b * 29) >> 8; \
/*			v = MAX(r, g); */ \
/*			v = MAX(v, b); */ \
			r += -(int)(HISTOGRAM_MIN * 0xffff); \
			g += -(int)(HISTOGRAM_MIN * 0xffff); \
			b += -(int)(HISTOGRAM_MIN * 0xffff); \
			v += -(int)(HISTOGRAM_MIN * 0xffff); \
			CLAMP(r, 0, HISTOGRAM_RANGE); \
			CLAMP(g, 0, HISTOGRAM_RANGE); \
			CLAMP(b, 0, HISTOGRAM_RANGE); \
			CLAMP(v, 0, HISTOGRAM_RANGE); \
			accum_r[r]++; \
			accum_g[g]++; \
			accum_b[b]++; \
			accum_v[v]++; \
/*			if(components == 4) accum_a[row[3]]++; */ \
			row += components; \
		} \
	} \
}



	VFrame *data = server->data;

	int w = data->get_w();
	//int h = data->get_h();
	int64_t *accum_r = accum[HISTOGRAM_RED];
	int64_t *accum_g = accum[HISTOGRAM_GREEN];
	int64_t *accum_b = accum[HISTOGRAM_BLUE];
	//int64_t *accum_a = accum[HISTOGRAM_ALPHA];
	int64_t *accum_v = accum[HISTOGRAM_VALUE];
	int r, g, b, y, u, v; // ,a;

	switch(data->get_color_model())
	{
		case BC_RGB888:
			HISTOGRAM_HEAD(unsigned char)
			r = (row[0] << 8) | row[0];
			g = (row[1] << 8) | row[1];
			b = (row[2] << 8) | row[2];
			HISTOGRAM_TAIL(3)
			break;
		case BC_RGB_FLOAT:
			HISTOGRAM_HEAD(float)
			r = (int)(row[0] * 0xffff);
			g = (int)(row[1] * 0xffff);
			b = (int)(row[2] * 0xffff);
			HISTOGRAM_TAIL(3)
			break;
		case BC_YUV888:
			HISTOGRAM_HEAD(unsigned char)
			y = (row[0] << 8) | row[0];
			u = (row[1] << 8) | row[1];
			v = (row[2] << 8) | row[2];
			server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
			HISTOGRAM_TAIL(3)
			break;
		case BC_RGBA8888:
			HISTOGRAM_HEAD(unsigned char)
			r = (row[0] << 8) | row[0];
			g = (row[1] << 8) | row[1];
			b = (row[2] << 8) | row[2];
			HISTOGRAM_TAIL(4)
			break;
		case BC_RGBA_FLOAT:
			HISTOGRAM_HEAD(float)
			r = (int)(row[0] * 0xffff);
			g = (int)(row[1] * 0xffff);
			b = (int)(row[2] * 0xffff);
			HISTOGRAM_TAIL(4)
			break;
		case BC_YUVA8888:
			HISTOGRAM_HEAD(unsigned char)
			y = (row[0] << 8) | row[0];
			u = (row[1] << 8) | row[1];
			v = (row[2] << 8) | row[2];
			server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
			HISTOGRAM_TAIL(4)
			break;
		case BC_RGB161616:
			HISTOGRAM_HEAD(uint16_t)
			r = row[0];
			g = row[1];
			b = row[2];
			HISTOGRAM_TAIL(3)
			break;
		case BC_YUV161616:
			HISTOGRAM_HEAD(uint16_t)
			y = row[0];
			u = row[1];
			v = row[2];
			server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
			HISTOGRAM_TAIL(3)
			break;
		case BC_RGBA16161616:
			HISTOGRAM_HEAD(uint16_t)
			r = row[0];
			g = row[1];
			b = row[2];
			HISTOGRAM_TAIL(3);
			break;
		case BC_YUVA16161616:
			HISTOGRAM_HEAD(uint16_t)
			y = row[0];
			u = row[1];
			v = row[2];
			server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
			HISTOGRAM_TAIL(4)
			break;
	}
}
Example #24
0
int Overlay::process_buffer(VFrame **frame,
	int64_t start_position,
	double frame_rate)
{
	load_configuration();


printf("Overlay::process_buffer mode=%d\n", config.mode);
	if(!temp) temp = new VFrame(0,
		-1,
		frame[0]->get_w(),
		frame[0]->get_h(),
		frame[0]->get_color_model(),
		-1);

	if(!overlayer)
		overlayer = new OverlayFrame(get_project_smp() + 1);

	int step;
	VFrame *output;

	if(config.direction == OverlayConfig::BOTTOM_FIRST)
	{
		input_layer1 = get_total_buffers() - 1;
		input_layer2 = -1;
		step = -1;
	}
	else
	{
		input_layer1 = 0;
		input_layer2 = get_total_buffers();
		step = 1;
	}

	if(config.output_layer == OverlayConfig::TOP)
	{
		output_layer = 0;
	}
	else
	{
		output_layer = get_total_buffers() - 1;
	}



// Direct copy the first layer
	output = frame[output_layer];
	read_frame(output,
		input_layer1,
		start_position,
		frame_rate,
		get_use_opengl());

	if(get_total_buffers() == 1) return 0;



	current_layer = input_layer1;
	if(get_use_opengl())
		run_opengl();

	for(int i = input_layer1 + step; i != input_layer2; i += step)
	{
		read_frame(temp,
			i,
			start_position,
			frame_rate,
			get_use_opengl());

// Call the opengl handler once for each layer
		if(get_use_opengl())
		{
			current_layer = i;
			run_opengl();
		}
		else
		{
			overlayer->overlay(output,
				temp,
				0,
				0,
				output->get_w(),
				output->get_h(),
				0,
				0,
				output->get_w(),
				output->get_h(),
				1,
				config.mode,
				NEAREST_NEIGHBOR);
		}
	}


	return 0;
}
void ThresholdUnit::process_package(LoadPackage *package)
{
	ThresholdPackage *pkg = (ThresholdPackage*)package;
	VFrame *data = server->data;
	int min = (int)(server->plugin->config.min * 0xffff);
	int max = (int)(server->plugin->config.max * 0xffff);
	int r, g, b, a, y, u, v;
	int w = server->data->get_w();
	int h = server->data->get_h();

#define THRESHOLD_HEAD(type) \
{ \
	for(int i = pkg->start; i < pkg->end; i++) \
	{ \
		type *in_row = (type*)data->get_rows()[i]; \
		type *out_row = in_row; \
		for(int j = 0; j < w; j++) \
		{

#define THRESHOLD_TAIL(components, r_on, g_on, b_on, a_on, r_off, g_off, b_off, a_off) \
			v = (r * 76 + g * 150 + b * 29) >> 8; \
			if(v >= min && v < max) \
			{ \
				*out_row++ = r_on; \
				*out_row++ = g_on; \
				*out_row++ = b_on; \
				if(components == 4) *out_row++ = a_on; \
			} \
			else \
			{ \
				*out_row++ = r_off; \
				*out_row++ = g_off; \
				*out_row++ = b_off; \
				if(components == 4) *out_row++ = a_off; \
			} \
			in_row += components; \
		} \
	} \
}


	switch(data->get_color_model())
	{
		case BC_RGB888:
			THRESHOLD_HEAD(unsigned char)
			r = (in_row[0] << 8) | in_row[0];
			g = (in_row[1] << 8) | in_row[1];
			b = (in_row[2] << 8) | in_row[2];
			THRESHOLD_TAIL(3, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff);
			break;
		case BC_RGB_FLOAT:
			THRESHOLD_HEAD(float)
			r = (int)(in_row[0] * 0xffff);
			g = (int)(in_row[1] * 0xffff);
			b = (int)(in_row[2] * 0xffff);
			THRESHOLD_TAIL(3, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0);
			break;
		case BC_RGBA8888:
			THRESHOLD_HEAD(unsigned char)
			r = (in_row[0] << 8) | in_row[0];
			g = (in_row[1] << 8) | in_row[1];
			b = (in_row[2] << 8) | in_row[2];
			THRESHOLD_TAIL(4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff);
			break;
		case BC_RGBA_FLOAT:
			THRESHOLD_HEAD(float)
			r = (int)(in_row[0] * 0xffff);
			g = (int)(in_row[1] * 0xffff);
			b = (int)(in_row[2] * 0xffff);
			THRESHOLD_TAIL(4, 1.0, 1.0, 1.0, 1.0, 0, 0, 0, 1.0);
			break;
		case BC_YUV888:
			THRESHOLD_HEAD(unsigned char)
			y = (in_row[0] << 8) | in_row[0];
			u = (in_row[1] << 8) | in_row[1];
			v = (in_row[2] << 8) | in_row[2];
			server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
			THRESHOLD_TAIL(3, 0xff, 0x80, 0x80, 0xff, 0x0, 0x80, 0x80, 0xff)
			break;
		case BC_YUVA8888:
			THRESHOLD_HEAD(unsigned char)
			y = (in_row[0] << 8) | in_row[0];
			u = (in_row[1] << 8) | in_row[1];
			v = (in_row[2] << 8) | in_row[2];
			server->yuv->yuv_to_rgb_16(r, g, b, y, u, v);
			THRESHOLD_TAIL(4, 0xff, 0x80, 0x80, 0xff, 0x0, 0x80, 0x80, 0xff)
			break;
	}
}