https://bitbucket.org/hudson/magic-lantern
Revision 98a8c30f2908ff35c09e6d5ecc28776dcec4eb92 authored by hudson@kremvax on 02 August 2009, 18:57:17 UTC, committed by hudson@kremvax on 02 August 2009, 18:57:17 UTC
1 parent ce55a35
Raw File
Tip revision: 98a8c30f2908ff35c09e6d5ecc28776dcec4eb92 authored by hudson@kremvax on 02 August 2009, 18:57:17 UTC
Only get debug events of type 0x0 and 0x8
Tip revision: 98a8c30
zebra.c
/** \file
 * Zebra stripes, contrast edge detection and crop marks.
 *
 */
/*
 * Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.net>
 * Edge detection code by Robert Thiel <rthiel@gmail.com>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 */

#include "dryos.h"
#include "bmp.h"
#include "version.h"
#include "config.h"
#include "menu.h"
#include "property.h"


static unsigned zebra_level = 0xF000;
static unsigned zebra_draw = 1;
static unsigned crop_draw = 1;
static unsigned edge_draw = 0;
static struct bmp_file_t * cropmarks;
static volatile unsigned lv_drawn = 0;
static volatile unsigned sensor_cleaning = 1;



/** Sobel edge detection */
static int32_t
edge_detect(
	uint32_t *		buf,
	uint32_t		pitch
)
{	
	const uint32_t		pixel1	= buf[0];
	const int32_t		p00	= (pixel1 & 0xFFFF);
	const int32_t		p01	= pixel1 >> 16;
	const uint32_t		pixel2	= buf[1];
	const int32_t		p02	= (pixel2 & 0xFFFF);
	const uint32_t		pixel3	= buf[pitch];
	const int32_t		p10	= (pixel3 & 0xFFFF);
	const int32_t		p11	= pixel3 >> 16;
	const uint32_t		pixel4	= buf[pitch+1];
	const int32_t		p12	= (pixel4 & 0xFFFF);
	
	int32_t sx1 = p00 - p11;
	int32_t sy1 = p01 - p10;
	
	int32_t sx2 = p01 - p12;
	int32_t sy2 = p02 - p11;

	// abs value
	sx1 = ( sx1 ^ (sx1 >> 15) ) - (sx1 >> 15);
	sy1 = ( sy1 ^ (sy1 >> 15) ) - (sy1 >> 15);
	
	sx2 = ( sx2 ^ (sx2 >> 15) ) - (sx2 >> 15);
	sy2 = ( sy2 ^ (sy2 >> 15) ) - (sy2 >> 15);
	
	return (((sx2 + sy2) >> 1 ) & 0xFF00 ) | ((sx1 + sy1) >> 9);
}


static unsigned
check_edge(
	unsigned		x,
	unsigned		y,
	uint16_t *		b_row,
	uint32_t *		v_row,
	unsigned		vram_pitch
)
{
	const unsigned dx = x/2;
	// Check for contrast
	uint32_t grad = edge_detect(
		&v_row[dx],
		vram_pitch
	);
	
	// Check for any high gradients in either pixel
	if( (grad & 0xF8F8) == 0 )
		return 0;

	// Color coding (using the blue colors starting at 0x70)
	b_row[dx] = 0x7070 | ((grad & 0xF8F8) >> 3) ;			
	return 1;
	
}


static unsigned
check_zebra(
	unsigned		x,
	unsigned		y,
	uint16_t *		b_row,
	uint32_t *		v_row,
	unsigned		vram_pitch
)
{
	const uint8_t zebra_color_0 = COLOR_BG; // 0x6F; // bright read
	const uint8_t zebra_color_1 = 0x5F; // dark red

	uint32_t pixel = v_row[x/2];
	uint32_t p0 = (pixel >> 16) & 0xFFFF;
	uint32_t p1 = (pixel >>  0) & 0xFFFF;

	// If neither pixel is overexposed, ignore it
	if( p0 < zebra_level && p1 < zebra_level )
		return 0;

	// Determine if we are a zig or a zag line
	uint32_t zag = ((y >> 3) ^ (x >> 3)) & 1;

	// Build the 16-bit word to write both pixels
	// simultaneously into the BMP VRAM
	uint16_t zebra_color_word = zag
		? (zebra_color_0<<8) | (zebra_color_0<<0)
		: (zebra_color_1<<8) | (zebra_color_1<<0);

	b_row[x/2] = zebra_color_word;
	return 1;
}


static unsigned
check_crop(
	unsigned		x,
	unsigned		y,
	uint16_t *		b_row,
	uint32_t *		v_row,
	unsigned		vram_pitch
)
{
	if( !cropmarks )
		return 0;

	uint8_t * pixbuf = &cropmarks->image[
		x + cropmarks->width * (cropmarks->height - y)
	];
	uint16_t pix = *(uint16_t*) pixbuf;
	if( pix == 0 )
		return 0;

	b_row[ x/2 ] = pix;
	return 1;
}


static void
draw_zebra( void )
{
	uint8_t * const bvram = bmp_vram();

	// If we don't have a bitmap vram yet, nothing to do.
	if( !bvram )
		return;

	// If we are not drawing edges, or zebras or crops, nothing to do
	if( !edge_draw && !zebra_draw )
	{
		if( !crop_draw )
			return;
		if( !cropmarks )
			return;
	}

	struct vram_info * vram = &vram_info[ vram_get_number(2) ];

	uint32_t x,y;


	// skip the audio meter at the top and the bar at the bottom
	// hardcoded; should use a constant based on the type of display
	// 33 is the bottom of the meters; 55 is the crop mark
	for( y=33 ; y < 390; y++ )
	{
		uint32_t * const v_row = (uint32_t*)( vram->vram + y * vram->pitch );
		uint16_t * const b_row = (uint16_t*)( bvram + y * bmp_pitch() );

		for( x=2 ; x < vram->width-2 ; x+=2 )
		{
			if( crop_draw && check_crop( x, y, b_row, v_row, vram->pitch ) )
				continue;

			if( edge_draw && check_edge( x, y, b_row, v_row, vram->pitch ) )
				continue;

			if( zebra_draw && check_zebra( x, y, b_row, v_row, vram->pitch ) )
				continue;

			// Nobody drew on it, make it clear
			b_row[x/2] = 0;
		}
	}
}


static void
zebra_toggle( void * priv )
{
	unsigned * ptr = priv;
	*ptr = (*ptr + 0x4000) & 0xF000;
}


static void
zebra_display( void * priv, int x, int y, int selected )
{
	bmp_printf( 
		selected ? MENU_FONT_SEL : MENU_FONT,
		x, y,
		//23456789012
		"Zebra thrs: 0x%04x",
		*(unsigned*) priv
	);
}

static void
zebra_draw_display( void * priv, int x, int y, int selected )
{
	bmp_printf(
		selected ? MENU_FONT_SEL : MENU_FONT,
		x, y,
		//23456789012
		"Zebras:     %s",
		*(unsigned*) priv ? "ON " : "OFF"
	);
}

static void
crop_display( void * priv, int x, int y, int selected )
{
	bmp_printf(
		selected ? MENU_FONT_SEL : MENU_FONT,
		x, y,
		//23456789012
		"Cropmarks:  %s",
		cropmarks ? (*(unsigned*) priv ? "ON " : "OFF") : "NO FILE"
	);
}

static void
edge_display( void * priv, int x, int y, int selected )
{
	bmp_printf(
		selected ? MENU_FONT_SEL : MENU_FONT,
		x, y,
		//23456789012
		"Edgedetect: %s",
		*(unsigned*) priv ? "ON " : "OFF"
	);
}


struct menu_entry zebra_menus[] = {
	{
		.priv		= &zebra_draw,
		.select		= menu_binary_toggle,
		.display	= zebra_draw_display,
	},
	{
		.priv		= &zebra_level,
		.select		= zebra_toggle,
		.display	= zebra_display,
	},
	{
		.priv		= &crop_draw,
		.select		= menu_binary_toggle,
		.display	= crop_display,
	},
	{
		.priv		= &edge_draw,
		.select		= menu_binary_toggle,
		.display	= edge_display,
	},
};

static void * lv_token;
static void
lv_token_handler(
	void *			token
)
{
	lv_token = token;
}


static void
lv_prop_handler(
	unsigned		property,
	void *			priv,
	unsigned *		addr,
	unsigned		len
)
{
	const unsigned value = *addr;
	switch( property )
	{
	case PROP_LV_ACTION:
		// LV_START==0, LV_STOP=1
		lv_drawn = !value;
		break;
	case PROP_GUI_STATE:
		// PLAYMENU==0, IDLE==1
		lv_drawn = !value;
		break;
	case PROP_ACTIVE_SWEEP_STATUS:
		// Let us know when the sensor is done cleaning
		sensor_cleaning = value;
		break;
	default:
		break;
	}

	prop_cleanup( lv_token, property );
}


static void
zebra_task( void )
{
	static unsigned properties[] = {
		PROP_LV_ACTION,
		PROP_GUI_STATE,
		PROP_ACTIVE_SWEEP_STATUS,
	};

	prop_register_slave(
		properties,
		COUNT(properties),
		lv_prop_handler,
		0,
		lv_token_handler
	);


	lv_drawn = 0;
	zebra_draw = config_int( global_config, "zebra.draw", 1 );
	zebra_level = config_int( global_config, "zebra.level", 0xF000 );
	crop_draw = config_int( global_config, "crop.draw", 1 );
	edge_draw = config_int( global_config, "edge.draw", 0 );

	int enable_liveview = config_int( global_config, "enable-liveview", 1 );

	cropmarks = bmp_load( "A:/cropmarks.bmp" );

	DebugMsg( DM_MAGIC, 3,
		"%s: Zebras=%s threshold=%x cropmarks=%x liveview=%d",
		__func__,
		zebra_draw ? "ON " : "OFF",
		zebra_level,
		(unsigned) cropmarks,
		enable_liveview
	);

	if( cropmarks )
	{
		DebugMsg( DM_MAGIC, 3,
			"Cropmarks: %dx%d @ %d",
			cropmarks->width,
			cropmarks->height,
			cropmarks->bits_per_pixel
		);
	}

	if( enable_liveview )
	{
/*
		DebugMsg( DM_MAGIC, 3, "Waiting for sweep status to end" );
		while( sensor_cleaning )
			msleep(100);
*/
		DebugMsg( DM_MAGIC, 3, "Entering liveview" );
		call( "FA_StartLiveView" );
	}


	menu_add( "Video", zebra_menus, COUNT(zebra_menus) );

	while(1)
	{
		if( !gui_show_menu && lv_drawn )
		{
			draw_zebra();
			msleep( 100 );
		} else {
			// Don't display the zebras over the menu.
			// wait a while and then try again
			msleep( 500 );
		}
	}
}


TASK_CREATE( "zebra_task", zebra_task, 0, 0x1f, 0x1000 );
back to top