Mercurial > hg > aimc
comparison trunk/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc @ 411:a908972d234e
- Added support for movies!
author | tomwalters |
---|---|
date | Thu, 21 Oct 2010 01:46:39 +0000 |
parents | 69466da9745e |
children | b6d5c0cc1849 |
comparison
equal
deleted
inserted
replaced
410:7af493eb1563 | 411:a908972d234e |
---|---|
48 | 48 |
49 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h" | 49 #include "Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.h" |
50 | 50 |
51 namespace aimc { | 51 namespace aimc { |
52 | 52 |
53 GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *pParam) | 53 GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *parameters) |
54 : GraphicsOutputDeviceCairo(pParam) { // or GraphicsOutputDevicePlotutils | 54 : GraphicsOutputDeviceCairo(parameters) { |
55 m_sMovieFile[0] = '\0'; | 55 sound_filename_.clear(); |
56 m_sSoundFile[0] = '\0'; | 56 movie_filename_.clear(); |
57 } | 57 } |
58 | 58 |
59 bool GraphicsOutputDeviceMovie::Initialize(const char *sSoundFile, | 59 bool GraphicsOutputDeviceMovie::Initialize(Parameters *global_parameters) { |
60 const char *sMovieFile) { | 60 global_parameters_ = global_parameters; |
61 sound_filename_ = global_parameters->GetString("input_filename"); | |
62 string file_suffix = parameters_->DefaultString("filename_suffix", ".mov"); | |
63 movie_filename_ = global_parameters->GetString("output_filename_base") | |
64 + file_suffix; | |
65 | |
61 FILE *f; | 66 FILE *f; |
62 AIM_ASSERT(sSoundFile); | |
63 AIM_ASSERT(sMovieFile); | |
64 | 67 |
65 // Check sound file exists | 68 // Check sound file exists |
66 if ((f = fopen(sSoundFile, "r")) == NULL) { | 69 if ((f = fopen(sound_filename_.c_str(), "r")) == NULL) { |
67 LOG_ERROR(_T("Couldn't open sound file '%s' for movie creation."), | 70 LOG_ERROR(_T("Couldn't open sound file '%s' for movie creation."), |
68 sSoundFile); | 71 sound_filename_.c_str()); |
72 sound_filename_.clear(); | |
69 return false; | 73 return false; |
70 } | 74 } |
71 fclose(f); | 75 fclose(f); |
72 strcpy(m_sSoundFile, sSoundFile); | |
73 | 76 |
74 // Check movie output file can be made | 77 // Check movie output file can be made |
75 if ( (f=fopen(sMovieFile, "w"))==NULL ) { | 78 if ((f = fopen(movie_filename_.c_str(), "w")) == NULL) { |
76 LOG_ERROR(_T("Couldn't open movie file '%s' to write to."), | 79 LOG_ERROR(_T("Couldn't open movie file '%s' to write to."), |
77 sMovieFile); | 80 movie_filename_.c_str()); |
81 movie_filename_.clear(); | |
78 return false; | 82 return false; |
79 } | 83 } |
80 fclose(f); | 84 fclose(f); |
81 strcpy(m_sMovieFile, sMovieFile); | |
82 | 85 |
83 // Get a temporary image output directory | 86 // Get a temporary image output directory |
84 //! \warning Not really safe ... but windows has no mkdtemp() | 87 //! \warning Not really safe ... but windows has no mkdtemp() |
85 //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt. | 88 //! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt. |
86 char *sTmpDir = NULL; | |
87 #ifdef _WINDOWS | 89 #ifdef _WINDOWS |
88 if ((sTmpDir = _tempnam(NULL, AIM_NAME)) | 90 char *temp_dir = NULL; |
89 && _mkdir(sTmpDir) >= 0) { | 91 if ((temp_dir = _tempnam(NULL, AIM_NAME)) |
90 strcpy(m_sDir, sTmpDir); | 92 && _mkdir(temp_dir) >= 0) { |
91 strcat(m_sDir, "\\"); // Make sure to end with trailing slash | 93 directory_ = temp_dir; |
92 } else | 94 directory_ += "\\"; // Make sure to end with trailing slash |
93 #else | 95 } else { |
94 strcpy(m_sDir, "/tmp/"AIM_NAME"-movie.XXXXXX"); | |
95 if (mkdtemp(m_sDir)) { | |
96 strcat(m_sDir, "/"); // Make sure to end with trailing slash | |
97 } else | |
98 #endif | |
99 { | |
100 LOG_ERROR(_T("Couldn't create a temporary directory for movie output.")); | 96 LOG_ERROR(_T("Couldn't create a temporary directory for movie output.")); |
101 if (sTmpDir) free(sTmpDir); | 97 if (temp_dir) { |
102 return false; | 98 free(temp_dir); |
103 } | 99 } |
104 if (sTmpDir) { | 100 return false; |
105 free(sTmpDir); | 101 } |
106 } | 102 if (temp_dir) { |
107 | 103 free(temp_dir); |
104 } | |
105 #else | |
106 char temp_dir[PATH_MAX]; | |
107 strcpy(temp_dir, "/tmp/"AIM_NAME"-movie.XXXXXX"); | |
108 if (mkdtemp(temp_dir)) { | |
109 directory_ = temp_dir; | |
110 directory_ += "/"; // Make sure to end with trailing slash | |
111 } else { | |
112 LOG_ERROR(_T("Couldn't create a temporary directory for movie output.")); | |
113 return false; | |
114 } | |
115 #endif | |
116 | |
108 // We want png for movie conversion | 117 // We want png for movie conversion |
109 //! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt | 118 parameters_->SetString("output.img.format", "png"); |
110 m_pParam->SetString("output.img.format", "png"); | 119 if ( !GraphicsOutputDeviceCairo::Initialize(directory_) ) { |
111 //if ( !GraphicsOutputDevicePlotutils::Initialize(m_sDir) ) { | 120 return false; |
112 if ( !GraphicsOutputDeviceCairo::Initialize(m_sDir) ) { | 121 } |
113 return false; | |
114 } | |
115 | |
116 return true; | 122 return true; |
117 } | 123 } |
118 | 124 |
119 void GraphicsOutputDeviceMovie::Start() { | 125 void GraphicsOutputDeviceMovie::Start() { |
120 //GraphicsOutputDevicePlotutils::Start(); | |
121 GraphicsOutputDeviceCairo::Start(); | 126 GraphicsOutputDeviceCairo::Start(); |
122 // Just output a single frame to get audio/video in sync, put params in there | 127 // Output a couple of frames to get audio/video in sync, put params in there. |
123 gGrab(); | 128 gGrab(); |
124 PlotParameterScreen(); | 129 PlotParameterScreen(); |
125 gRelease(); | 130 gRelease(); |
131 gGrab(); | |
132 PlotParameterScreen(); | |
133 gRelease(); | |
126 } | 134 } |
127 | 135 |
128 void GraphicsOutputDeviceMovie::Stop() { | 136 void GraphicsOutputDeviceMovie::Stop() { |
129 // Make sure Plotutils is really done writing. | |
130 //GraphicsOutputDevicePlotutils::Stop(); | |
131 GraphicsOutputDeviceCairo::Stop(); | 137 GraphicsOutputDeviceCairo::Stop(); |
132 CloseFile(); | 138 CloseFile(); |
133 | 139 |
134 #ifdef __WX__ | 140 #ifdef __WX__ |
135 // GUI only: popup dialog | 141 // GUI only: popup dialog |
136 #else | 142 #else |
137 printf("Generating movie ... \n"); | 143 printf("Generating movie ... \n"); |
138 #endif | 144 #endif |
139 AIM_ASSERT(m_pParam); | 145 AIM_ASSERT(parameters_); |
140 // Convert images and sound file to a movie | 146 // Convert images and sound file to a movie. |
141 //! \warning Movie files are overwritten without warning | 147 //! \warning Movie files are overwritten without warning. |
142 //! \bug ffmpeg only works with colour images, not with bw. So make sure to not use bw only in drawing.. | |
143 // Always convert to audio stream of 44.1kHz or problems may occur in playing or conversio. | |
144 float fFps = 1000.0 / m_pParam->GetFloat("output.frameperiod"); | |
145 char sffmpegPath[1024]; | 148 char sffmpegPath[1024]; |
146 if (!m_pParam->IsSet("output.ffmpeg_path")) { | 149 if (!parameters_->IsSet("output.ffmpeg_path")) { |
147 strcpy(sffmpegPath,"ffmpeg"); | 150 strcpy(sffmpegPath,"ffmpeg"); |
148 } else { | 151 } else { |
149 strcpy(sffmpegPath, m_pParam->GetString("output.ffmpeg_path")); | 152 strcpy(sffmpegPath, parameters_->GetString("output.ffmpeg_path")); |
150 } | 153 } |
151 char sCodecOptions[1024]; | 154 char sCodecOptions[1024]; |
152 if (!m_pParam->IsSet("output.ffmpeg_codec_options")) { | 155 if (!parameters_->IsSet("output.ffmpeg_codec_options")) { |
153 strcpy(sCodecOptions,""); | 156 strcpy(sCodecOptions,""); |
154 } else { | 157 } else { |
155 strcpy(sCodecOptions, m_pParam->GetString("output.ffmpeg_codec_options")); | 158 strcpy(sCodecOptions, parameters_->GetString("output.ffmpeg_codec_options")); |
156 } | 159 } |
157 | 160 float frame_rate = global_parameters_->DefaultFloat("frame_rate", -1.0); |
158 char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer | 161 char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer |
159 snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), | 162 snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), |
160 "%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" " | 163 "%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" " |
161 "-title \"%s\" -comment \"Generated by "AIM_NAME" "AIM_VERSION_STRING"\" " | |
162 "-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"", | 164 "-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"", |
163 sffmpegPath, fFps, m_sSoundFile, m_sDir, | 165 sffmpegPath, frame_rate, sound_filename_.c_str(), directory_.c_str(), |
164 m_pParam->GetString("output.movie.title"), | 166 frame_rate, sCodecOptions, movie_filename_.c_str()); |
165 fFps, sCodecOptions, m_sMovieFile); | |
166 printf(sCmdLine); | 167 printf(sCmdLine); |
167 printf("\n"); | 168 printf("\n"); |
168 if (system(sCmdLine)) { | 169 if (system(sCmdLine)) { |
169 LOG_ERROR(_T("Couldn't create movie output.")); | 170 LOG_ERROR(_T("Couldn't create movie output.")); |
170 } | 171 } |
197 FindClose(hList); | 198 FindClose(hList); |
198 _rmdir(m_sDir); | 199 _rmdir(m_sDir); |
199 #else | 200 #else |
200 DIR *dir; | 201 DIR *dir; |
201 struct dirent *dirent; | 202 struct dirent *dirent; |
202 if (!(dir = opendir(m_sDir))) { | 203 if (!(dir = opendir(directory_.c_str()))) { |
203 LOG_ERROR(_T("Couldn't remove files in temporary directory.")); | 204 LOG_ERROR(_T("Couldn't remove files in temporary directory.")); |
204 return; | 205 return; |
205 } | 206 } |
206 while ((dirent = readdir(dir))) { | 207 while ((dirent = readdir(dir))) { |
207 snprintf(sCmdLine, | 208 snprintf(sCmdLine, |
208 sizeof(sCmdLine)/sizeof(sCmdLine[0]), | 209 sizeof(sCmdLine)/sizeof(sCmdLine[0]), |
209 "%s%s", | 210 "%s%s", |
210 m_sDir, | 211 directory_.c_str(), |
211 dirent->d_name); | 212 dirent->d_name); |
212 unlink(sCmdLine); | 213 unlink(sCmdLine); |
213 } | 214 } |
214 closedir(dir); | 215 closedir(dir); |
215 rmdir(m_sDir); | 216 rmdir(directory_.c_str()); |
216 #endif | 217 #endif |
217 } | 218 } |
218 | 219 |
219 void GraphicsOutputDeviceMovie::PlotParameterScreen() { | 220 void GraphicsOutputDeviceMovie::PlotParameterScreen() { |
220 AIM_ASSERT(m_pParam); | 221 AIM_ASSERT(parameters_); |
221 char sStr[50]; | 222 char sStr[50]; |
222 int lineno = 1; | 223 int lineno = 1; |
223 | 224 |
224 float fMarL = m_pParam->GetFloat(_S("graph.margin.left")); | 225 float fMarL = parameters_->GetFloat(_S("graph.margin.left")); |
225 float fMarT = m_pParam->GetFloat(_S("graph.margin.top")); | 226 float fMarT = parameters_->GetFloat(_S("graph.margin.top")); |
226 float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there! | 227 float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there! |
227 | 228 |
228 gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++), | 229 gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++), |
229 _S("AIM-C")); | 230 _S("AIM-C")); |
230 gText2f(fMarL, | 231 gText2f(fMarL, |
247 }; | 248 }; |
248 for (int i = 0; pPlotParams[i]; i++) { | 249 for (int i = 0; pPlotParams[i]; i++) { |
249 snprintf(sStr, | 250 snprintf(sStr, |
250 sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"), | 251 sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"), |
251 pPlotParams[i], | 252 pPlotParams[i], |
252 m_pParam->GetString(pPlotParams[i])); | 253 parameters_->GetString(pPlotParams[i])); |
253 gText2f(fMarL, | 254 gText2f(fMarL, |
254 1-(fMarT+fTextHeight*lineno++), | 255 1-(fMarT+fTextHeight*lineno++), |
255 sStr); | 256 sStr); |
256 } | 257 } |
257 } | 258 } |