annotate src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc @ 263:07dc1f7047f5

Debug output for audio_example and added a write function for aimc_data
author hamel.phil
date Thu, 06 Jan 2011 20:11:41 +0000
parents 988c8b6f7946
children b106283f812f
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>
tomwalters@252 48
tomwalters@252 49 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h"
tomwalters@252 50
tomwalters@252 51 namespace aimc {
tomwalters@252 52
tomwalters@252 53 GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *parameters)
tomwalters@252 54 : GraphicsOutputDeviceCairo(parameters) {
tomwalters@252 55 sound_filename_.clear();
tomwalters@252 56 movie_filename_.clear();
tomwalters@252 57 }
tomwalters@252 58
tomwalters@252 59 bool GraphicsOutputDeviceMovie::Initialize(Parameters *global_parameters) {
tomwalters@252 60 global_parameters_ = global_parameters;
tomwalters@252 61 sound_filename_ = global_parameters->GetString("input_filename");
tomwalters@252 62 string file_suffix = parameters_->DefaultString("filename_suffix", ".mov");
tomwalters@252 63 movie_filename_ = global_parameters->GetString("output_filename_base")
tomwalters@252 64 + file_suffix;
tomwalters@252 65
tomwalters@252 66 FILE *f;
tomwalters@252 67
tomwalters@252 68 // Check sound file exists
tomwalters@252 69 if ((f = fopen(sound_filename_.c_str(), "r")) == NULL) {
tomwalters@252 70 LOG_ERROR(_T("Couldn't open sound file '%s' for movie creation."),
tomwalters@252 71 sound_filename_.c_str());
tomwalters@252 72 sound_filename_.clear();
tomwalters@252 73 return false;
tomwalters@252 74 }
tomwalters@252 75 fclose(f);
tomwalters@252 76
tomwalters@252 77 // Check movie output file can be made
tomwalters@252 78 if ((f = fopen(movie_filename_.c_str(), "w")) == NULL) {
tomwalters@252 79 LOG_ERROR(_T("Couldn't open movie file '%s' to write to."),
tomwalters@252 80 movie_filename_.c_str());
tomwalters@252 81 movie_filename_.clear();
tomwalters@252 82 return false;
tomwalters@252 83 }
tomwalters@252 84 fclose(f);
tomwalters@252 85
tomwalters@252 86 // Get a temporary image output directory
tomwalters@252 87 //! \warning Not really safe ... but windows has no mkdtemp()
tomwalters@252 88 //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt.
tomwalters@252 89 #ifdef _WINDOWS
tomwalters@252 90 char *temp_dir = NULL;
tomwalters@252 91 if ((temp_dir = _tempnam(NULL, AIM_NAME))
tomwalters@252 92 && _mkdir(temp_dir) >= 0) {
tomwalters@252 93 directory_ = temp_dir;
tomwalters@252 94 directory_ += "\\"; // Make sure to end with trailing slash
tomwalters@252 95 } else {
tomwalters@252 96 LOG_ERROR(_T("Couldn't create a temporary directory for movie output."));
tomwalters@252 97 if (temp_dir) {
tomwalters@252 98 free(temp_dir);
tomwalters@252 99 }
tomwalters@252 100 return false;
tomwalters@252 101 }
tomwalters@252 102 if (temp_dir) {
tomwalters@252 103 free(temp_dir);
tomwalters@252 104 }
tomwalters@252 105 #else
tomwalters@252 106 char temp_dir[PATH_MAX];
tomwalters@252 107 strcpy(temp_dir, "/tmp/"AIM_NAME"-movie.XXXXXX");
tomwalters@252 108 if (mkdtemp(temp_dir)) {
tomwalters@252 109 directory_ = temp_dir;
tomwalters@252 110 directory_ += "/"; // Make sure to end with trailing slash
tomwalters@252 111 } else {
tomwalters@252 112 LOG_ERROR(_T("Couldn't create a temporary directory for movie output."));
tomwalters@252 113 return false;
tomwalters@252 114 }
tomwalters@252 115 #endif
tomwalters@252 116
tomwalters@252 117 // We want png for movie conversion
tomwalters@252 118 parameters_->SetString("output.img.format", "png");
tomwalters@252 119 if ( !GraphicsOutputDeviceCairo::Initialize(directory_) ) {
tomwalters@252 120 return false;
tomwalters@252 121 }
tomwalters@252 122 return true;
tomwalters@252 123 }
tomwalters@252 124
tomwalters@252 125 void GraphicsOutputDeviceMovie::Start() {
tomwalters@252 126 GraphicsOutputDeviceCairo::Start();
tomwalters@252 127 // Output a couple of frames to get audio/video in sync, put params in there.
tomwalters@252 128 gGrab();
tomwalters@252 129 PlotParameterScreen();
tomwalters@252 130 gRelease();
tomwalters@252 131 gGrab();
tomwalters@252 132 PlotParameterScreen();
tomwalters@252 133 gRelease();
tomwalters@252 134 }
tomwalters@252 135
tomwalters@252 136 void GraphicsOutputDeviceMovie::Reset(Parameters* global_parameters) {
tomwalters@252 137 Stop();
tomwalters@252 138 Initialize(global_parameters);
tomwalters@252 139 }
tomwalters@252 140
tomwalters@252 141 void GraphicsOutputDeviceMovie::Stop() {
tomwalters@252 142 GraphicsOutputDeviceCairo::Stop();
tomwalters@252 143 CloseFile();
tom@253 144 m_iFileNumber = 0;
tomwalters@252 145
tomwalters@252 146 #ifdef __WX__
tomwalters@252 147 // GUI only: popup dialog
tomwalters@252 148 #else
tomwalters@252 149 printf("Generating movie ... \n");
tomwalters@252 150 #endif
tomwalters@252 151 AIM_ASSERT(parameters_);
tomwalters@252 152 // Convert images and sound file to a movie.
tomwalters@252 153 //! \warning Movie files are overwritten without warning.
tomwalters@252 154 char sffmpegPath[1024];
tomwalters@252 155 if (!parameters_->IsSet("output.ffmpeg_path")) {
tomwalters@252 156 strcpy(sffmpegPath,"ffmpeg");
tomwalters@252 157 } else {
tomwalters@252 158 strcpy(sffmpegPath, parameters_->GetString("output.ffmpeg_path"));
tomwalters@252 159 }
tomwalters@252 160 char sCodecOptions[1024];
tomwalters@252 161 if (!parameters_->IsSet("output.ffmpeg_codec_options")) {
tomwalters@252 162 strcpy(sCodecOptions,"");
tomwalters@252 163 } else {
tomwalters@252 164 strcpy(sCodecOptions, parameters_->GetString("output.ffmpeg_codec_options"));
tomwalters@252 165 }
tomwalters@252 166 float frame_rate = global_parameters_->DefaultFloat("frame_rate", -1.0);
tomwalters@252 167 char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer
tomwalters@252 168 snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]),
tomwalters@252 169 "%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" "
tomwalters@252 170 "-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"",
tomwalters@252 171 sffmpegPath, frame_rate, sound_filename_.c_str(), directory_.c_str(),
tomwalters@252 172 frame_rate, sCodecOptions, movie_filename_.c_str());
tomwalters@252 173 printf(sCmdLine);
tomwalters@252 174 printf("\n");
tomwalters@252 175 if (system(sCmdLine)) {
tomwalters@252 176 LOG_ERROR(_T("Couldn't create movie output."));
tomwalters@252 177 }
tomwalters@252 178
tomwalters@252 179 #ifdef __WX__
tomwalters@252 180 // GUI only: close dialog again
tomwalters@252 181 #endif
tomwalters@252 182 // Remove files in temporary directory and the dir itself
tomwalters@252 183 //! \todo make portable function, possibly decided on by build system
tomwalters@252 184 #ifdef _WINDOWS
tomwalters@252 185 HANDLE hList;
tomwalters@252 186 WIN32_FIND_DATA FileData;
tomwalters@252 187 snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), "%s/*.*", directory_.c_str());
tomwalters@252 188 if ((hList = FindFirstFile(sCmdLine, &FileData)) == INVALID_HANDLE_VALUE) {
tomwalters@252 189 LOG_ERROR(_T("Couldn't remove files from temporary directory."));
tomwalters@252 190 return;
tomwalters@252 191 }
tomwalters@252 192 bool bRMfinished = false;
tomwalters@252 193 while (!bRMfinished) {
tomwalters@252 194 snprintf(sCmdLine,
tomwalters@252 195 sizeof(sCmdLine)/sizeof(sCmdLine[0]),
tomwalters@252 196 "%s%s",
tomwalters@252 197 directory_.c_str(),
tomwalters@252 198 FileData.cFileName);
tomwalters@252 199 remove(sCmdLine);
tomwalters@252 200 if (!FindNextFile(hList, &FileData) && GetLastError() == ERROR_NO_MORE_FILES) {
tomwalters@252 201 bRMfinished = true;
tomwalters@252 202 }
tomwalters@252 203 }
tomwalters@252 204 FindClose(hList);
tomwalters@252 205 _rmdir(directory_.c_str());
tomwalters@252 206 #else
tomwalters@252 207 DIR *dir;
tomwalters@252 208 struct dirent *dirent;
tomwalters@252 209 if (!(dir = opendir(directory_.c_str()))) {
tomwalters@252 210 LOG_ERROR(_T("Couldn't remove files in temporary directory."));
tomwalters@252 211 return;
tomwalters@252 212 }
tomwalters@252 213 while ((dirent = readdir(dir))) {
tomwalters@252 214 snprintf(sCmdLine,
tomwalters@252 215 sizeof(sCmdLine)/sizeof(sCmdLine[0]),
tomwalters@252 216 "%s%s",
tomwalters@252 217 directory_.c_str(),
tomwalters@252 218 dirent->d_name);
tomwalters@252 219 unlink(sCmdLine);
tomwalters@252 220 }
tomwalters@252 221 closedir(dir);
tomwalters@252 222 rmdir(directory_.c_str());
tomwalters@252 223 #endif
tomwalters@252 224 }
tomwalters@252 225
tomwalters@252 226 void GraphicsOutputDeviceMovie::PlotParameterScreen() {
tomwalters@252 227 AIM_ASSERT(parameters_);
tomwalters@252 228 char sStr[50];
tomwalters@252 229 int lineno = 1;
tomwalters@252 230
tomwalters@252 231 float fMarL = parameters_->GetFloat(_S("graph.margin.left"));
tomwalters@252 232 float fMarT = parameters_->GetFloat(_S("graph.margin.top"));
tomwalters@252 233 float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there!
tomwalters@252 234
tomwalters@252 235 gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++),
tomwalters@252 236 _S("AIM-C"));
tomwalters@252 237 gText2f(fMarL,
tomwalters@252 238 1-(fMarT+fTextHeight*lineno++),
tomwalters@252 239 _S("(c) 2006-2010, Thomas Walters, Willem van Engen"));
tomwalters@252 240 gText2f(fMarL,
tomwalters@252 241 1-(fMarT+fTextHeight*lineno++),
tomwalters@252 242 _S("http://aimc.acousticscale.org/"));
tomwalters@252 243 lineno++;
tomwalters@252 244
tomwalters@252 245 static const char *pPlotParams[] = {
tomwalters@252 246 _S("input.buffersize"),
tomwalters@252 247 _S("input.samplerate"),
tomwalters@252 248 _S("bmm.freqstart"),
tomwalters@252 249 _S("bmm.freqend"),
tomwalters@252 250 _S("bmm.numchannels"),
tomwalters@252 251 _S("preset.name"),
tomwalters@252 252 _S("preset.title"),
tomwalters@252 253 NULL
tomwalters@252 254 };
tomwalters@252 255 for (int i = 0; pPlotParams[i]; i++) {
tomwalters@252 256 snprintf(sStr,
tomwalters@252 257 sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"),
tomwalters@252 258 pPlotParams[i],
tomwalters@252 259 parameters_->GetString(pPlotParams[i]));
tomwalters@252 260 gText2f(fMarL,
tomwalters@252 261 1-(fMarT+fTextHeight*lineno++),
tomwalters@252 262 sStr);
tomwalters@252 263 }
tomwalters@252 264 }
tomwalters@252 265 } // namespace aimc