|
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 |
}
|