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