/* === S Y N F I G ========================================================= */ /*! \file trgt_yuv.cpp ** \brief Template File ** ** $Id$ ** ** \legal ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley ** Copyright (c) 2007 Chris Moore ** ** This package 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 package 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. ** \endlegal */ /* ========================================================================= */ /* === H E A D E R S ======================================================= */ #ifdef USING_PCH # include "pch.h" #else #ifdef HAVE_CONFIG_H # include #endif #include "trgt_yuv.h" #include #include #include #include #endif using namespace synfig; using namespace std; using namespace etl; /* === M A C R O S ========================================================= */ #define Y_FLOOR (16) #define Y_CEIL (235) #define Y_RANGE (Y_CEIL-Y_FLOOR) #define UV_FLOOR (16) #define UV_CEIL (240) #define UV_RANGE (UV_CEIL-UV_FLOOR) /* === G L O B A L S ======================================================= */ SYNFIG_TARGET_INIT(yuv); SYNFIG_TARGET_SET_NAME(yuv,"yuv420p"); SYNFIG_TARGET_SET_EXT(yuv,"yuv"); SYNFIG_TARGET_SET_VERSION(yuv,"0.1"); SYNFIG_TARGET_SET_CVS_ID(yuv,"$Id$"); /* === M E T H O D S ======================================================= */ yuv::yuv(const char *FILENAME, const synfig::TargetParam& /* params */): filename(FILENAME), file( (filename=="-")?stdout:fopen(filename.c_str(),POPEN_BINARY_WRITE_TYPE) ), dithering(true) { // YUV420P doesn't have an alpha channel set_remove_alpha(); } yuv::~yuv() { } bool yuv::init() { if (!file) return false; fprintf(file.get(), "YUV4MPEG2 W%d H%d F%d:1 Ip\n", desc.get_w(), desc.get_h(), round_to_int(desc.get_frame_rate())); return true; } bool yuv::set_rend_desc(RendDesc *given_desc) { given_desc->clear_flags(); // Make sure our width is divisible by two given_desc->set_w(given_desc->get_w()*2/2); given_desc->set_h(given_desc->get_h()*2/2); desc=*given_desc; // Set up our surface surface.set_wh(desc.get_w(),desc.get_h()); return true; } bool yuv::start_frame(synfig::ProgressCallback */*callback*/) { fprintf(file.get(), "FRAME\n"); return static_cast(file); } Color * yuv::start_scanline(int x) { return surface[x]; } bool yuv::end_scanline() { return static_cast(file); } void yuv::end_frame() { const int w=desc.get_w(),h=desc.get_h(); int x,y; assert(file); // Output Y' channel, adjusting // the gamma as we go for(y=0;yy+1) { surface[y+1][x-1]+=error * ((float)3/(float)16); surface[y+1][x]+=error * ((float)5/(float)16); if(surface.get_w()>x+1) surface[y+1][x+1]+=error * ((float)1/(float)16); } if(surface.get_w()>x+1) surface[y][x+1]+=error * ((float)7/(float)16); } fputc(i,file.get()); } // Create new super-sampled surface Surface sm_surface(w/2,h/2); for(y=0;yy+1) { sm_surface[y+1][x-1]+=error * ((float)3/(float)16); sm_surface[y+1][x]+=error * ((float)5/(float)16); if(sm_surface.get_w()>x+1) sm_surface[y+1][x+1]+=error * ((float)1/(float)16); } if(sm_surface.get_w()>x+1) sm_surface[y][x+1]+=error * ((float)7/(float)16); } fputc(i,file.get()); } // Output V channel for(y=0;yy+1) { sm_surface[y+1][x-1]+=error * ((float)3/(float)16); sm_surface[y+1][x]+=error * ((float)5/(float)16); if(sm_surface.get_w()>x+1) sm_surface[y+1][x+1]+=error * ((float)1/(float)16); } if(sm_surface.get_w()>x+1) sm_surface[y][x+1]+=error * ((float)7/(float)16); } fputc(i,file.get()); } // Flush out the frame fflush(file.get()); }