Linux (gtk): Add preliminary AV recording with x264 and flac.
This commit is contained in:
parent
a15e6cee10
commit
6f91e947c3
|
@ -10,6 +10,10 @@ pixmap_DATA = DeSmuME.xpm
|
||||||
EXTRA_DIST = DeSmuME.xpm desmume.desktop
|
EXTRA_DIST = DeSmuME.xpm desmume.desktop
|
||||||
bin_PROGRAMS = desmume
|
bin_PROGRAMS = desmume
|
||||||
desmume_SOURCES = \
|
desmume_SOURCES = \
|
||||||
|
avout.h \
|
||||||
|
avout_pipe_base.cpp avout_pipe_base.h \
|
||||||
|
avout_x264.cpp avout_x264.h \
|
||||||
|
avout_flac.cpp avout_flac.h \
|
||||||
desmume.h desmume.cpp \
|
desmume.h desmume.cpp \
|
||||||
dTool.h dToolsList.cpp \
|
dTool.h dToolsList.cpp \
|
||||||
tools/ioregsView.cpp tools/ioregsView.h \
|
tools/ioregsView.cpp tools/ioregsView.h \
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AVOUT_H_
|
||||||
|
#define _AVOUT_H_
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class AVOut {
|
||||||
|
public:
|
||||||
|
virtual bool begin(const char* fname) { return false; }
|
||||||
|
virtual void end() {}
|
||||||
|
virtual bool isRecording() { return false; }
|
||||||
|
virtual void updateAudio(void* soundData, int soundLen) {}
|
||||||
|
virtual void updateVideo(const u16* buffer) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "avout_flac.h"
|
||||||
|
|
||||||
|
AVOutFlac::AVOutFlac() {
|
||||||
|
const char* const args[] = {
|
||||||
|
"flac",
|
||||||
|
"-f",
|
||||||
|
"-o", this->filename,
|
||||||
|
"--endian=little",
|
||||||
|
"--channels=2",
|
||||||
|
"--bps=16",
|
||||||
|
"--sample-rate=44100",
|
||||||
|
"--sign=signed",
|
||||||
|
"--force-raw-format",
|
||||||
|
"-",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
memcpy(this->args, args, sizeof(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const* AVOutFlac::getArgv(const char* fname) {
|
||||||
|
if (strlen(fname) >= sizeof(this->filename)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
strncpy(this->filename, fname, sizeof(this->filename));
|
||||||
|
return this->args;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AVOUT_FLAC_H_
|
||||||
|
#define _AVOUT_FLAC_H_
|
||||||
|
|
||||||
|
#include "avout_pipe_base.h"
|
||||||
|
|
||||||
|
class AVOutFlac : public AVOutPipeBase {
|
||||||
|
public:
|
||||||
|
AVOutFlac();
|
||||||
|
protected:
|
||||||
|
Type type() { return TYPE_AUDIO; }
|
||||||
|
const char* const* getArgv(const char* fname);
|
||||||
|
private:
|
||||||
|
char filename[1024];
|
||||||
|
const char* args[12];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "SPU.h"
|
||||||
|
|
||||||
|
#include "avout_pipe_base.h"
|
||||||
|
|
||||||
|
static inline int writeAll(int fd, const void* buf, size_t count) {
|
||||||
|
ssize_t written = 0, writtenTotal = 0;
|
||||||
|
do {
|
||||||
|
written = write(fd, ((u8*)buf) + writtenTotal, count - writtenTotal);
|
||||||
|
} while (written >= 0 && (writtenTotal += written) < count);
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AVOutPipeBase::begin(const char* fname) {
|
||||||
|
if (this->recording) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const char* const* args = this->getArgv(fname);
|
||||||
|
if (args == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int pipefd[2];
|
||||||
|
if (pipe(pipefd) < 0) {
|
||||||
|
fprintf(stderr, "Fail to open pipe\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
close(pipefd[1]);
|
||||||
|
dup2(pipefd[0], STDIN_FILENO);
|
||||||
|
execvp(args[0], (char* const*)args);
|
||||||
|
fprintf(stderr, "Fail to start %s: %d %s\n", args[0], errno, strerror(errno));
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
close(pipefd[0]);
|
||||||
|
this->pipe_fd = pipefd[1];
|
||||||
|
this->recording = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AVOutPipeBase::end() {
|
||||||
|
if (this->recording) {
|
||||||
|
close(this->pipe_fd);
|
||||||
|
this->recording = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AVOutPipeBase::isRecording() {
|
||||||
|
return this->recording;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AVOutPipeBase::updateAudio(void* soundData, int soundLen) {
|
||||||
|
if(!this->recording || this->type() != TYPE_AUDIO) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (writeAll(this->pipe_fd, soundData, soundLen * 2 * 2) == -1) {
|
||||||
|
fprintf(stderr, "Error on writing audio: %d %s\n", errno, strerror(errno));
|
||||||
|
this->end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AVOutPipeBase::updateVideo(const u16* buffer) {
|
||||||
|
if(!this->recording || this->type() != TYPE_VIDEO) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
u8 rgb[256 * 384 * 3];
|
||||||
|
u8* cur = rgb;
|
||||||
|
for (int i = 0; i < 256 * 384; i++) {
|
||||||
|
u16 gpu_pixel = buffer[i];
|
||||||
|
*cur = ((gpu_pixel >> 0) & 0x1f) << 3;
|
||||||
|
cur++;
|
||||||
|
*cur = ((gpu_pixel >> 5) & 0x1f) << 3;
|
||||||
|
cur++;
|
||||||
|
*cur = ((gpu_pixel >> 10) & 0x1f) << 3;
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
if (write(this->pipe_fd, rgb, 256 * 384 * 3) == -1) {
|
||||||
|
fprintf(stderr, "Error on writing video: %d %s\n", errno, strerror(errno));
|
||||||
|
this->end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AVOUT_PIPE_BASE_H_
|
||||||
|
#define _AVOUT_PIPE_BASE_H_
|
||||||
|
|
||||||
|
#include "avout.h"
|
||||||
|
|
||||||
|
class AVOutPipeBase : public AVOut {
|
||||||
|
public:
|
||||||
|
bool begin(const char* fname);
|
||||||
|
void end();
|
||||||
|
bool isRecording();
|
||||||
|
void updateAudio(void* soundData, int soundLen);
|
||||||
|
void updateVideo(const u16* buffer);
|
||||||
|
protected:
|
||||||
|
enum Type { TYPE_AUDIO, TYPE_VIDEO };
|
||||||
|
virtual Type type() = 0;
|
||||||
|
virtual const char* const* getArgv(const char* fname) = 0;
|
||||||
|
private:
|
||||||
|
bool recording;
|
||||||
|
int pipe_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "avout_x264.h"
|
||||||
|
|
||||||
|
AVOutX264::AVOutX264() {
|
||||||
|
const char* const args[] = {
|
||||||
|
"x264",
|
||||||
|
"--qp", "0",
|
||||||
|
"--demuxer", "raw",
|
||||||
|
"--input-csp", "rgb",
|
||||||
|
"--input-depth", "8",
|
||||||
|
"--input-res", "256x384",
|
||||||
|
"--fps", "60",
|
||||||
|
"--output-csp", "i444",
|
||||||
|
"-o", this->filename,
|
||||||
|
"-",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
memcpy(this->args, args, sizeof(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const* AVOutX264::getArgv(const char* fname) {
|
||||||
|
if (strlen(fname) >= sizeof(this->filename)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
strncpy(this->filename, fname, sizeof(this->filename));
|
||||||
|
return this->args;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2014 DeSmuME team
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with the this software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _AVOUT_X264_H_
|
||||||
|
#define _AVOUT_X264_H_
|
||||||
|
|
||||||
|
#include "avout_pipe_base.h"
|
||||||
|
|
||||||
|
class AVOutX264 : public AVOutPipeBase {
|
||||||
|
public:
|
||||||
|
AVOutX264();
|
||||||
|
protected:
|
||||||
|
Type type() { return TYPE_VIDEO; }
|
||||||
|
const char* const* getArgv(const char* fname);
|
||||||
|
private:
|
||||||
|
char filename[1024];
|
||||||
|
const char* args[19];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -51,6 +51,9 @@
|
||||||
#include "cheatsGTK.h"
|
#include "cheatsGTK.h"
|
||||||
#include "GPU_osd.h"
|
#include "GPU_osd.h"
|
||||||
|
|
||||||
|
#include "avout_x264.h"
|
||||||
|
#include "avout_flac.h"
|
||||||
|
|
||||||
#include "commandline.h"
|
#include "commandline.h"
|
||||||
|
|
||||||
#include "slot2.h"
|
#include "slot2.h"
|
||||||
|
@ -106,6 +109,12 @@ enum {
|
||||||
|
|
||||||
gboolean EmuLoop(gpointer data);
|
gboolean EmuLoop(gpointer data);
|
||||||
|
|
||||||
|
static AVOutX264 avout_x264;
|
||||||
|
static AVOutFlac avout_flac;
|
||||||
|
static void RecordAV_x264();
|
||||||
|
static void RecordAV_flac();
|
||||||
|
static void RecordAV_stop();
|
||||||
|
|
||||||
static void DoQuit();
|
static void DoQuit();
|
||||||
static void RecordMovieDialog();
|
static void RecordMovieDialog();
|
||||||
static void PlayMovieDialog();
|
static void PlayMovieDialog();
|
||||||
|
@ -186,6 +195,12 @@ static const char *ui_description =
|
||||||
" <menuitem action='recordmovie'/>"
|
" <menuitem action='recordmovie'/>"
|
||||||
" <menuitem action='playmovie'/>"
|
" <menuitem action='playmovie'/>"
|
||||||
" <menuitem action='stopmovie'/>"
|
" <menuitem action='stopmovie'/>"
|
||||||
|
" <separator/>"
|
||||||
|
" <menu action='RecordAVMenu'>"
|
||||||
|
" <menuitem action='record_x264'/>"
|
||||||
|
" <menuitem action='record_flac'/>"
|
||||||
|
" <menuitem action='record_stop'/>"
|
||||||
|
" </menu>"
|
||||||
" <menuitem action='printscreen'/>"
|
" <menuitem action='printscreen'/>"
|
||||||
" <separator/>"
|
" <separator/>"
|
||||||
" <menuitem action='quit'/>"
|
" <menuitem action='quit'/>"
|
||||||
|
@ -341,6 +356,10 @@ static const GtkActionEntry action_entries[] = {
|
||||||
{ "recordmovie", NULL, "Record movie _to ...", NULL, NULL, RecordMovieDialog },
|
{ "recordmovie", NULL, "Record movie _to ...", NULL, NULL, RecordMovieDialog },
|
||||||
{ "playmovie", NULL, "Play movie _from ...", NULL, NULL, PlayMovieDialog },
|
{ "playmovie", NULL, "Play movie _from ...", NULL, NULL, PlayMovieDialog },
|
||||||
{ "stopmovie", NULL, "Stop movie", NULL, NULL, StopMovie },
|
{ "stopmovie", NULL, "Stop movie", NULL, NULL, StopMovie },
|
||||||
|
{ "RecordAVMenu", NULL, "Record _video/audio" },
|
||||||
|
{ "record_x264", "gtk-media-record", "Record lossless H._264 (video only)...", NULL, NULL, RecordAV_x264 },
|
||||||
|
{ "record_flac", "gtk-media-record", "Record _flac (audio only)...", NULL, NULL, RecordAV_flac },
|
||||||
|
{ "record_stop", "gtk-media-stop", "_Stop recording", NULL, NULL, RecordAV_stop },
|
||||||
{ "SavestateMenu", NULL, "_Save state" },
|
{ "SavestateMenu", NULL, "_Save state" },
|
||||||
{ "LoadstateMenu", NULL, "_Load state" },
|
{ "LoadstateMenu", NULL, "_Load state" },
|
||||||
#ifdef DESMUME_GTK_FIRMWARE_BROKEN
|
#ifdef DESMUME_GTK_FIRMWARE_BROKEN
|
||||||
|
@ -1063,6 +1082,138 @@ static void SaveStateDialog()
|
||||||
gtk_widget_destroy(pFileSelection);
|
gtk_widget_destroy(pFileSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RecordAV_x264()
|
||||||
|
{
|
||||||
|
GtkFileFilter *pFilter_mkv, *pFilter_mp4, *pFilter_any;
|
||||||
|
GtkWidget *pFileSelection;
|
||||||
|
GtkWidget *pParent;
|
||||||
|
gchar *sPath;
|
||||||
|
|
||||||
|
if (desmume_running())
|
||||||
|
Pause();
|
||||||
|
|
||||||
|
pParent = GTK_WIDGET(pWindow);
|
||||||
|
|
||||||
|
pFilter_mkv = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_add_pattern(pFilter_mkv, "*.mkv");
|
||||||
|
gtk_file_filter_set_name(pFilter_mkv, "Matroska (.mkv)");
|
||||||
|
|
||||||
|
pFilter_mp4 = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_add_pattern(pFilter_mp4, "*.mp4");
|
||||||
|
gtk_file_filter_set_name(pFilter_mp4, "MP4 (.mp4)");
|
||||||
|
|
||||||
|
pFilter_any = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_add_pattern(pFilter_any, "*");
|
||||||
|
gtk_file_filter_set_name(pFilter_any, "All files");
|
||||||
|
|
||||||
|
/* Creating the selection window */
|
||||||
|
pFileSelection = gtk_file_chooser_dialog_new("Save video...",
|
||||||
|
GTK_WINDOW(pParent),
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_SAVE, GTK_RESPONSE_OK,
|
||||||
|
NULL);
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (pFileSelection), TRUE);
|
||||||
|
|
||||||
|
/* Only the dialog window is accepting events: */
|
||||||
|
gtk_window_set_modal(GTK_WINDOW(pFileSelection), TRUE);
|
||||||
|
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(pFileSelection), pFilter_mkv);
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(pFileSelection), pFilter_mp4);
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(pFileSelection), pFilter_any);
|
||||||
|
|
||||||
|
/* Showing the window */
|
||||||
|
switch(gtk_dialog_run(GTK_DIALOG(pFileSelection))) {
|
||||||
|
case GTK_RESPONSE_OK:
|
||||||
|
sPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileSelection));
|
||||||
|
|
||||||
|
if(avout_x264.begin(sPath)) {
|
||||||
|
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "record_x264"), FALSE);
|
||||||
|
} else {
|
||||||
|
GtkWidget *pDialog = gtk_message_dialog_new(GTK_WINDOW(pFileSelection),
|
||||||
|
GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_ERROR,
|
||||||
|
GTK_BUTTONS_OK,
|
||||||
|
"Unable to record video to:\n%s", sPath);
|
||||||
|
gtk_dialog_run(GTK_DIALOG(pDialog));
|
||||||
|
gtk_widget_destroy(pDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(sPath);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gtk_widget_destroy(pFileSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RecordAV_flac()
|
||||||
|
{
|
||||||
|
GtkFileFilter *pFilter_flac, *pFilter_any;
|
||||||
|
GtkWidget *pFileSelection;
|
||||||
|
GtkWidget *pParent;
|
||||||
|
gchar *sPath;
|
||||||
|
|
||||||
|
if (desmume_running())
|
||||||
|
Pause();
|
||||||
|
|
||||||
|
pParent = GTK_WIDGET(pWindow);
|
||||||
|
|
||||||
|
pFilter_flac = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_add_pattern(pFilter_flac, "*.flac");
|
||||||
|
gtk_file_filter_set_name(pFilter_flac, "FLAC file (.flac)");
|
||||||
|
|
||||||
|
pFilter_any = gtk_file_filter_new();
|
||||||
|
gtk_file_filter_add_pattern(pFilter_any, "*");
|
||||||
|
gtk_file_filter_set_name(pFilter_any, "All files");
|
||||||
|
|
||||||
|
/* Creating the selection window */
|
||||||
|
pFileSelection = gtk_file_chooser_dialog_new("Save audio...",
|
||||||
|
GTK_WINDOW(pParent),
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
GTK_STOCK_SAVE, GTK_RESPONSE_OK,
|
||||||
|
NULL);
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (pFileSelection), TRUE);
|
||||||
|
|
||||||
|
/* Only the dialog window is accepting events: */
|
||||||
|
gtk_window_set_modal(GTK_WINDOW(pFileSelection), TRUE);
|
||||||
|
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(pFileSelection), pFilter_flac);
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(pFileSelection), pFilter_any);
|
||||||
|
|
||||||
|
/* Showing the window */
|
||||||
|
switch(gtk_dialog_run(GTK_DIALOG(pFileSelection))) {
|
||||||
|
case GTK_RESPONSE_OK:
|
||||||
|
sPath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(pFileSelection));
|
||||||
|
|
||||||
|
if(avout_flac.begin(sPath)) {
|
||||||
|
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "record_flac"), FALSE);
|
||||||
|
} else {
|
||||||
|
GtkWidget *pDialog = gtk_message_dialog_new(GTK_WINDOW(pFileSelection),
|
||||||
|
GTK_DIALOG_MODAL,
|
||||||
|
GTK_MESSAGE_ERROR,
|
||||||
|
GTK_BUTTONS_OK,
|
||||||
|
"Unable to record audio to:\n%s", sPath);
|
||||||
|
gtk_dialog_run(GTK_DIALOG(pDialog));
|
||||||
|
gtk_widget_destroy(pDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(sPath);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gtk_widget_destroy(pFileSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RecordAV_stop() {
|
||||||
|
avout_x264.end();
|
||||||
|
avout_flac.end();
|
||||||
|
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "record_x264"), TRUE);
|
||||||
|
gtk_action_set_sensitive(gtk_action_group_get_action(action_group, "record_flac"), TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
static void OpenNdsDialog()
|
static void OpenNdsDialog()
|
||||||
{
|
{
|
||||||
GtkFileFilter *pFilter_nds, *pFilter_dsgba, *pFilter_any;
|
GtkFileFilter *pFilter_nds, *pFilter_dsgba, *pFilter_any;
|
||||||
|
@ -1181,8 +1332,12 @@ static void OpenRecent(GtkRecentChooser *chooser, gpointer user_data)
|
||||||
|
|
||||||
static void Reset()
|
static void Reset()
|
||||||
{
|
{
|
||||||
|
bool shouldBeRunning = desmume_running();
|
||||||
|
Pause();
|
||||||
NDS_Reset();
|
NDS_Reset();
|
||||||
Launch();
|
if (shouldBeRunning) {
|
||||||
|
Launch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2035,6 +2190,18 @@ public:
|
||||||
while (gtk_events_pending())
|
while (gtk_events_pending())
|
||||||
gtk_main_iteration();
|
gtk_main_iteration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HUD uses this to show pause state
|
||||||
|
virtual bool EMU_IsEmulationPaused() { return !desmume_running(); }
|
||||||
|
|
||||||
|
virtual bool AVI_IsRecording()
|
||||||
|
{
|
||||||
|
return avout_x264.isRecording() || avout_flac.isRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void AVI_SoundUpdate(void* soundData, int soundLen) {
|
||||||
|
avout_flac.updateAudio(soundData, soundLen);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void DoQuit()
|
static void DoQuit()
|
||||||
|
@ -2138,6 +2305,7 @@ gboolean EmuLoop(gpointer data)
|
||||||
_updateDTools();
|
_updateDTools();
|
||||||
gtk_widget_queue_draw( pDrawingArea );
|
gtk_widget_queue_draw( pDrawingArea );
|
||||||
osd->clear();
|
osd->clear();
|
||||||
|
avout_x264.updateVideo((u16*)GPU_screen);
|
||||||
|
|
||||||
if (gtk_fps_limiter_disabled || keys_latch & KEYMASK_(KEY_BOOST - 1)) {
|
if (gtk_fps_limiter_disabled || keys_latch & KEYMASK_(KEY_BOOST - 1)) {
|
||||||
if (autoframeskip) {
|
if (autoframeskip) {
|
||||||
|
@ -2747,6 +2915,9 @@ common_gtk_main( class configured_features *my_config)
|
||||||
/* Main loop */
|
/* Main loop */
|
||||||
gtk_main();
|
gtk_main();
|
||||||
|
|
||||||
|
avout_x264.end();
|
||||||
|
avout_flac.end();
|
||||||
|
|
||||||
desmume_free();
|
desmume_free();
|
||||||
|
|
||||||
#if defined(HAVE_LIBOSMESA)
|
#if defined(HAVE_LIBOSMESA)
|
||||||
|
|
Loading…
Reference in New Issue