annotate trunk/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc @ 402:69466da9745e

- Massive refactoring to make module tree stuff work. In theory we now support configuration files again. The graphics stuff is untested as yet.
author tomwalters
date Mon, 18 Oct 2010 04:42:28 +0000
parents dd13c9834ceb
children a908972d234e
rev   line source
tomwalters@397 1 // Copyright 2006, Willem van Engen
tomwalters@397 2 //
tomwalters@397 3 // AIM-C: A C++ implementation of the Auditory Image Model
tomwalters@397 4 // http://www.acousticscale.org/AIMC
tomwalters@397 5 //
tomwalters@397 6 // Licensed under the Apache License, Version 2.0 (the "License");
tomwalters@397 7 // you may not use this file except in compliance with the License.
tomwalters@397 8 // You may obtain a copy of the License at
tomwalters@397 9 //
tomwalters@397 10 // http://www.apache.org/licenses/LICENSE-2.0
tomwalters@397 11 //
tomwalters@397 12 // Unless required by applicable law or agreed to in writing, software
tomwalters@397 13 // distributed under the License is distributed on an "AS IS" BASIS,
tomwalters@397 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
tomwalters@397 15 // See the License for the specific language governing permissions and
tomwalters@397 16 // limitations under the License.
tomwalters@397 17
tomwalters@397 18 /*!
tomwalters@397 19 * \file
tomwalters@397 20 * \brief Output device for output to a movie
tomwalters@397 21 *
tomwalters@397 22 * \author Willem van Engen <cnbh@willem.engen.nl>
tomwalters@397 23 * \date created 2006/10/16
tomwalters@397 24 * \version \$Id: GraphicsOutputDeviceMovie.cpp 633 2008-09-11 04:20:16Z tom $
tomwalters@397 25 */
tomwalters@397 26
tomwalters@397 27 /*! \todo
tomwalters@397 28 * A recent experiment showed that the video was about an audioframe
tomwalters@397 29 * (something like 30 ms) behind the audio in rdct.wav. It seems odd
tomwalters@397 30 * to me, since I already output a frame at the beginning to compensate
tomwalters@397 31 * for the missed buffer.
tomwalters@397 32 * A solution that would solve this and be a broader improvement, is to
tomwalters@397 33 * include the source's time when Fire()ing. The outputdevice can then
tomwalters@397 34 * do audio/video synchronization. In the case of the movie, the very
tomwalters@397 35 * first gGrab() looks at the time and emits as much empty output frames
tomwalters@397 36 * as needed until the correct signal time is reached.
tomwalters@397 37 */
tomwalters@397 38 #include "Support/Common.h"
tomwalters@397 39
tomwalters@397 40 #ifdef _WINDOWS
tomwalters@398 41 # include <direct.h> // for _mkdir&_rmdir
tomwalters@397 42 #else
tomwalters@398 43 # include <sys/types.h>
tomwalters@398 44 # include <dirent.h> // for opendir&friends
tomwalters@397 45 #endif
tomwalters@397 46 #include <stdio.h>
tomwalters@397 47 #include <string.h>
tomwalters@397 48
tom@400 49 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h"
tomwalters@397 50
tom@400 51 namespace aimc {
tomwalters@397 52
tomwalters@397 53 GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *pParam)
tomwalters@398 54 : GraphicsOutputDeviceCairo(pParam) { // or GraphicsOutputDevicePlotutils
tomwalters@398 55 m_sMovieFile[0] = '\0';
tomwalters@398 56 m_sSoundFile[0] = '\0';
tomwalters@397 57 }
tomwalters@397 58
tomwalters@397 59 bool GraphicsOutputDeviceMovie::Initialize(const char *sSoundFile,
tomwalters@397 60 const char *sMovieFile) {
tomwalters@398 61 FILE *f;
tomwalters@398 62 AIM_ASSERT(sSoundFile);
tomwalters@398 63 AIM_ASSERT(sMovieFile);
tomwalters@397 64
tomwalters@398 65 // Check sound file exists
tomwalters@398 66 if ((f = fopen(sSoundFile, "r")) == NULL) {
tom@400 67 LOG_ERROR(_T("Couldn't open sound file '%s' for movie creation."),
tomwalters@397 68 sSoundFile);
tomwalters@398 69 return false;
tomwalters@398 70 }
tomwalters@398 71 fclose(f);
tomwalters@398 72 strcpy(m_sSoundFile, sSoundFile);
tomwalters@397 73
tomwalters@398 74 // Check movie output file can be made
tomwalters@398 75 if ( (f=fopen(sMovieFile, "w"))==NULL ) {
tom@400 76 LOG_ERROR(_T("Couldn't open movie file '%s' to write to."),
tomwalters@397 77 sMovieFile);
tomwalters@398 78 return false;
tomwalters@398 79 }
tomwalters@398 80 fclose(f);
tomwalters@398 81 strcpy(m_sMovieFile, sMovieFile);
tomwalters@397 82
tomwalters@398 83 // Get a temporary image output directory
tomwalters@398 84 //! \warning Not really safe ... but windows has no mkdtemp()
tomwalters@398 85 //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt.
tomwalters@398 86 char *sTmpDir = NULL;
tomwalters@397 87 #ifdef _WINDOWS
tomwalters@398 88 if ((sTmpDir = _tempnam(NULL, AIM_NAME))
tomwalters@397 89 && _mkdir(sTmpDir) >= 0) {
tomwalters@398 90 strcpy(m_sDir, sTmpDir);
tomwalters@398 91 strcat(m_sDir, "\\"); // Make sure to end with trailing slash
tomwalters@398 92 } else
tomwalters@397 93 #else
tomwalters@398 94 strcpy(m_sDir, "/tmp/"AIM_NAME"-movie.XXXXXX");
tomwalters@398 95 if (mkdtemp(m_sDir)) {
tomwalters@398 96 strcat(m_sDir, "/"); // Make sure to end with trailing slash
tomwalters@398 97 } else
tomwalters@397 98 #endif
tomwalters@398 99 {
tom@400 100 LOG_ERROR(_T("Couldn't create a temporary directory for movie output."));
tomwalters@398 101 if (sTmpDir) free(sTmpDir);
tomwalters@398 102 return false;
tomwalters@398 103 }
tomwalters@398 104 if (sTmpDir) {
tomwalters@397 105 free(sTmpDir);
tomwalters@397 106 }
tomwalters@397 107
tomwalters@398 108 // We want png for movie conversion
tomwalters@398 109 //! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt
tomwalters@398 110 m_pParam->SetString("output.img.format", "png");
tomwalters@398 111 //if ( !GraphicsOutputDevicePlotutils::Initialize(m_sDir) ) {
tomwalters@398 112 if ( !GraphicsOutputDeviceCairo::Initialize(m_sDir) ) {
tomwalters@398 113 return false;
tomwalters@397 114 }
tomwalters@397 115
tomwalters@398 116 return true;
tomwalters@397 117 }
tomwalters@397 118
tomwalters@397 119 void GraphicsOutputDeviceMovie::Start() {
tomwalters@398 120 //GraphicsOutputDevicePlotutils::Start();
tomwalters@398 121 GraphicsOutputDeviceCairo::Start();
tomwalters@398 122 // Just output a single frame to get audio/video in sync, put params in there
tomwalters@398 123 gGrab();
tomwalters@398 124 PlotParameterScreen();
tomwalters@398 125 gRelease();
tomwalters@397 126 }
tomwalters@397 127
tomwalters@397 128 void GraphicsOutputDeviceMovie::Stop() {
tomwalters@398 129 // Make sure Plotutils is really done writing.
tomwalters@398 130 //GraphicsOutputDevicePlotutils::Stop();
tomwalters@398 131 GraphicsOutputDeviceCairo::Stop();
tomwalters@398 132 CloseFile();
tomwalters@397 133
tomwalters@397 134 #ifdef __WX__
tomwalters@398 135 // GUI only: popup dialog
tomwalters@397 136 #else
tomwalters@398 137 printf("Generating movie ... \n");
tomwalters@397 138 #endif
tomwalters@398 139 AIM_ASSERT(m_pParam);
tomwalters@398 140 // Convert images and sound file to a movie
tomwalters@398 141 //! \warning Movie files are overwritten without warning
tomwalters@398 142 //! \bug ffmpeg only works with colour images, not with bw. So make sure to not use bw only in drawing..
tomwalters@398 143 // Always convert to audio stream of 44.1kHz or problems may occur in playing or conversio.
tomwalters@398 144 float fFps = 1000.0 / m_pParam->GetFloat("output.frameperiod");
tomwalters@398 145 char sffmpegPath[1024];
tomwalters@398 146 if (!m_pParam->IsSet("output.ffmpeg_path")) {
tomwalters@397 147 strcpy(sffmpegPath,"ffmpeg");
tomwalters@397 148 } else {
tomwalters@398 149 strcpy(sffmpegPath, m_pParam->GetString("output.ffmpeg_path"));
tomwalters@397 150 }
tomwalters@397 151 char sCodecOptions[1024];
tomwalters@398 152 if (!m_pParam->IsSet("output.ffmpeg_codec_options")) {
tomwalters@397 153 strcpy(sCodecOptions,"");
tomwalters@397 154 } else {
tomwalters@398 155 strcpy(sCodecOptions, m_pParam->GetString("output.ffmpeg_codec_options"));
tomwalters@397 156 }
tomwalters@397 157
tomwalters@398 158 char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer
tomwalters@398 159 snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]),
tomwalters@398 160 "%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" "
tomwalters@398 161 "-title \"%s\" -comment \"Generated by "AIM_NAME" "AIM_VERSION_STRING"\" "
tomwalters@398 162 "-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"",
tomwalters@398 163 sffmpegPath, fFps, m_sSoundFile, m_sDir,
tomwalters@398 164 m_pParam->GetString("output.movie.title"),
tomwalters@398 165 fFps, sCodecOptions, m_sMovieFile);
tomwalters@397 166 printf(sCmdLine);
tomwalters@397 167 printf("\n");
tomwalters@398 168 if (system(sCmdLine)) {
tom@400 169 LOG_ERROR(_T("Couldn't create movie output."));
tomwalters@398 170 }
tomwalters@397 171
tomwalters@397 172 #ifdef __WX__
tomwalters@398 173 // GUI only: close dialog again
tomwalters@397 174 #endif
tomwalters@398 175 // Remove files in temporary directory and the dir itself
tomwalters@398 176 //! \todo make portable function, possibly decided on by build system
tomwalters@397 177 #ifdef _WINDOWS
tomwalters@398 178 HANDLE hList;
tomwalters@398 179 WIN32_FIND_DATA FileData;
tomwalters@398 180 snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), "%s/*.*", m_sDir);
tomwalters@398 181 if ((hList = FindFirstFile(sCmdLine, &FileData)) == INVALID_HANDLE_VALUE) {
tom@400 182 LOG_ERROR(_T("Couldn't remove files from temporary directory."));
tomwalters@398 183 return;
tomwalters@398 184 }
tomwalters@398 185 bool bRMfinished = false;
tomwalters@398 186 while (!bRMfinished) {
tomwalters@398 187 snprintf(sCmdLine,
tomwalters@397 188 sizeof(sCmdLine)/sizeof(sCmdLine[0]),
tomwalters@398 189 "%s%s",
tomwalters@397 190 m_sDir,
tomwalters@397 191 FileData.cFileName);
tomwalters@398 192 remove(sCmdLine);
tomwalters@398 193 if (!FindNextFile(hList, &FileData) && GetLastError() == ERROR_NO_MORE_FILES) {
tomwalters@398 194 bRMfinished = true;
tomwalters@397 195 }
tomwalters@398 196 }
tomwalters@398 197 FindClose(hList);
tomwalters@398 198 _rmdir(m_sDir);
tomwalters@397 199 #else
tomwalters@398 200 DIR *dir;
tomwalters@398 201 struct dirent *dirent;
tomwalters@398 202 if (!(dir = opendir(m_sDir))) {
tom@400 203 LOG_ERROR(_T("Couldn't remove files in temporary directory."));
tomwalters@398 204 return;
tomwalters@398 205 }
tomwalters@402 206 while ((dirent = readdir(dir))) {
tomwalters@398 207 snprintf(sCmdLine,
tomwalters@397 208 sizeof(sCmdLine)/sizeof(sCmdLine[0]),
tomwalters@398 209 "%s%s",
tomwalters@397 210 m_sDir,
tomwalters@397 211 dirent->d_name);
tomwalters@398 212 unlink(sCmdLine);
tomwalters@398 213 }
tomwalters@398 214 closedir(dir);
tomwalters@398 215 rmdir(m_sDir);
tomwalters@397 216 #endif
tomwalters@397 217 }
tomwalters@397 218
tomwalters@397 219 void GraphicsOutputDeviceMovie::PlotParameterScreen() {
tomwalters@398 220 AIM_ASSERT(m_pParam);
tomwalters@398 221 char sStr[50];
tomwalters@398 222 int lineno = 1;
tomwalters@397 223
tomwalters@398 224 float fMarL = m_pParam->GetFloat(_S("graph.margin.left"));
tomwalters@398 225 float fMarT = m_pParam->GetFloat(_S("graph.margin.top"));
tomwalters@398 226 float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there!
tomwalters@397 227
tomwalters@398 228 gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++),
tomwalters@397 229 _S("AIM-C"));
tomwalters@398 230 gText2f(fMarL,
tomwalters@397 231 1-(fMarT+fTextHeight*lineno++),
tomwalters@397 232 _S("(c) 2006-2010, Thomas Walters, Willem van Engen"));
tomwalters@398 233 gText2f(fMarL,
tomwalters@397 234 1-(fMarT+fTextHeight*lineno++),
tomwalters@397 235 _S("http://aimc.acousticscale.org/"));
tomwalters@398 236 lineno++;
tomwalters@397 237
tomwalters@398 238 static const char *pPlotParams[] = {
tomwalters@398 239 _S("input.buffersize"),
tomwalters@398 240 _S("input.samplerate"),
tomwalters@398 241 _S("bmm.freqstart"),
tomwalters@398 242 _S("bmm.freqend"),
tomwalters@398 243 _S("bmm.numchannels"),
tomwalters@398 244 _S("preset.name"),
tomwalters@398 245 _S("preset.title"),
tomwalters@398 246 NULL
tomwalters@398 247 };
tomwalters@398 248 for (int i = 0; pPlotParams[i]; i++) {
tomwalters@398 249 snprintf(sStr,
tomwalters@397 250 sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"),
tomwalters@398 251 pPlotParams[i],
tomwalters@397 252 m_pParam->GetString(pPlotParams[i]));
tomwalters@398 253 gText2f(fMarL,
tomwalters@397 254 1-(fMarT+fTextHeight*lineno++),
tomwalters@397 255 sStr);
tomwalters@398 256 }
tomwalters@397 257 }
tom@400 258 } // namespace aimc