Blame synfig-core/src/modules/mod_yuv420p/trgt_yuv.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file trgt_yuv.cpp
Carlos Lopez a09598
**	\brief Template File
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007 Chris Moore
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
*/
Carlos Lopez a09598
/* ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
#include "trgt_yuv.h"
Carlos Lopez a09598
#include <etl stringf=""></etl>
Carlos Lopez a09598
#include <cstdio></cstdio>
Carlos Lopez a09598
#include <algorithm></algorithm>
Carlos Lopez a09598
#include <functional></functional>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
using namespace synfig;
Carlos Lopez a09598
using namespace std;
Carlos Lopez a09598
using namespace etl;
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#define Y_FLOOR	(16)
Carlos Lopez a09598
#define Y_CEIL	(235)
Carlos Lopez a09598
#define Y_RANGE (Y_CEIL-Y_FLOOR)
Carlos Lopez a09598
Carlos Lopez a09598
#define UV_FLOOR	(16)
Carlos Lopez a09598
#define UV_CEIL		(240)
Carlos Lopez a09598
#define UV_RANGE (UV_CEIL-UV_FLOOR)
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
SYNFIG_TARGET_INIT(yuv);
Carlos Lopez a09598
SYNFIG_TARGET_SET_NAME(yuv,"yuv420p");
Carlos Lopez a09598
SYNFIG_TARGET_SET_EXT(yuv,"yuv");
Carlos Lopez a09598
SYNFIG_TARGET_SET_VERSION(yuv,"0.1");
Carlos Lopez a09598
SYNFIG_TARGET_SET_CVS_ID(yuv,"$Id$");
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Diego Barrios Romero 6202fa
yuv::yuv(const char *FILENAME, const synfig::TargetParam& /* params */):
Carlos Lopez a09598
	filename(FILENAME),
Carlos Lopez a09598
	file( (filename=="-")?stdout:fopen(filename.c_str(),POPEN_BINARY_WRITE_TYPE) ),
Carlos Lopez a09598
	dithering(true)
Carlos Lopez a09598
{
Carlos Lopez a09598
	// YUV420P doesn't have an alpha channel
dc451c
	set_alpha_mode(TARGET_ALPHA_MODE_FILL);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
yuv::~yuv()
Carlos Lopez a09598
{
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
aae0f9
yuv::init(synfig::ProgressCallback * /* cb */)
Carlos Lopez a09598
{
Carlos Lopez a09598
	if (!file)
Carlos Lopez a09598
		return false;
Carlos Lopez a09598
Carlos Lopez a09598
	fprintf(file.get(), "YUV4MPEG2 W%d H%d F%d:1 Ip\n",
Carlos Lopez a09598
			desc.get_w(), desc.get_h(),
Carlos Lopez a09598
			round_to_int(desc.get_frame_rate()));
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
yuv::set_rend_desc(RendDesc *given_desc)
Carlos Lopez a09598
{
Carlos Lopez a09598
	given_desc->clear_flags();
Carlos Lopez a09598
Carlos Lopez a09598
	// Make sure our width is divisible by two
Carlos Lopez a09598
	given_desc->set_w(given_desc->get_w()*2/2);
Carlos Lopez a09598
	given_desc->set_h(given_desc->get_h()*2/2);
Carlos Lopez a09598
Carlos Lopez a09598
	desc=*given_desc;
Carlos Lopez a09598
Carlos Lopez a09598
	// Set up our surface
Carlos Lopez a09598
	surface.set_wh(desc.get_w(),desc.get_h());
Carlos Lopez a09598
Carlos Lopez a09598
	return true;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
yuv::start_frame(synfig::ProgressCallback */*callback*/)
Carlos Lopez a09598
{
Carlos Lopez a09598
	fprintf(file.get(), "FRAME\n");
Carlos Lopez a09598
	return static_cast<bool>(file);</bool>
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Color *
Carlos Lopez a09598
yuv::start_scanline(int x)
Carlos Lopez a09598
{
Carlos Lopez a09598
	return surface[x];
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
bool
Carlos Lopez a09598
yuv::end_scanline()
Carlos Lopez a09598
{
Carlos Lopez a09598
	return static_cast<bool>(file);</bool>
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
yuv::end_frame()
Carlos Lopez a09598
{
Carlos Lopez a09598
	const int w=desc.get_w(),h=desc.get_h();
Carlos Lopez a09598
	int x,y;
Carlos Lopez a09598
Carlos Lopez a09598
	assert(file);
Carlos Lopez a09598
Carlos Lopez a09598
	// Output Y' channel, adjusting
Carlos Lopez a09598
	// the gamma as we go
Carlos Lopez a09598
	for(y=0;y
Carlos Lopez a09598
		for(x=0;x
Carlos Lopez a09598
		{
Carlos Lopez a09598
			Color& c(surface[y][x]);
Carlos Lopez a09598
			c=c.clamped();
Carlos Lopez a09598
			float f(c.get_y());
Carlos Lopez a09598
			int i(max(min(round_to_int(c.get_y()*Y_RANGE),Y_RANGE),0)+Y_FLOOR);
Carlos Lopez a09598
Carlos Lopez a09598
			if(dithering)
Carlos Lopez a09598
			{
Carlos Lopez a09598
				const float er(f-((float)i-Y_FLOOR)/Y_RANGE);
Carlos Lopez a09598
				const Color error(er,er,er);
Carlos Lopez a09598
Carlos Lopez a09598
				if(surface.get_h()>y+1)
Carlos Lopez a09598
				{
Carlos Lopez a09598
					surface[y+1][x-1]+=error * ((float)3/(float)16);
Carlos Lopez a09598
					surface[y+1][x]+=error * ((float)5/(float)16);
Carlos Lopez a09598
					if(surface.get_w()>x+1)
Carlos Lopez a09598
						surface[y+1][x+1]+=error * ((float)1/(float)16);
Carlos Lopez a09598
				}
Carlos Lopez a09598
				if(surface.get_w()>x+1)
Carlos Lopez a09598
					surface[y][x+1]+=error * ((float)7/(float)16);
Carlos Lopez a09598
			}
Carlos Lopez a09598
Carlos Lopez a09598
			fputc(i,file.get());
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
	// Create new super-sampled surface
Carlos Lopez a09598
	Surface sm_surface(w/2,h/2);
Carlos Lopez a09598
	for(y=0;y
Carlos Lopez a09598
		for(x=0;x
Carlos Lopez a09598
		{
Carlos Lopez a09598
			Color c(Color::alpha());
Carlos Lopez a09598
			c+=surface[y][x];
Carlos Lopez a09598
			c+=surface[y+1][x];
Carlos Lopez a09598
			c+=surface[y][x+1];
Carlos Lopez a09598
			c+=surface[y+1][x+1];
Carlos Lopez a09598
			c/=4;
Carlos Lopez a09598
			sm_surface[y/2][x/2]=c;
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
	// Output U channel
Carlos Lopez a09598
	for(y=0;y
Carlos Lopez a09598
		for(x=0;x
Carlos Lopez a09598
		{
Carlos Lopez a09598
			const Color& c(sm_surface[y][x]);
Carlos Lopez a09598
			const float f(c.get_u());
Carlos Lopez a09598
			const int i(max(min(round_to_int((f+0.5f)*UV_RANGE),UV_RANGE),0)+UV_FLOOR);
Carlos Lopez a09598
Carlos Lopez a09598
			if(dithering)
Carlos Lopez a09598
			{
Carlos Lopez a09598
				const float er(f-((((float)i-UV_FLOOR)/UV_RANGE)-0.5f));
Carlos Lopez a09598
				const Color error(Color::YUV(0,er,0));
Carlos Lopez a09598
Carlos Lopez a09598
				if(sm_surface.get_h()>y+1)
Carlos Lopez a09598
				{
Carlos Lopez a09598
					sm_surface[y+1][x-1]+=error * ((float)3/(float)16);
Carlos Lopez a09598
					sm_surface[y+1][x]+=error * ((float)5/(float)16);
Carlos Lopez a09598
					if(sm_surface.get_w()>x+1)
Carlos Lopez a09598
						sm_surface[y+1][x+1]+=error * ((float)1/(float)16);
Carlos Lopez a09598
				}
Carlos Lopez a09598
				if(sm_surface.get_w()>x+1)
Carlos Lopez a09598
					sm_surface[y][x+1]+=error * ((float)7/(float)16);
Carlos Lopez a09598
			}
Carlos Lopez a09598
			fputc(i,file.get());
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
	// Output V channel
Carlos Lopez a09598
	for(y=0;y
Carlos Lopez a09598
		for(x=0;x
Carlos Lopez a09598
		{
Carlos Lopez a09598
			const Color& c(sm_surface[y][x]);
Carlos Lopez a09598
			const float f(c.get_v());
Carlos Lopez a09598
			const int i(max(min(round_to_int((f+0.5f)*UV_RANGE),UV_RANGE),0)+UV_FLOOR);
Carlos Lopez a09598
Carlos Lopez a09598
			if(dithering)
Carlos Lopez a09598
			{
Carlos Lopez a09598
				const float er(f-((((float)i-UV_FLOOR)/UV_RANGE)-0.5f));
Carlos Lopez a09598
				const Color error(Color::YUV(0,0,er));
Carlos Lopez a09598
Carlos Lopez a09598
				if(sm_surface.get_h()>y+1)
Carlos Lopez a09598
				{
Carlos Lopez a09598
					sm_surface[y+1][x-1]+=error * ((float)3/(float)16);
Carlos Lopez a09598
					sm_surface[y+1][x]+=error * ((float)5/(float)16);
Carlos Lopez a09598
					if(sm_surface.get_w()>x+1)
Carlos Lopez a09598
						sm_surface[y+1][x+1]+=error * ((float)1/(float)16);
Carlos Lopez a09598
				}
Carlos Lopez a09598
				if(sm_surface.get_w()>x+1)
Carlos Lopez a09598
					sm_surface[y][x+1]+=error * ((float)7/(float)16);
Carlos Lopez a09598
			}
Carlos Lopez a09598
			fputc(i,file.get());
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
	// Flush out the frame
Carlos Lopez a09598
	fflush(file.get());
Carlos Lopez a09598
}