diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trunk/src/Modules/Output/Graphics/Devices/GraphicsOutputDeviceMovie.cc	Fri Oct 15 05:40:53 2010 +0000
@@ -0,0 +1,256 @@
+// Copyright 2006, Willem van Engen
+//
+// AIM-C: A C++ implementation of the Auditory Image Model
+// http://www.acousticscale.org/AIMC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*!
+ * \file
+ * \brief Output device for output to a movie
+ *
+ * \author Willem van Engen <cnbh@willem.engen.nl>
+ * \date created 2006/10/16
+ * \version \$Id: GraphicsOutputDeviceMovie.cpp 633 2008-09-11 04:20:16Z tom $
+ */
+
+/*! \todo
+ *  A recent experiment showed that the video was about an audioframe
+ *  (something like 30 ms) behind the audio in rdct.wav. It seems odd
+ *  to me, since I already output a frame at the beginning to compensate
+ *  for the missed buffer.
+ *  A solution that would solve this and be a broader improvement, is to
+ *  include the source's time when Fire()ing. The outputdevice can then
+ *  do audio/video synchronization. In the case of the movie, the very
+ *  first gGrab() looks at the time and emits as much empty output frames
+ *  as needed until the correct signal time is reached.
+ */
+#include "Support/Common.h"
+
+#ifdef _WINDOWS
+#	include <direct.h> // for _mkdir&_rmdir
+#else
+#	include <sys/types.h>
+#	include <dirent.h> // for opendir&friends
+#endif
+#include <stdio.h>
+#include <string.h>
+
+
+#include "Output/GraphicsOutputDeviceMovie.h"
+
+GraphicsOutputDeviceMovie::GraphicsOutputDeviceMovie(Parameters *pParam)
+	: GraphicsOutputDeviceCairo(pParam) {  // or GraphicsOutputDevicePlotutils
+	m_sMovieFile[0] = '\0';
+	m_sSoundFile[0] = '\0';
+}
+
+bool GraphicsOutputDeviceMovie::Initialize(const char *sSoundFile,
+                                           const char *sMovieFile) {
+	FILE *f;
+	AIM_ASSERT(sSoundFile);
+	AIM_ASSERT(sMovieFile);
+
+	// Check sound file exists
+	if ((f = fopen(sSoundFile, "r")) == NULL) {
+		AIM_ERROR(_T("Couldn't open sound file '%s' for movie creation."),
+             sSoundFile);
+		return false;
+	}
+	fclose(f);
+	strcpy(m_sSoundFile, sSoundFile);
+
+	// Check movie output file can be made
+	if ( (f=fopen(sMovieFile, "w"))==NULL ) {
+		aimERROR(_T("Couldn't open movie file '%s' to write to."),
+             sMovieFile);
+		return false;
+	}
+	fclose(f);
+	strcpy(m_sMovieFile, sMovieFile);
+
+	// Get a temporary image output directory
+	//! \warning Not really safe ... but windows has no mkdtemp()
+	//! \todo Make build system check for mkdtemp() to use it when available. See TODO.txt.
+	char *sTmpDir = NULL;
+#ifdef _WINDOWS
+	if ((sTmpDir = _tempnam(NULL, AIM_NAME))
+      && _mkdir(sTmpDir) >= 0) {
+		strcpy(m_sDir, sTmpDir);
+		strcat(m_sDir, "\\"); // Make sure to end with trailing slash
+	} else
+#else
+	strcpy(m_sDir, "/tmp/"AIM_NAME"-movie.XXXXXX");
+	if (mkdtemp(m_sDir)) {
+		strcat(m_sDir, "/"); // Make sure to end with trailing slash
+	} else
+#endif
+	{
+		AIM_ERROR(_T("Couldn't create a temporary directory for movie output."));
+		if (sTmpDir) free(sTmpDir);
+		return false;
+	}
+	if (sTmpDir) {
+    free(sTmpDir);
+  }
+
+	// We want png for movie conversion
+	//! \bug This may change the user preference in GUI, hmm what to do? See TODO.txt
+	m_pParam->SetString("output.img.format", "png");
+	//if ( !GraphicsOutputDevicePlotutils::Initialize(m_sDir) ) {
+	if ( !GraphicsOutputDeviceCairo::Initialize(m_sDir) ) {
+		return false;
+  }
+
+	return true;
+}
+
+void GraphicsOutputDeviceMovie::Start() {
+	//GraphicsOutputDevicePlotutils::Start();
+	GraphicsOutputDeviceCairo::Start();
+	// Just output a single frame to get audio/video in sync, put params in there
+	gGrab();
+	PlotParameterScreen();
+	gRelease();
+}
+
+void GraphicsOutputDeviceMovie::Stop() {
+	// Make sure Plotutils is really done writing.
+	//GraphicsOutputDevicePlotutils::Stop();
+	GraphicsOutputDeviceCairo::Stop();
+	CloseFile();
+
+#ifdef __WX__
+	// GUI only: popup dialog
+#else
+	printf("Generating movie ... \n");
+#endif
+	AIM_ASSERT(m_pParam);
+	// Convert images and sound file to a movie
+	//! \warning Movie files are overwritten without warning
+	//! \bug ffmpeg only works with colour images, not with bw. So make sure to not use bw only in drawing..
+	// Always convert to audio stream of 44.1kHz or problems may occur in playing or conversio.
+	float fFps = 1000.0 / m_pParam->GetFloat("output.frameperiod");
+	char sffmpegPath[1024];
+	if (!m_pParam->IsSet("output.ffmpeg_path")) {
+  strcpy(sffmpegPath,"ffmpeg");
+  } else {
+  	strcpy(sffmpegPath, m_pParam->GetString("output.ffmpeg_path"));
+  }
+  char sCodecOptions[1024];
+	if (!m_pParam->IsSet("output.ffmpeg_codec_options")) {
+    strcpy(sCodecOptions,"");
+  } else {
+	  strcpy(sCodecOptions, m_pParam->GetString("output.ffmpeg_codec_options"));
+  }
+
+	char sCmdLine[1024]; //!\todo check that snprintf does not want a larger buffer
+	snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]),
+		"%s -r %.2f -y -i \"%s\" -i \"%s%%06d.png\" "
+		"-title \"%s\" -comment \"Generated by "AIM_NAME" "AIM_VERSION_STRING"\" "
+		"-sameq -r %.2f -ar 44100 -acodec pcm_s16le %s \"%s\"",
+		sffmpegPath, fFps, m_sSoundFile, m_sDir,
+		m_pParam->GetString("output.movie.title"),
+		fFps, sCodecOptions, m_sMovieFile);
+    printf(sCmdLine);
+    printf("\n");
+	if (system(sCmdLine)) {
+		AIM_ERROR(_T("Couldn't create movie output."));
+	}
+
+#ifdef __WX__
+	// GUI only: close dialog again
+#endif
+	// Remove files in temporary directory and the dir itself
+	//! \todo make portable function, possibly decided on by build system
+#ifdef _WINDOWS
+	HANDLE hList;
+	WIN32_FIND_DATA FileData;
+	snprintf(sCmdLine, sizeof(sCmdLine)/sizeof(sCmdLine[0]), "%s/*.*", m_sDir);
+	if ((hList = FindFirstFile(sCmdLine, &FileData)) == INVALID_HANDLE_VALUE) {
+		AIM_ERROR(_T("Couldn't remove files from temporary directory."));
+		return;
+	}
+	bool bRMfinished = false;
+	while (!bRMfinished) {
+	  snprintf(sCmdLine,
+             sizeof(sCmdLine)/sizeof(sCmdLine[0]),
+			       "%s%s",
+             m_sDir,
+             FileData.cFileName);
+		remove(sCmdLine);
+		if (!FindNextFile(hList, &FileData) && GetLastError() == ERROR_NO_MORE_FILES) {
+			bRMfinished = true;
+    }
+	}
+	FindClose(hList);
+	_rmdir(m_sDir);
+#else
+	DIR *dir;
+	struct dirent *dirent;
+	if (!(dir = opendir(m_sDir))) {
+		AIM_ERROR(_T("Couldn't remove files in temporary directory."));
+		return;
+	}
+	while (dirent = readdir(dir)) {
+		snprintf(sCmdLine,
+             sizeof(sCmdLine)/sizeof(sCmdLine[0]),
+			       "%s%s",
+             m_sDir,
+             dirent->d_name);
+		unlink(sCmdLine);
+	}
+	closedir(dir);
+	rmdir(m_sDir);
+#endif
+}
+
+void GraphicsOutputDeviceMovie::PlotParameterScreen() {
+	AIM_ASSERT(m_pParam);
+	char sStr[50];
+	int lineno = 1;
+
+	float fMarL = m_pParam->GetFloat(_S("graph.margin.left"));
+	float fMarT = m_pParam->GetFloat(_S("graph.margin.top"));
+	float fTextHeight = 1.0f / 50.0f * 1.2; // change this when fontsizing is there!
+
+	gText2f(fMarL, 1-(fMarT+fTextHeight*lineno++),
+          _S("AIM-C"));
+	gText2f(fMarL,
+          1-(fMarT+fTextHeight*lineno++),
+          _S("(c) 2006-2010, Thomas Walters, Willem van Engen"));
+	gText2f(fMarL,
+          1-(fMarT+fTextHeight*lineno++),
+          _S("http://aimc.acousticscale.org/"));
+	lineno++;
+
+	static const char *pPlotParams[] = {
+		_S("input.buffersize"),
+		_S("input.samplerate"),
+		_S("bmm.freqstart"),
+		_S("bmm.freqend"),
+		_S("bmm.numchannels"),
+		_S("preset.name"),
+		_S("preset.title"),
+		NULL
+	};
+	for (int i = 0; pPlotParams[i]; i++) {
+		snprintf(sStr,
+             sizeof(sStr)/sizeof(sStr[0]), _S("%s=%s"),
+			       pPlotParams[i],
+             m_pParam->GetString(pPlotParams[i]));
+		gText2f(fMarL,
+            1-(fMarT+fTextHeight*lineno++),
+            sStr);
+	}
+}