annotate src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc @ 611:0fbaf443ec82

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