int cAudio::Start(void)
{
	lt_debug("%s >\n", __func__);
	if (! HAL_nodec)
		Thread::startThread();
	lt_debug("%s <\n", __func__);
	return 0;
}
int cVideo::Start(void *, unsigned short, unsigned short, void *)
{
	lt_debug("%s running %d >\n", __func__, thread_running);
	if (!thread_running && !HAL_nodec)
		Thread::startThread();
	lt_debug("%s running %d <\n", __func__, thread_running);
	return 0;
}
int cVideo::Stop(bool)
{
	lt_debug("%s running %d >\n", __func__, thread_running);
	if (thread_running) {
		thread_running = false;
		Thread::joinThread();
	}
	lt_debug("%s running %d <\n", __func__, thread_running);
	return 0;
}
int cAudio::Stop(void)
{
	lt_debug("%s >\n", __func__);
	if (thread_started)
	{
		thread_started = false;
		Thread::joinThread();
	}
	lt_debug("%s <\n", __func__);
	return 0;
}
int cAudio::PrepareClipPlay(int ch, int srate, int bits, int le)
{
	lt_debug("%s ch %d srate %d bits %d le %d adevice %p\n", __func__, ch, srate, bits, le, adevice);;
	int driver;
	int byte_format = le ? AO_FMT_LITTLE : AO_FMT_BIG;
	if (sformat.bits != bits || sformat.channels != ch || sformat.rate != srate ||
	    sformat.byte_format != byte_format || adevice == NULL)
	{
		driver = ao_default_driver_id();
		sformat.bits = bits;
		sformat.channels = ch;
		sformat.rate = srate;
		sformat.byte_format = byte_format;
		sformat.matrix = 0;
		if (adevice)
			ao_close(adevice);
		adevice = ao_open_live(driver, &sformat, NULL);
		ao_info *ai = ao_driver_info(driver);
		lt_info("%s: changed params ch %d srate %d bits %d le %d adevice %p\n",
			__func__, ch, srate, bits, le, adevice);;
		lt_info("libao driver: %d name '%s' short '%s' author '%s'\n",
				driver, ai->name, ai->short_name, ai->author);
	}
	return 0;
};
Exemple #6
0
void cVideo::routeVideo(int standby)
{
	lt_debug("%s(%d)\n", __FUNCTION__, standby);

	int avsfd = open("/dev/stb/tdsystem", O_RDONLY);
	if (avsfd < 0)
	{
		perror("open tdsystem");
		return;
	}

	/* in standby, we always route VCR scart to the TV. Once there is a UI
	   to configure this, we can think more about this... */
	if (standby)
	{
		lt_info("%s set fastblank and pin8 to follow VCR SCART, route VCR to TV\n", __FUNCTION__);
		if (ioctl(avsfd, IOC_AVS_FASTBLANK_SET, (unsigned char)3) < 0)
			perror("IOC_AVS_FASTBLANK_SET, 3");
		/* TODO: should probably depend on aspect ratio setting */
		if (ioctl(avsfd, IOC_AVS_SCART_PIN8_FOLLOW_VCR) < 0)
			perror("IOC_AVS_SCART_PIN8_FOLLOW_VCR");
		if (ioctl(avsfd, IOC_AVS_ROUTE_VCR2TV) < 0)
			perror("IOC_AVS_ROUTE_VCR2TV");
	} else {
		unsigned char fblk = 1;
		lt_info("%s set fastblank=%d pin8=%dV, route encoder to TV\n", __FUNCTION__, fblk, scartvoltage);
		if (ioctl(avsfd, IOC_AVS_FASTBLANK_SET, fblk) < 0)
			perror("IOC_AVS_FASTBLANK_SET, fblk");
		if (!noscart && ioctl(avsfd, IOC_AVS_SCART_PIN8_SET, scartvoltage) < 0)
			perror("IOC_AVS_SCART_PIN8_SET");
		if (ioctl(avsfd, IOC_AVS_ROUTE_ENC2TV) < 0)
			perror("IOC_AVS_ROUTE_ENC2TV");
	}
	close(avsfd);
}
int cAudio::do_mute(bool enable, bool remember)
{
	lt_debug("%s(%d, %d)\n", __FUNCTION__, enable, remember);
	int avsfd;
	int ret;
	if (remember)
		Muted = enable;
	ret = ioctl(fd, MPEG_AUD_SET_MUTE, enable);
	if (ret < 0)
		lt_info("%s(%d) failed (%m)\n", __FUNCTION__, (int)enable);

	/* are we using alternative DSP / mixer? */
	if (clipfd != -1 || mixer_fd != -1)
		setVolume(volume,volume); /* considers "Muted" variable, "remember"
					     is basically always true in this context */
	avsfd = open("/dev/stb/tdsystem", O_RDONLY);
	if (avsfd >= 0)
	{
		if (enable)
			ioctl(avsfd, IOC_AVS_SET_VOLUME, 31);
		else
			ioctl(avsfd, IOC_AVS_SET_VOLUME, 0);
		close(avsfd);
	}
	return ret;
}
int cAudio::WriteClip(unsigned char *buffer, int size)
{
	lt_debug("cAudio::%s buf 0x%p size %d\n", __func__, buffer, size);
	if (!adevice) {
		lt_info("%s: adevice not opened?\n", __func__);
		return 0;
	}
	ao_play(adevice, (char *)buffer, size);
	return size;
};
Exemple #9
0
int cVideo::Start(void * /*PcrChannel*/, unsigned short /*PcrPid*/, unsigned short /*VideoPid*/, void * /*hChannel*/)
{
	lt_debug("%s playstate=%d\n", __FUNCTION__, playstate);
	if (playstate == VIDEO_PLAYING)
		return 0;
	if (playstate == VIDEO_FREEZED)  /* in theory better, but not in practice :-) */
		fop(ioctl, MPEG_VID_CONTINUE);
	playstate = VIDEO_PLAYING;
	fop(ioctl, MPEG_VID_PLAY);
	return fop(ioctl, MPEG_VID_SYNC_ON, VID_SYNC_AUD);
}
Exemple #10
0
int cVideo::Stop(bool blank)
{
	lt_debug("%s(%d)\n", __FUNCTION__, blank);
	if (blank)
	{
		playstate = VIDEO_STOPPED;
		fop(ioctl, MPEG_VID_STOP);
		return setBlank(1);
	}
	playstate = VIDEO_FREEZED;
	return fop(ioctl, MPEG_VID_FREEZE);
}
Exemple #11
0
void cVideo::Standby(unsigned int bOn)
{
	lt_debug("%s(%d)\n", __FUNCTION__, bOn);
	if (bOn)
	{
		setBlank(1);
		fop(ioctl, MPEG_VID_SET_OUTFMT, VID_OUTFMT_DISABLE_DACS);
	} else
		fop(ioctl, MPEG_VID_SET_OUTFMT, outputformat);
	routeVideo(bOn);
	video_standby = bOn;
}
Exemple #12
0
int cVideo::setCroppingMode(vidDispMode_t format)
{
	croppingMode = format;
	const char *format_string[] = { "norm", "letterbox", "unknown", "mode_1_2", "mode_1_4", "mode_2x", "scale", "disexp" };
	const char *f;
	if (format >= VID_DISPMODE_NORM && format <= VID_DISPMODE_DISEXP)
		f = format_string[format];
	else
		f = "ILLEGAL format!";
	lt_debug("%s(%d) => %s\n", __FUNCTION__, format, f);
	return fop(ioctl, MPEG_VID_SET_DISPMODE, format);
}
Exemple #13
0
int cVideo::SetStreamType(VIDEO_FORMAT type)
{
	static const char *VF[] = {
		"VIDEO_FORMAT_MPEG2",
		"VIDEO_FORMAT_MPEG4",
		"VIDEO_FORMAT_VC1",
		"VIDEO_FORMAT_JPEG",
		"VIDEO_FORMAT_GIF",
		"VIDEO_FORMAT_PNG"
	};

	lt_debug("%s type=%s\n", __FUNCTION__, VF[type]);
	return 0;
}
Exemple #14
0
/* this function is regularly called, checks if video parameters
   changed and triggers appropriate actions */
void cVideo::VideoParamWatchdog(void)
{
	static unsigned int _v_info = (unsigned int) -1;
	unsigned int v_info;
	if (fd == -1)
		return;
	ioctl(fd, MPEG_VID_GET_V_INFO_RAW, &v_info);
	if (_v_info != v_info)
	{
		lt_debug("%s params changed. old: %08x new: %08x\n", __FUNCTION__, _v_info, v_info);
		setAspectRatio(-1, -1);
	}
	_v_info = v_info;
}
bool cCpuFreqManager::SetCpuFreq(unsigned long f)
{
#if HAVE_SPARK_HARDWARE || HAVE_DUCKBOX_HARDWARE
	if (f) {
		FILE *pll0 = fopen ("/proc/cpu_frequ/pll0_ndiv_mdiv", "w");
		if (pll0) {
			f /= 1000000;
			fprintf(pll0, "%lu\n", (f/10 << 8) | 3);
			fclose (pll0);
			return false;
		}
	}
#else
	/* actually SetCpuFreq is used to determine if the system is in standby
	   this is an "elegant" hack, because:
	   * during a recording, cpu freq is kept "high", even if the box is sent to standby
	   * the "SetStandby" call is made even if a recording is running
	   On the TD, setting standby disables the frontend, so we must not do it
	   if a recording is running.
	   For now, the values in neutrino are hardcoded:
	   * f == 0        => max => not standby
	   * f == 50000000 => min => standby
	 */
	lt_debug("%s(%lu) => set standby = %s\n", __FUNCTION__, f, f?"true":"false");
#if 0
	int fd = open("/dev/stb/tdsystem", O_RDONLY);
	if (fd < 0)
	{
		perror("open tdsystem");
		return false;
	}
	if (f)
	{
		ioctl(fd, IOC_AVS_SET_VOLUME, 31); /* mute AVS to avoid ugly noise */
		ioctl(fd, IOC_AVS_STANDBY_ENTER);
	}
	else
	{
		ioctl(fd, IOC_AVS_SET_VOLUME, 31); /* mute AVS to avoid ugly noise */
		ioctl(fd, IOC_AVS_STANDBY_LEAVE);
		/* unmute will be done by cAudio::do_mute(). Ugly, but prevents pops */
		// ioctl(fd, IOC_AVS_SET_VOLUME, 0); /* max gain */
	}

	close(fd);
#endif
#endif
	return true;
}
int cAudio::StopClip()
{
	lt_debug("%s\n", __func__);
#if 0
	/* don't do anything - closing / reopening ao all the time makes for long delays
	 * reinit on-demand (e.g. for changed parameters) instead */
	if (!adevice) {
		lt_info("%s: adevice not opened?\n", __func__);
		return 0;
	}
	ao_close(adevice);
	adevice = NULL;
#endif
	return 0;
};
Exemple #17
0
/*
 * runs the rmfp_player in a terminal
 * just doing popen() or similar does not work because then
 * the output will be buffered after starting up and we will only
 * see "Playback has started..." after the player exits
 */
void PBPrivate::run_rmfp()
{
	lt_debug("%s: starting\n", __func__);
	thread_started = true;
	//Watch for the space at the end
	std::string base = "rmfp_player -dram 1 -ve 1 -waitexit ";
	std::string filename(fname);
	std::string file = '"' + filename + '"';
	std::string final = base + file;

	if (pmode == PLAYMODE_TS && duration != 0)
	{
		std::stringstream du;
		du << (duration /** 60000LL*/);
		final = base + "-duration " + du.str() + " " + file;
Exemple #18
0
cVideo::cVideo(int, void *, void *)
{
	lt_debug("%s\n", __FUNCTION__);
	if ((fd = open(VIDEO_DEVICE, O_RDWR)) < 0)
		lt_info("%s cannot open %s: %m\n", __FUNCTION__, VIDEO_DEVICE);
	fcntl(fd, F_SETFD, FD_CLOEXEC);

	playstate = VIDEO_STOPPED;
	croppingMode = VID_DISPMODE_NORM;
	outputformat = VID_OUTFMT_RGBC_SVIDEO;
	scartvoltage = -1;
	z[0] = 100;
	z[1] = 100;
	zoomvalue = &z[0];
	const char *blanknames[2] = { "/share/tuxbox/blank_576.mpg", "/share/tuxbox/blank_480.mpg" };
	int blankfd;
	struct stat st;

	for (int i = 0; i < 2; i++)
	{
		blank_data[i] = NULL; /* initialize */
		blank_size[i] = 0;
		blankfd = open(blanknames[i], O_RDONLY);
		if (blankfd < 0)
		{
			lt_info("%s cannot open %s: %m", __FUNCTION__, blanknames[i]);
			continue;
		}
		if (fstat(blankfd, &st) != -1 && st.st_size > 0)
		{
			blank_size[i] = st.st_size;
			blank_data[i] = malloc(blank_size[i]);
			if (! blank_data[i])
				lt_info("%s malloc failed (%m)\n", __FUNCTION__);
			else if (read(blankfd, blank_data[i], blank_size[i]) != blank_size[i])
			{
				lt_info("%s short read (%m)\n", __FUNCTION__);
				free(blank_data[i]); /* don't leak... */
				blank_data[i] = NULL;
			}
		}
		close(blankfd);
	}
	video_standby = 0;
	noscart = (getenv("TRIPLE_NOSCART") != NULL);
	if (noscart)
		lt_info("%s TRIPLE_NOSCART variable prevents SCART switching\n", __FUNCTION__);
}
Exemple #19
0
int cVideo::setBlank(int)
{
	lt_debug("%s\n", __FUNCTION__);
	/* The TripleDragon has no VIDEO_SET_BLANK ioctl.
	   instead, you write a black still-MPEG Iframe into the decoder.
	   The original software uses different files for 4:3 and 16:9 and
	   for PAL and NTSC. I optimized that a little bit
	 */
	int index = 0; /* default PAL */
	int ret = 0;
	VIDEOINFO v;
	BUFINFO buf;
	pthread_mutex_lock(&stillp_mutex);
	memset(&v, 0, sizeof(v));
	ioctl(fd, MPEG_VID_GET_V_INFO, &v);

	if ((v.v_size % 240) == 0) /* NTSC */
	{
		lt_info("%s NTSC format detected", __FUNCTION__);
		index = 1;
	}

	if (blank_data[index] == NULL) /* no MPEG found */
	{
		ret = -1;
		goto out;
	}
	/* hack: this might work only on those two still-MPEG files!
	   I diff'ed the 4:3 and the 16:9 still mpeg from the original
	   soft and spotted the single bit difference, so there is no
	   need to keep two different MPEGs in memory
	   If we would read them from disk all the time it would be
	   slower and it might wake up the drive occasionally */
	if (v.pel_aspect_ratio == VID_DISPSIZE_4x3)
		((char *)blank_data[index])[7] &= ~0x10; // clear the bit
	else
		((char *)blank_data[index])[7] |=  0x10; // set the bit

	//WARN("blank[7] == 0x%02x", ((char *)blank_data[index])[7]);

	buf.ulLen = blank_size[index];
	buf.ulStartAdrOff = (int)blank_data[index];
	fop(ioctl, MPEG_VID_STILLP_WRITE, &buf);
	ret = fop(ioctl, MPEG_VID_SELECT_SOURCE, VID_SOURCE_DEMUX);
 out:
	pthread_mutex_unlock(&stillp_mutex);
	return ret;
}
void cAudio::getAudioInfo(int &type, int &layer, int &freq, int &bitrate, int &mode)
{
	type = 0;
	layer = 0;	/* not used */
	freq = 0;
	bitrate = 0;	/* not used, but easy to get :-) */
	mode = 0;	/* default: stereo */
	if (c) {
		type = (c->codec_id != AV_CODEC_ID_MP2); /* only mpeg / not mpeg is indicated */
		freq = c->sample_rate;
		bitrate = c->bit_rate;
		if (c->channels == 1)
			mode = 3; /* for AV_CODEC_ID_MP2, only stereo / mono is detected for now */
		if (c->codec_id != AV_CODEC_ID_MP2) {
			switch (c->channel_layout) {
				case AV_CH_LAYOUT_MONO:
					mode = 1;	// "C"
					break;
				case AV_CH_LAYOUT_STEREO:
					mode = 2;	// "L/R"
					break;
				case AV_CH_LAYOUT_2_1:
				case AV_CH_LAYOUT_SURROUND:
					mode = 3;	// "L/C/R"
					break;
				case AV_CH_LAYOUT_2POINT1:
					mode = 4;	// "L/R/S"
					break;
				case AV_CH_LAYOUT_3POINT1:
					mode = 5;	// "L/C/R/S"
					break;
				case AV_CH_LAYOUT_2_2:
				case AV_CH_LAYOUT_QUAD:
					mode = 6;	// "L/R/SL/SR"
					break;
				case AV_CH_LAYOUT_5POINT0:
				case AV_CH_LAYOUT_5POINT1:
					mode = 7;	// "L/C/R/SL/SR"
					break;
				default:
					lt_info("%s: unknown ch_layout 0x%" PRIx64 "\n",
						 __func__, c->channel_layout);
			}
		}
	}
	lt_debug("%s t: %d l: %d f: %d b: %d m: %d codec_id: %x\n",
		  __func__, type, layer, freq, bitrate, mode, c->codec_id);
};
Exemple #21
0
void cVideo::SetVideoMode(analog_mode_t mode)
{
	lt_debug("%s(%d)\n", __FUNCTION__, mode);
	switch(mode)
	{
		case ANALOG_SD_YPRPB_SCART:
			outputformat = VID_OUTFMT_YBR_SVIDEO;
			break;
		case ANALOG_SD_RGB_SCART:
			outputformat = VID_OUTFMT_RGBC_SVIDEO;
			break;
		default:
			lt_info("%s unknown mode %d\n", __FUNCTION__, mode);
			return;
	}
	fop(ioctl, MPEG_VID_SET_OUTFMT, outputformat);
}
bool cCpuFreqManager::SetCpuFreq(unsigned long f)
{
	/* actually SetCpuFreq is used to determine if the system is in standby
	   this is an "elegant" hack, because:
	   * during a recording, cpu freq is kept "high", even if the box is sent to standby
	   * the "SetStandby" call is made even if a recording is running
	   On the TD, setting standby disables the frontend, so we must not do it
	   if a recording is running.
	   For now, the values in neutrino are hardcoded:
	   * f == 0        => max => not standby
	   * f == 50000000 => min => standby
	 */
	lt_debug("%s(%lu) => set standby = %s\n", __FUNCTION__, f, f?"true":"false");
	int fd = open("/dev/stb/tdsystem", O_RDONLY);
	if (fd < 0)
	{
		perror("open tdsystem");
		return false;
	}
	if (f)
	{
		ioctl(fd, IOC_AVS_SET_VOLUME, 31); /* mute AVS to avoid ugly noise */
		ioctl(fd, IOC_AVS_STANDBY_ENTER);
		if (getenv("TRIPLE_LCDBACKLIGHT"))
		{
			lt_info("%s: TRIPLE_LCDBACKLIGHT is set: keeping LCD backlight on\n", __func__);
			close(fd);
			fd = open("/dev/stb/tdlcd", O_RDONLY);
			if (fd < 0)
				lt_info("%s: open tdlcd error: %m\n", __func__);
			else
				ioctl(fd, IOC_LCD_BACKLIGHT_ON);
		}
	}
	else
	{
		ioctl(fd, IOC_AVS_SET_VOLUME, 31); /* mute AVS to avoid ugly noise */
		ioctl(fd, IOC_AVS_STANDBY_LEAVE);
		/* unmute will be done by cAudio::do_mute(). Ugly, but prevents pops */
		// ioctl(fd, IOC_AVS_SET_VOLUME, 0); /* max gain */
	}

	close(fd);
	return true;
}
cVideo::cVideo(int, void *, void *, unsigned int)
{
	lt_debug("%s\n", __func__);
	av_register_all();
	if (!HAL_nodec)
		dmxbuf = (uint8_t *)malloc(DMX_BUF_SZ);
	bufpos = 0;
	thread_running = false;
	w_h_changed = false;
	dec_w = dec_h = 0;
	buf_num = 0;
	buf_in = 0;
	buf_out = 0;
	pig_x = pig_y = pig_w = pig_h = 0;
	display_aspect = DISPLAY_AR_16_9;
	display_crop = DISPLAY_AR_MODE_LETTERBOX;
	v_format = VIDEO_FORMAT_MPEG2;
}
Exemple #24
0
void cVideo::SetSyncMode(AVSYNC_TYPE Mode)
{
	lt_debug("%s %d\n", __FUNCTION__, Mode);
	/*
	 * { 0, LOCALE_OPTIONS_OFF },
	 * { 1, LOCALE_OPTIONS_ON  },
	 * { 2, LOCALE_AUDIOMENU_AVSYNC_AM }
	 */
	switch(Mode)
	{
		case 0:
			ioctl(fd, MPEG_VID_SYNC_OFF);
			break;
		case 1:
			ioctl(fd, MPEG_VID_SYNC_ON, VID_SYNC_VID);
			break;
		default:
			ioctl(fd, MPEG_VID_SYNC_ON, VID_SYNC_AUD);
			break;
	}
};
static lt_ext_module_t *
lt_ext_module_new_with_data(const char                  *name,
			    const lt_ext_module_funcs_t *funcs)
{
	lt_ext_module_t *retval;

	lt_return_val_if_fail (name != NULL, NULL);
	lt_return_val_if_fail (funcs != NULL, NULL);

	retval = lt_mem_alloc_object(sizeof (lt_ext_module_t));
	if (retval) {
		retval->name = strdup(name);
		lt_mem_add_ref(&retval->parent, retval->name,
			       (lt_destroy_func_t)free);
		retval->funcs = funcs;

		lt_debug(LT_MSGCAT_MODULE, "Loading the internal extension handler: %s", name);
	}

	return retval;
}
Exemple #26
0
void cVideo::Pig(int x, int y, int w, int h, int /*osd_w*/, int /*osd_h*/)
{
	/* x = y = w = h = -1 -> reset / "hide" PIG */
	if (x == -1 && y == -1 && w == -1 && h == -1)
	{
		setZoom(-1);
		setAspectRatio(-1, -1);
		return;
	}
	SCALEINFO s;
	memset(&s, 0, sizeof(s));
	s.src.hori_size = 720;
	s.src.vert_size = 576;
	s.des.hori_off = x;
	s.des.vert_off = y;
	s.des.hori_size = w;
	s.des.vert_size = h;
	lt_debug("%s src: %d:%d:%d:%d dst: %d:%d:%d:%d", __FUNCTION__,
		s.src.hori_off,s.src.vert_off,s.src.hori_size,s.src.vert_size,
		s.des.hori_off,s.des.vert_off,s.des.hori_size,s.des.vert_size);
	fop(ioctl, MPEG_VID_SET_DISPMODE, VID_DISPMODE_SCALE);
	fop(ioctl, MPEG_VID_SCALE_ON);
	fop(ioctl, MPEG_VID_SET_SCALE_POS, &s);
}
Exemple #27
0
int cVideo::getBlank(void)
{
	lt_debug("%s\n", __FUNCTION__);
	return 0;
}
Exemple #28
0
void cVideo::FastForwardMode(int mode)
{
	lt_debug("%s\n", __FUNCTION__);
	fop(ioctl, MPEG_VID_FASTFORWARD, mode);
}
Exemple #29
0
void cVideo::StopPicture()
{
	lt_debug("%s\n", __FUNCTION__);
	fop(ioctl, MPEG_VID_SELECT_SOURCE, VID_SOURCE_DEMUX);
}
Exemple #30
0
/* set zoom in percent (100% == 1:1) */
int cVideo::setZoom(int zoom)
{
	if (zoom == -1) // "auto" reset
		zoom = *zoomvalue;

	if (zoom > 150 || zoom < 100)
		return -1;

	*zoomvalue = zoom;

	if (zoom == 100)
	{
		setCroppingMode(croppingMode);
		return fop(ioctl, MPEG_VID_SCALE_OFF);
	}

	/* the SCALEINFO describes the source and destination of the scaled
	   video. "src" is the part of the source picture that gets scaled,
	   "dst" is the area on the screen where this part is displayed
	   Messing around with MPEG_VID_SET_SCALE_POS disables the automatic
	   letterboxing, which, as I guess, is only a special case of
	   MPEG_VID_SET_SCALE_POS. Therefor we need to care for letterboxing
	   etc here, which is probably not yet totally correct */
	SCALEINFO s;
	memset(&s, 0, sizeof(s));
	if (zoom > 100)
	{
		/* 1 = 4:3, 3 = 16:9, 4 = 2.21:1, 0 = unknown */
		int x = getAspectRatio();
		if (x < 3 && croppingMode == VID_DISPMODE_NORM)
		{
			s.src.hori_size = 720;
			s.des.hori_size = 720 * 3/4 * zoom / 100;
			if (s.des.hori_size > 720)
			{
				/* the destination exceeds the screen size.
				   TODO: decrease source size to allow higher
				   zoom factors (is this useful ?) */
				s.des.hori_size = 720;
				zoom = 133; // (720*4*100)/(720*3)
				*zoomvalue = zoom;
			}
		}
		else
		{
			s.src.hori_size = 2 * 720 - 720 * zoom / 100;
			s.des.hori_size = 720;
		}
		s.src.vert_size = 2 * 576 - 576 * zoom / 100;
		s.des.hori_off = (720 - s.des.hori_size) / 2;
		s.des.vert_size = 576;
	}
/* not working correctly (wrong formula) and does not make sense IMHO
	else
	{
		s.src.hori_size = 720;
		s.src.vert_size = 576;
		s.des.hori_size = 720 * zoom / 100;
		s.des.vert_size = 576 * zoom / 100;
		s.des.hori_off = (720 - s.des.hori_size) / 2;
		s.des.vert_off = (576 - s.des.vert_size) / 2;
	}
 */
	lt_debug("%s %d%% src: %d:%d:%d:%d dst: %d:%d:%d:%d\n", __FUNCTION__, zoom,
		s.src.hori_off,s.src.vert_off,s.src.hori_size,s.src.vert_size,
		s.des.hori_off,s.des.vert_off,s.des.hori_size,s.des.vert_size);
	fop(ioctl, MPEG_VID_SET_DISPMODE, VID_DISPMODE_SCALE);
	fop(ioctl, MPEG_VID_SCALE_ON);
	return fop(ioctl, MPEG_VID_SET_SCALE_POS, &s);
}