From: Oliver O. <fr...@us...> - 2007-07-18 06:53:58
|
Update of /cvsroot/simspark/simspark/spark/plugin/movieff In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv5247 Added Files: Tag: projectx Makefile.am export.cpp iitemmovieff.cpp iitemmovieff.h iitemmovieff_c.cpp movieff.cpp movieff.h movieff_c.cpp Log Message: added movieff plugin --- NEW FILE: export.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of simspark Wed May 9 2007 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: export.cpp,v 1.1.2.1 2007/07/18 06:53:54 fruit Exp $ This program 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; version 2 of the License. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "movieff.h" #include "iitemmovieff.h" #include <zeitgeist/zeitgeist.h> ZEITGEIST_EXPORT_BEGIN() ZEITGEIST_EXPORT(MovieFF); ZEITGEIST_EXPORT(IItemMovieFF); ZEITGEIST_EXPORT_END() --- NEW FILE: movieff.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of simspark Wed May 9 2007 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2007 RoboCup Soccer Server 3D Maintenance Group $Id: movieff.h,v 1.1.2.1 2007/07/18 06:53:54 fruit Exp $ This program 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; version 2 of the License. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. MovieFF HISTORY: 26/05/07 - OO - Initial version */ #ifndef MOVIEFF_H #define MOVIEFF_H #include <ffmpeg/avformat.h> #include <oxygen/sceneserver/sceneserver.h> #include <kerosin/renderserver/baserenderserver.h> #include <kerosin/renderserver/customrender.h> #include <fstream> class MovieFF : public kerosin::CustomRender { public: MovieFF(); virtual ~MovieFF(); virtual void OnLink(); // called each step after the renderer finished virtual void Render(); //! open a movie file bool Open(const std::string& name); //! finish the file void Close(); //! start a series of snapshots (static pictures of the current scene) bool StartSnapshots(const std::string& s); //! stop taking snapshots void StopSnapshots(); protected: bool InitBuffers(); void FreeBuffers(); void RecordInternalState(const std::string& name); protected: /** cached reference to the RenderServer */ boost::shared_ptr<kerosin::BaseRenderServer> mRenderServer; /** chached reference to the SceneServer */ boost::shared_ptr<oxygen::SceneServer> mSceneServer; unsigned int mEncLength, mRGBLength, mYUVLength; //! pointer to a yuv buffer uint8_t* mYUVBuffer; //! pointer to a rgb buffer uint8_t* mRGBBuffer; //! pointer to a buffer uint8_t* mEncBuffer; //! reference to a codec context AVCodecContext* mContext; //! reference to a codec AVCodec* mCodec; //! pointer to a frame buffer AVFrame* mRGBpic; //! pointer to a frame buffer AVFrame* mYUVpic; //! flag if the movie file was successfully opened bool mOpen; //! file handle std::ofstream mFile; //! the rate for taking snapshots (every 'rate' call of Render(), we take one) unsigned int mSnapRate; //! flag if we currently want to take snapshots or not bool mDoSnaps; //! the base name for snapshot files std::string mSnapName; //! are we OK? bool mInitialized; }; DECLARE_CLASS(MovieFF); #endif // MOVIEFF_H --- NEW FILE: iitemmovieff_c.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of simspark Wed May 9 2007 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2007 RoboCup Soccer Server 3D Maintenance Group $Id: iitemmovieff_c.cpp,v 1.1.2.1 2007/07/18 06:53:54 fruit Exp $ This program 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; version 2 of the License. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. IItemMovieFF HISTORY: 26/05/07 - OO - Initial version */ #include "iitemmovieff.h" void CLASS(IItemMovieFF)::DefineClass() { DEFINE_BASECLASS(kerosin/InputItem); } --- NEW FILE: Makefile.am --- if BUILD_KEROSIN pkglib_LTLIBRARIES = movieff.la endif movieff_la_SOURCES = \ movieff.cpp movieff.h movieff_c.cpp \ iitemmovieff.cpp iitemmovieff.h iitemmovieff_c.cpp \ export.cpp # -module tells automake we're not building a library but a loadable module # so we don't need the "lib" prefix in the module name movieff_la_LDFLAGS = -module -avoid-version -lavformat -lavcodec -lavutil AM_CPPFLAGS = -I${top_srcdir}/lib @RUBY_CPPFLAGS@ -D__STDC_CONSTANT_MACROS --- NEW FILE: iitemmovieff.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of simspark Wed May 9 2007 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2007 RoboCup Soccer Server 3D Maintenance Group $Id: iitemmovieff.cpp,v 1.1.2.1 2007/07/18 06:53:54 fruit Exp $ This program 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; version 2 of the License. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. InputItem for MovieFF HISTORY: 26/05/07 - OO - Initial version */ #include "iitemmovieff.h" #include <zeitgeist/scriptserver/scriptserver.h> #include <zeitgeist/corecontext.h> #include <iomanip> #include <sstream> // just an arbitrary number (above 12) static const int CmdRecord = 95; static const int CmdSnapshot = 96; IItemMovieFF::IItemMovieFF() : mRec(false), mMovieNo(0) { } void IItemMovieFF::OnLink() { boost::shared_ptr<zeitgeist::ScriptServer> scriptServer = GetCore()->GetScriptServer(); // publish constants to the scripts scriptServer->CreateVariable("Command.Record", CmdRecord); scriptServer->CreateVariable("Command.Snapshot", CmdSnapshot); time_t timet = time(0); tm* now = localtime(&timet); int year = now->tm_year - 100; while (year < 0) year += 100; // fix for wrong clocks while (year > 99) year -= 100; // be future proof for beyond robocup 2099 ;-) std::ostringstream ss; ss << std::setw(2) << std::setfill('0') << year << std::setw(2) << std::setfill('0') << now->tm_mon + 1 << std::setw(2) << std::setfill('0') << now->tm_mday << std::setw(2) << std::setfill('0') << now->tm_hour << std::setw(2) << std::setfill('0') << now->tm_min; mFilenameInfix = ss.str(); } void IItemMovieFF::ProcessInput(const kerosin::Input& input) { // just an arbitrary constant. It has to be mapped to a key somewhere (e.g. bindings.rb) if ((input.mId != CmdRecord) && (input.mId != CmdSnapshot)) return; if (mMovieFF.get() == 0) { boost::shared_ptr<zeitgeist::CoreContext> context = GetCore()->CreateContext(); mMovieFF = boost::shared_static_cast<MovieFF> (context->New("MovieFF", "/sys/server/simulation/RenderControl/MovieFF")); if (mMovieFF.get() == 0) { return; } } switch (input.mId) { case CmdSnapshot: if (mSnap) { mMovieFF->StopSnapshots(); mSnap = false; } else { mSnap = mMovieFF->StartSnapshots("sparkphoto_" + mFilenameInfix); std::cerr << "(iitemmovieff) starting snapshots\n"; } break; case CmdRecord: if (mRec) { ++mMovieNo; mMovieFF->Close(); mRec = false; } else { std::ostringstream ss; ss << "sparkmovie_" << mFilenameInfix << "-" << mMovieNo << ".mpg"; mRec = mMovieFF->Open(ss.str()); } break; default: ;/* nothing to do */ } return; } --- NEW FILE: iitemmovieff.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of simspark Wed May 9 2007 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2007 RoboCup Soccer Server 3D Maintenance Group $Id: iitemmovieff.h,v 1.1.2.1 2007/07/18 06:53:54 fruit Exp $ This program 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; version 2 of the License. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. InputItem for MovieFF HISTORY: 26/05/07 - OO - Initial version */ #ifndef IITEMMOVIEFF_H #define IITEMMOVIEFF_H #include "movieff.h" #include <kerosin/inputserver/inputitem.h> class IItemMovieFF : public kerosin::InputItem { public: IItemMovieFF(); virtual ~IItemMovieFF() {} virtual void OnLink(); virtual void ProcessInput(const kerosin::Input& input); private: bool mRec; bool mSnap; unsigned int mMovieNo; boost::shared_ptr<MovieFF> mMovieFF; std::string mFilenameInfix; }; DECLARE_CLASS(IItemMovieFF); #endif // IITEMMOVIEFF_H --- NEW FILE: movieff_c.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of simspark Wed May 9 2007 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2007 RoboCup Soccer Server 3D Maintenance Group $Id: movieff_c.cpp,v 1.1.2.1 2007/07/18 06:53:54 fruit Exp $ This program 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; version 2 of the License. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. MovieFF HISTORY: 26/05/07 - OO - Initial version */ #include "movieff.h" FUNCTION(MovieFF,open) { std::string filename; if ( (in.GetSize() != 1) || (! in.GetValue(in[0],filename)) ) { return false; } return obj->Open(filename); } FUNCTION(MovieFF,closeMovie) { if ( (in.GetSize() != 0)) { return false; } obj->Close(); return true; } void CLASS(MovieFF)::DefineClass() { DEFINE_BASECLASS(kerosin/CustomRender); DEFINE_FUNCTION(open); DEFINE_FUNCTION(closeMovie); } --- NEW FILE: movieff.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of simspark Wed May 9 2007 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2007 RoboCup Soccer Server 3D Maintenance Group $Id: movieff.cpp,v 1.1.2.1 2007/07/18 06:53:54 fruit Exp $ This program 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; version 2 of the License. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. MovieFF HISTORY: 26/05/07 - OO - Initial version */ #include "movieff.h" #include <zeitgeist/logserver/logserver.h> #include <oxygen/physicsserver/hingejoint.h> #include <oxygen/physicsserver/universaljoint.h> #include <iomanip> #include <sstream> MovieFF::MovieFF() : mEncLength(0), mRGBLength(0), mYUVLength(0), mYUVBuffer(0), mRGBBuffer(0), mEncBuffer(0), mContext(0), mCodec(0), mRGBpic(0), mYUVpic(0), mOpen(false), mSnapRate(15), mDoSnaps(false), mSnapName("movieff_"), mInitialized(false) { av_register_all(); } MovieFF::~MovieFF() { StopSnapshots(); Close(); } void MovieFF::OnLink() { mRenderServer = boost::shared_dynamic_cast<kerosin::BaseRenderServer>(GetCore()->Get("/sys/server/render")); if (mRenderServer.get() == 0) { GetLog()->Error() << "(MovieFF) ERROR: RenderServer not found\n"; } mSceneServer = boost::shared_dynamic_cast<oxygen::SceneServer>(GetCore()->Get("/sys/server/scene")); if (mSceneServer.get() == 0) { GetLog()->Error() << "(MovieFF) ERROR: SceneServer not found\n"; } std::cerr << "(MovieFF) OnLink\n"; } void MovieFF::Render() { if (!mOpen && !mDoSnaps) { return; } if (!mRenderServer->CopyFrame((char*) mRGBBuffer)) { std::cerr << "(MovieFF) couldn't get buffer content\n"; return; } static unsigned int snapCounter = 0; static unsigned int snapNo = 0; // do snapshots if requested if (mDoSnaps && ++snapCounter >= mSnapRate) { snapCounter = 0; std::ostringstream fnstr, internalstr; fnstr << mSnapName << "-" << std::setw(4) << std::setfill('0') << snapNo << ".ppm"; internalstr << mSnapName << "-" << std::setw(4) << std::setfill('0') << snapNo << ".txt"; std::cerr << "Opening " << fnstr.str().c_str() << "\n"; std::ofstream ppm(fnstr.str().c_str()); ppm << "P3\n"; ppm << "# " << fnstr.str() << ", generated by simspark movieff plugin.\n"; ppm << mContext->width << " " << mContext->height << "\n255\n"; for (int y = 0; y < mContext->height; ++y) { ppm << " "; for (int x = 0; x < mContext->width; ++x) { ppm << (int) mRGBBuffer[y * mContext->width * 3 + x * 3 + 0] << " "; ppm << (int) mRGBBuffer[y * mContext->width * 3 + x * 3 + 1] << " "; ppm << (int) mRGBBuffer[y * mContext->width * 3 + x * 3 + 2] << "\n"; } } ppm.close(); RecordInternalState(internalstr.str()); snapNo++; } if (!mOpen) return; /* * Colorspace conversion from RGB to codec's format (likely YUV420P). * OpenGL's RGB pixel format is RGB24 in lavc. */ img_convert((AVPicture *) mYUVpic, mContext->pix_fmt, (AVPicture *) mRGBpic, PIX_FMT_RGB24, mContext->width, mContext->height); /* Encode the frame yuv_pic storing the output in enc_buf. */ int size = avcodec_encode_video(mContext, mEncBuffer, mEncLength, mYUVpic); if (size) { mFile.write((char *)mEncBuffer, size); } } bool MovieFF::Open(const std::string& name) { if (mOpen) return true; std::cerr << "(MovieFF) open " << name << "\n"; if (!InitBuffers()) return false; mFile.open(name.c_str()); if (!mFile.is_open()) { GetLog()->Error() << "(MovieFF) ERROR: opening output file " << name << "\n"; FreeBuffers(); return false; } mOpen = true; return true; } void MovieFF::Close() { static bool exit = false; if (!exit) { exit = true; return; } std::cerr << "(MovieFF) Closing movie\n"; FreeBuffers(); mFile.close(); mOpen = false; } bool MovieFF::StartSnapshots(const std::string& s) { mSnapName = s; mDoSnaps = true; if (mRenderServer.get() == 0) { std::cerr << "(MovieFF) mRenderServer expired\n"; GetLog()->Error() << "(MovieFF) ERROR: No reference to RenderServer\n"; return false; } return InitBuffers(); } void MovieFF::StopSnapshots() { return; std::cerr << "(MovieFF) Stopping snapshots\n"; FreeBuffers(); mDoSnaps = false; } void MovieFF::RecordInternalState(const std::string& name) { if (mSceneServer.get() == 0) return; boost::shared_ptr<oxygen::Scene> scene(mSceneServer->GetActiveScene()); if (scene.get() == 0) return; std::ofstream fout(name.c_str()); Leaf::TLeafList jointList; scene->GetChildrenSupportingClass("Joint", jointList, true); Leaf::TLeafList::const_iterator i = jointList.begin(); while (i != jointList.end()) { boost::shared_ptr<oxygen::UniversalJoint> uj = boost::shared_dynamic_cast<oxygen::UniversalJoint>(*i); boost::shared_ptr<oxygen::HingeJoint> hj = boost::shared_dynamic_cast<oxygen::HingeJoint>(*i); if (uj.get() != 0) { fout << uj->GetFullPath() << "1\t" << uj->GetAngle(oxygen::Joint::AI_FIRST) << "\n"; fout << uj->GetFullPath() << "2\t" << uj->GetAngle(oxygen::Joint::AI_SECOND) << "\n"; } else if (hj.get() != 0) { fout << hj->GetFullPath() << "\t" << hj->GetAngle() << "\n"; } ++i; } } bool MovieFF::InitBuffers() { if (mInitialized) return true; if (mRenderServer.get() == 0) { GetLog()->Error() << "(MovieFF) ERROR: No reference to RenderServer\n"; return false; } int width = mRenderServer->Width(); int height = mRenderServer->Height(); if (width < 1 || height < 1) { GetLog()->Error() << "(MovieFF) ERROR: RenderServer target size invalid\n"; return false; } std::cerr << "(MovieFF) Init buffers\n"; mContext = avcodec_alloc_context(); if (mContext == 0) { GetLog()->Error() << "(MovieFF) ERROR: Allocating the codec context failed\n"; return false; } mContext->codec_id = CODEC_ID_MPEG1VIDEO; mContext->codec_type = CODEC_TYPE_VIDEO; mCodec = avcodec_find_encoder(mContext->codec_id); if (mCodec == 0) { GetLog()->Error() << "(MovieFF) ERROR: Could not find MPEG-1 encoder\n"; av_free(mContext); return false; } mContext->pix_fmt = PIX_FMT_YUV420P; mContext->width = width; mContext->height = height; #if ( LIBAVCODEC_VERSION_INT >> 16 ) >= 51 mContext->time_base = ( AVRational ) { 1, 25 }; #else mContext->frame_rate = 25; #endif mContext->bit_rate = 1600 * 1000; mContext->gop_size = 10; mContext->max_b_frames = 1; int err = avcodec_open(mContext, mCodec); if (err < 0) { GetLog()->Error() << "(MovieFF) ERROR opening video output codec (" << err << ")\n"; av_free(mContext); return false; } mRGBpic = avcodec_alloc_frame(); mYUVpic = avcodec_alloc_frame(); if (mRGBpic == 0 || mYUVpic == 0) { GetLog()->Error() << "(MovieFF) Could not allocate avcodec frame\n"; av_free(mContext); av_free(mRGBpic); av_free(mYUVpic); return false; } /* enc_buf holds the encoded frame, so enc_len must be at least * a reasonable estimate of the size of the largest I-frame. */ mEncLength = width * height * 3; mEncBuffer = new uint8_t[ mEncLength ]; /* rgb_buf holds the unencoded frame in packed RGB from OpenGL. */ mRGBLength = avpicture_get_size(PIX_FMT_RGB24, width, height); mRGBBuffer = new uint8_t[ mRGBLength ]; avpicture_fill(( AVPicture * ) mRGBpic, mRGBBuffer, PIX_FMT_RGB24, width, height); // yuv_buf holds the unencoded frame in codec's native pixel format. mYUVLength = avpicture_get_size(mContext->pix_fmt, width, height); mYUVBuffer = new uint8_t[mYUVLength]; avpicture_fill(( AVPicture * ) mYUVpic, mYUVBuffer, mContext->pix_fmt, width, height ); mInitialized = true; return true; } void MovieFF::FreeBuffers() { if (mOpen && mDoSnaps) return; std::cerr << "(MovieFF) Freeing buffers\n"; mInitialized = false; if (mOpen) { // Flush any frames left in lavc buffer by encoding a NULL frame. for (int i = 0; i <= mContext->max_b_frames; ++i) { int size = avcodec_encode_video(mContext, mEncBuffer, mEncLength, NULL); if (size) mFile.write((char*)(mEncBuffer), size); } char trailer[4]; trailer[0] = 0x00; trailer[1] = 0x00; trailer[2] = 0x01; trailer[3] = 0xb7; mFile.write(trailer, 4); avcodec_close(mContext); } delete[] mRGBBuffer; mRGBBuffer = 0; delete[] mYUVBuffer; mYUVBuffer = 0; delete[] mEncBuffer; mEncBuffer = 0; av_free(mContext); av_free(mRGBpic); av_free(mYUVpic); } |