annotate trunk/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc @ 400:dd13c9834ceb

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