annotate trunk/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc @ 706:f8e90b5d85fd tip

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