1 /* === S Y N F I G ========================================================= */
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
36 #include <ETL/stringf>
42 using namespace synfig;
46 /* === M A C R O S ========================================================= */
50 #define Y_RANGE (Y_CEIL-Y_FLOOR)
54 #define UV_RANGE (UV_CEIL-UV_FLOOR)
56 /* === G L O B A L S ======================================================= */
58 SYNFIG_TARGET_INIT(yuv);
59 SYNFIG_TARGET_SET_NAME(yuv,"yuv420p");
60 SYNFIG_TARGET_SET_EXT(yuv,"yuv");
61 SYNFIG_TARGET_SET_VERSION(yuv,"0.1");
62 SYNFIG_TARGET_SET_CVS_ID(yuv,"$Id$");
64 /* === M E T H O D S ======================================================= */
66 yuv::yuv(const char *FILENAME):
68 file( (filename=="-")?stdout:fopen(filename.c_str(),POPEN_BINARY_WRITE_TYPE) ),
71 // YUV420P doesn't have an alpha channel
85 fprintf(file.get(), "YUV4MPEG2 W%d H%d F%d:1 Ip\n",
86 desc.get_w(), desc.get_h(),
87 round_to_int(desc.get_frame_rate()));
92 yuv::set_rend_desc(RendDesc *given_desc)
94 given_desc->clear_flags();
96 // Make sure our width is divisible by two
97 given_desc->set_w(given_desc->get_w()*2/2);
98 given_desc->set_h(given_desc->get_h()*2/2);
102 // Set up our surface
103 surface.set_wh(desc.get_w(),desc.get_h());
109 yuv::start_frame(synfig::ProgressCallback */*callback*/)
111 fprintf(file.get(), "FRAME\n");
112 return static_cast<bool>(file);
116 yuv::start_scanline(int x)
124 return static_cast<bool>(file);
130 const int w=desc.get_w(),h=desc.get_h();
135 // Output Y' channel, adjusting
136 // the gamma as we go
140 Color& c(surface[y][x]);
142 c.set_r(gamma().r_F32_to_F32(c.get_r()));
143 c.set_g(gamma().g_F32_to_F32(c.get_g()));
144 c.set_b(gamma().b_F32_to_F32(c.get_b()));
146 int i(max(min(round_to_int(c.get_y()*Y_RANGE),Y_RANGE),0)+Y_FLOOR);
150 const float er(f-((float)i-Y_FLOOR)/Y_RANGE);
151 const Color error(er,er,er);
153 if(surface.get_h()>y+1)
155 surface[y+1][x-1]+=error * ((float)3/(float)16);
156 surface[y+1][x]+=error * ((float)5/(float)16);
157 if(surface.get_w()>x+1)
158 surface[y+1][x+1]+=error * ((float)1/(float)16);
160 if(surface.get_w()>x+1)
161 surface[y][x+1]+=error * ((float)7/(float)16);
168 // Create new super-sampled surface
169 Surface sm_surface(w/2,h/2);
173 Color c(Color::alpha());
177 c+=surface[y+1][x+1];
179 sm_surface[y/2][x/2]=c;
183 for(y=0;y<sm_surface.get_h();y++)
184 for(x=0;x<sm_surface.get_w();x++)
186 const Color& c(sm_surface[y][x]);
187 const float f(c.get_u());
188 const int i(max(min(round_to_int((f+0.5f)*UV_RANGE),UV_RANGE),0)+UV_FLOOR);
192 const float er(f-((((float)i-UV_FLOOR)/UV_RANGE)-0.5f));
193 const Color error(Color::YUV(0,er,0));
195 if(sm_surface.get_h()>y+1)
197 sm_surface[y+1][x-1]+=error * ((float)3/(float)16);
198 sm_surface[y+1][x]+=error * ((float)5/(float)16);
199 if(sm_surface.get_w()>x+1)
200 sm_surface[y+1][x+1]+=error * ((float)1/(float)16);
202 if(sm_surface.get_w()>x+1)
203 sm_surface[y][x+1]+=error * ((float)7/(float)16);
209 for(y=0;y<sm_surface.get_h();y++)
210 for(x=0;x<sm_surface.get_w();x++)
212 const Color& c(sm_surface[y][x]);
213 const float f(c.get_v());
214 const int i(max(min(round_to_int((f+0.5f)*UV_RANGE),UV_RANGE),0)+UV_FLOOR);
218 const float er(f-((((float)i-UV_FLOOR)/UV_RANGE)-0.5f));
219 const Color error(Color::YUV(0,0,er));
221 if(sm_surface.get_h()>y+1)
223 sm_surface[y+1][x-1]+=error * ((float)3/(float)16);
224 sm_surface[y+1][x]+=error * ((float)5/(float)16);
225 if(sm_surface.get_w()>x+1)
226 sm_surface[y+1][x+1]+=error * ((float)1/(float)16);
228 if(sm_surface.get_w()>x+1)
229 sm_surface[y][x+1]+=error * ((float)7/(float)16);
234 // Flush out the frame