OSDN Git Service

[Qt][MOVIE_SAVER] Update but still crashed on start to save :-(
authorK.Ohta <whatisthis.sowhat@gmail.com>
Fri, 27 May 2016 17:36:47 +0000 (02:36 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Fri, 27 May 2016 17:36:47 +0000 (02:36 +0900)
17 files changed:
source/build-cmake/buildvars.dat
source/build-cmake/buildvars_mingw_cross_win32.dat
source/src/qt/avio/movie_saver.cpp
source/src/qt/avio/movie_saver.h
source/src/qt/common/emu_thread.cpp
source/src/qt/common/emu_thread.h
source/src/qt/common/mainwidget.h
source/src/qt/common/qt_utils.cpp
source/src/qt/gui/CMakeLists.txt
source/src/qt/gui/commonclasses.h
source/src/qt/gui/mainwidget_base.h
source/src/qt/gui/menu_main.cpp
source/src/qt/osd_base.cpp
source/src/qt/osd_base.h
source/src/qt/osd_screen.cpp
source/src/qt/osd_sound.cpp
source/tool/installer_unix.sh

index c637cbd..3dd6259 100644 (file)
@@ -37,6 +37,6 @@ LIB_INSTALL="/usr/local/lib/x86_64-linux-gnu/"
 #LIB_INSTALL="/usr/local/lib/"
 #LIB_INSTALL="/usr/lib/x86_64-linux-gnu/"
 
-CMAKE_APPENDFLAG="-DCMAKE_AR:STRING=gcc-ar-6 -DCMAKE_NM:STRING=gcc-nm-6 -DCMAKE_RANLIB:STRING=gcc-ranlib-6"
+CMAKE_APPENDFLAG="-DUSE_MOVIE_SAVER=ON -DUSE_MOVIE_LOADER=ON -DCMAKE_AR:STRING=gcc-ar-6 -DCMAKE_NM:STRING=gcc-nm-6 -DCMAKE_RANLIB:STRING=gcc-ranlib-6"
 
 
index 6eb471d..4e5249d 100644 (file)
@@ -34,16 +34,12 @@ MAKEFLAGS_GENERAL="-j4"
 
 
 CMAKE_LINKFLAG="-static-libstdc++ -static-libgcc"
+CMAKE_APPENDFLAG="-DUSE_QT5_4_APIS=ON"
 #CMAKE_APPENDFLAG="-DCMAKE_AR:STRING=i686-w64-mingw32-gcc-ar \
 #                   -DCMAKE_LD:STRING=i686-w64-mingw32-gcc-ld \
 #                 -DCMAKE_NM:STRING=i686-w64-mingw32-gcc-nm \
 #                 -DCMAKE_RANLIB:STRING=i686-w64-mingw32-gcc-ranlib \
 #                 "
 
-#CMAKE_APPENDFLAG="-DCMAKE_AR:STRING=i686-w64-mingw32-gcc-ar \
-#                -DCMAKE_NM:STRING=i686-w64-mingw32-gcc-nm \
-##               -DCMAKE_RANLIB:STRING=i686-w64-mingw32-gcc-ranlib \
-#                 "
-
 
 
index 4920071..43b95ce 100644 (file)
@@ -21,7 +21,7 @@ MOVIE_SAVER::MOVIE_SAVER(int width, int height, int fps, OSD *osd) : QThread(0)
        rec_fps = fps;
        p_osd = osd;
        recording = false;
-#if defined(MOVIE_SAVER)
+#if defined(USE_MOVIE_SAVER)
        memset(audio_frame, 0x00, sizeof(audio_frame));
        memset(video_frame, 0x00, sizeof(video_frame));
        memset(video_dst, 0x00, sizeof(video_dst));
@@ -45,7 +45,7 @@ MOVIE_SAVER::~MOVIE_SAVER()
 
 void MOVIE_SAVER::enqueue_video(QByteArray *p, int width, int height)
 {
-#if defined(MOVIE_SAVER)
+#if defined(USE_MOVIE_SAVER)
        if(!recording) return;
        if(p == NULL) return;
        QByteArray *pp = new QByteArray(p->data(), p->size());
@@ -63,10 +63,11 @@ bool MOVIE_SAVER::dequeue_video(uint32_t *p)
        if(p == NULL) return false;
 
        QByteArray *pp = video_data_queue.dequeue();
-#if defined(MOVIE_SAVER)
-       if((pp == NULL) || (video_size <= 0)) return false;
+#if defined(USE_MOVIE_SAVER)
+       if(pp == NULL) return false;
        
        video_size = pp->size();
+       if(video_size <= 0) return false;
        memcpy(p, pp->data(), video_size);
 #else
        video_size = 0;
@@ -78,10 +79,11 @@ bool MOVIE_SAVER::dequeue_video(uint32_t *p)
 
 void MOVIE_SAVER::enqueue_audio(QByteArray *p)
 {
-#if defined(MOVIE_SAVER)
+#if defined(USE_MOVIE_SAVER)
        if(!recording) return;
        if(p == NULL) return;
        QByteArray *pp = new QByteArray(p->data(), p->size());
+       AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie: Enqueue audio data %d bytes", p->size());
        audio_data_queue.enqueue(pp);
 #endif   
 }
@@ -92,11 +94,13 @@ bool MOVIE_SAVER::dequeue_audio(int16_t *p)
        if(audio_data_queue.isEmpty()) return false;
        if(p == NULL) return false;
        QByteArray *pp = audio_data_queue.dequeue();
-#if defined(MOVIE_SAVER)
-       if((pp == NULL) || (audio_size <= 0)) return false;
+#if defined(USE_MOVIE_SAVER)
+       if(pp == NULL) return false;
+       AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie: Dequeue audio data %d bytes", pp->size());
 
        audio_size = pp->size();
-       memcpy(p, pp->data(), audio_size);
+       if(audio_size <= 0) return false;
+       memcpy(p, pp->constData(), audio_size);
 #else
        audio_size = 0;
 #endif   
@@ -104,12 +108,44 @@ bool MOVIE_SAVER::dequeue_audio(int16_t *p)
        return true;
 }
 
+
+
+int MOVIE_SAVER::write_audio_frame(const void *_time_base, void *_pkt)
+{
+#if defined(USE_LIBAV)
+       AVFormatContext *fmt_ctx = output_context;
+       AVStream *st = (AVStream *)audio_stream;
+       AVRational *time_base = (AVRational *)_time_base;
+       AVPacket *pkt = (AVPacket *)_pkt;
+       
+    /* rescale output packet timestamp values from codec to stream timebase */
+    av_packet_rescale_ts(pkt, *time_base, st->time_base);
+    pkt->stream_index = st->index;
+    /* Write the compressed frame to the media file. */
+    //log_packet(fmt_ctx, pkt);
+    return av_interleaved_write_frame(fmt_ctx, pkt);
+#else
+       return -1;
+#endif
+}
+
 void MOVIE_SAVER::run()
 {
        bRunThread = true;
+       //AGAR_DebugLog(AGAR_LOG_DEBUG, "MOVIE THREAD: Start");
        
+    AVCodecContext *c;
+    AVPacket pkt = { 0 }; // data and size must be 0;
+    AVFrame *frame;
+    int ret;
+    int got_packet;
+    int dst_nb_samples;
+
        int fps_wait = (int)((1000.0 / p_osd->vm_frame_rate()) / 2.0);
        int tmp_wait = fps_wait;
+       int ncount_audio = 0;
+       int ncount_video = 0;
+
        while(bRunThread) {
                if(recording) {
                        if(!bRunThread) break;
@@ -121,24 +157,77 @@ void MOVIE_SAVER::run()
                                        uint64_t us = (uint64_t)floor(((double)bytes * 1000000.0) / (double)audio_codec->sample_rate);
                                        double samples = ((double)us / 1000000.0) * (double)audio_codec->sample_rate;
                                        int ret;
+                                       AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie: Write audio data %d bytes", bytes);
                                        
                                        if(bytes == 0) goto _video;
                                        
                                        av_init_packet(&pkt);
-                                       pkt.dts = pkt.pts = (int64_t)samples;
-                                       pkt.flags |= AV_PKT_FLAG_KEY;
-                                       pkt.data = (uint8_t *)audio_frame;
-                                       pkt.size = (uint32_t)bytes;
-                                       pkt.stream_index = 1;
-                                       ret = av_write_frame(output_context, &pkt);
+                                       {
+                                               frame = audio_tmp_frame;
+                                               if (av_compare_ts(audio_next_pts, audio_stream->codec->time_base,
+                                                                                 (double)fps_wait, (AVRational){ 1, 1 }) >= 0)
+                                                       goto _video;
+                                               frame->pts = audio_next_pts;
+                                               audio_next_pts += frame->nb_samples;
+                                       }
+
+                                       /* convert samples from native format to destination codec format, using the resampler */
+                                       /* compute destination number of samples */
+                                       audio_dst_nb_samples = av_rescale_rnd(swr_get_delay(audio_swr_context, audio_codec->sample_rate)
+                                                                                                                 + frame->nb_samples,
+                                                                                                                 audio_codec->sample_rate,
+                                                                                                                 audio_codec->sample_rate,
+                                                                                                                 AV_ROUND_UP);
+                                       //av_assert0(audio_dst_nb_samples == frame->nb_samples);
+                                       /* when we pass a frame to the encoder, it may keep a reference to it
+                                        * internally;
+                                        * make sure we do not overwrite it here
+                                        */
+                                       ret = av_frame_make_writable(frame);
+                                       if (ret < 0) {
+                                               AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie/Audio: Error while converting\n");
+                                               do_close();
+                                               continue;
+                                       }
+                                       /* convert to destination format */
+                                       ret = swr_convert(audio_swr_context,
+                                                                         frame->data, audio_dst_nb_samples,
+                                                                         (const uint8_t **)frame->data, frame->nb_samples);
+                                       if (ret < 0) {
+                                               AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie/Audio: Error while converting\n");
+                                               do_close();
+                                               continue;
+                                       }
+                                       frame->pts = av_rescale_q(audio_samples_count, (AVRational){1, audio_codec->sample_rate},
+                                                                                         audio_codec->time_base);
+                                       audio_samples_count += dst_nb_samples;
+                                       ret = avcodec_encode_audio2(audio_codec, &pkt, frame, &got_packet);
+                                       if (ret < 0) {
+                                               AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie/Audio : Error encoding audio frame\n");
+                                               do_close();
+                                               continue;
+                                       }
+                                       if (got_packet) {
+                                               ret = write_audio_frame((const void *)(&audio_codec->time_base), (void *)(&pkt));
+                                               if (ret < 0) {
+                                                       AGAR_DebugLog(AGAR_LOG_DEBUG, "Movie/Audio Error while writing audio frame\n");
+                                                       do_close();
+                                                       continue;
+                                               }
+                                       }
 #endif // defined(USE_LIBAV)
                                        totalAudioFrame++;
+                                       ncount_audio++;
                                }
                        }
-_video:
-               if(0) {
+               _video:
+                       if(0) {
+                       }
                }
+               if(ncount_audio > 10) { 
+                       ncount_audio = 0;
                }
+               
                if(fps_wait >= tmp_wait) {
                        this->msleep(tmp_wait);
                        tmp_wait = 0;
@@ -155,10 +244,12 @@ _video:
 
 void MOVIE_SAVER::do_close()
 {
+       int i;
 #if defined(USE_LIBAV)
        if(output_context != NULL) {
                av_write_trailer(output_context);
                avio_close(output_context->pb);
+               //av_freep(&output_context->pb);
        }
        if(audio_stream != NULL) {
                av_free(audio_stream);
@@ -191,8 +282,8 @@ void MOVIE_SAVER::do_close()
        video_height_queue.clear();
 
        // Message
-       AGAR_DebugLog(AGAR_LOG_DEBUG, "MOVIE: Close: Read:   Video %ll frames, Audio %ll frames", totalSrcFrame, totalAudioFrame);
-       AGAR_DebugLog(AGAR_LOG_DEBUG, "MOVIE: Close: Write:  Video %ll frames, Audio %ll frames", totalDstFrame, totalAudioFrame);
+       AGAR_DebugLog(AGAR_LOG_DEBUG, "MOVIE: Close: Read:   Video %q frames, Audio %q frames", totalSrcFrame, totalAudioFrame);
+       AGAR_DebugLog(AGAR_LOG_DEBUG, "MOVIE: Close: Write:  Video %q frames, Audio %q frames", totalDstFrame, totalAudioFrame);
        totalSrcFrame = 0;
        totalDstFrame = 0;
        totalAudioFrame = 0;
@@ -210,22 +301,49 @@ bool MOVIE_SAVER::is_recording(void)
 {
        return recording;
 }
-#if defined(MOVIE_SAVER) && defined(USE_LIBAV)
+#if defined(USE_MOVIE_SAVER) && defined(USE_LIBAV)
 static const AVRational time_base_15 = (AVRational){1001, 14485};
 static const AVRational time_base_24 = (AVRational){1001, 23976};
 static const AVRational time_base_25 = (AVRational){1001, 25025};
 static const AVRational time_base_30 = (AVRational){1001, 29970};
 static const AVRational time_base_60 = (AVRational){1001, 59940};
-#endif // defined(MOVIE_SAVER) &&  defined(USE_LIBAV) 
+#endif // defined(USE_MOVIE_SAVER) &&  defined(USE_LIBAV) 
 
-void MOVIE_SAVER::do_open(QString filename)
+AVFrame *MOVIE_SAVER::alloc_audio_frame(enum AVSampleFormat sample_fmt,
+                                                                               uint64_t channel_layout,
+                                                                               int sample_rate, int nb_samples)
+{
+    AVFrame *frame = av_frame_alloc();
+    int ret;
+    if (!frame) {
+        fprintf(stderr, "Error allocating an audio frame\n");
+        //exit(1);
+               return NULL;
+    }
+    frame->format = sample_fmt;
+    frame->channel_layout = channel_layout;
+    frame->sample_rate = sample_rate;
+    frame->nb_samples = nb_samples;
+    if (nb_samples) {
+        ret = av_frame_get_buffer(frame, 0);
+        if (ret < 0) {
+            fprintf(stderr, "Error allocating an audio buffer\n");
+            return NULL;
+        }
+    }
+    return frame;
+}
+
+void MOVIE_SAVER::do_open(QString filename, int fps)
 {
        do_close();
+       do_set_record_fps(fps);
 
        _filename = filename;
 #if defined(USE_LIBAV)
-       format = av_guess_format("mp4", NULL, NULL);
-
+       av_register_all();
+       format = av_guess_format(NULL, filename.toLocal8Bit().constData(), NULL);
+       printf("%s\n", filename.toLocal8Bit().constData());
        if(format == NULL) {
                AGAR_DebugLog(AGAR_LOG_DEBUG, "AVC ERROR: Failed to initialize libavf");
                return;
@@ -257,9 +375,29 @@ void MOVIE_SAVER::do_open(QString filename)
        video_codec->has_b_frames = 1;
        QString author = QString::fromUtf8("emu");
        author = author + p_osd->get_vm_config_name();
-       QString date_str = QString::fromUtf8("Record from");
+       QString date_str = QString::fromUtf8("Record from ");
        date_str = date_str + create_date_file_name();
        
+       switch(rec_fps) {
+       case 15:
+               time_base = time_base_15;
+               break;
+       case 24:
+               time_base = time_base_24;
+               break;
+       case 25:
+               time_base = time_base_25;
+               break;
+       case 30:
+               time_base = time_base_30;
+               break;
+       case 60:
+               time_base = time_base_60;
+               break;
+       default:
+               time_base = (AVRational){1001, rec_fps * 1000};
+               break;
+       }
        { // Video Start
                av_dict_set(&output_context->metadata, "title", date_str.toUtf8().constData(), 0);
                av_dict_set(&output_context->metadata, "author", author.toUtf8().constData(), 0);
@@ -321,6 +459,9 @@ void MOVIE_SAVER::do_open(QString filename)
                return;
        }
 
+       audio_next_pts = 0;
+       audio_dst_nb_samples = 0;
+       audio_samples_count = 0;
        // Temporally using libAV's AAC
        audio_codec = audio_stream->codec;
        audio_codec->frame_size = 1024; 
@@ -332,7 +473,32 @@ void MOVIE_SAVER::do_open(QString filename)
        audio_codec->bit_rate = audio_codec->sample_rate * 8 * 2;
        audio_codec->rc_buffer_size = audio_codec->sample_rate / 4; // 250 ms worth
        audio_codec->channels = 2;
-
+       
+    if (audio_codec->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
+        audio_nb_samples = 10000;
+    else
+        audio_nb_samples = audio_codec->frame_size;
+       audio_frame_data =  alloc_audio_frame(audio_codec->sample_fmt, audio_codec->channel_layout,
+                                                                                        audio_codec->sample_rate, audio_nb_samples);
+       audio_tmp_frame  =  alloc_audio_frame(audio_codec->sample_fmt, audio_codec->channel_layout,
+                                                                                        audio_codec->sample_rate, audio_nb_samples);
+       
+       audio_swr_context =  swr_alloc();
+       //if (audio_swr_context == NULL) {
+       //      fprintf(stderr, "Could not allocate resampler context\n");
+       //      return;
+       //}
+       av_opt_set_int       (audio_swr_context, "in_channel_count",   audio_codec->channels,       0);
+       av_opt_set_int       (audio_swr_context, "in_sample_rate",     audio_codec->sample_rate,    0);
+       av_opt_set_sample_fmt(audio_swr_context, "in_sample_fmt",      AV_SAMPLE_FMT_S16, 0);
+       av_opt_set_int       (audio_swr_context, "out_channel_count",  audio_codec->channels,       0);
+       av_opt_set_int       (audio_swr_context, "out_sample_rate",    audio_codec->sample_rate,    0);
+       av_opt_set_sample_fmt(audio_swr_context, "out_sample_fmt",     audio_codec->sample_fmt,     0);
+       /* initialize the resampling context */
+       //if ((ret = swr_init(ost->swr_ctx)) < 0) {
+       //      fprintf(stderr, "Failed to initialize the resampling context\n");
+       //      exit(1);
+       //}
        // Context
        //output_context->mux_rate = 100080 * 1000;
        output_context->bit_rate = 100080 * 1000;
@@ -346,7 +512,9 @@ void MOVIE_SAVER::do_open(QString filename)
        }               
 
        av_dump_format(output_context, 0, filename.toLocal8Bit().constData(), 1);
+       //av_dump_format(output_context, 1, NULL, 1);
        AGAR_DebugLog(AGAR_LOG_DEBUG, "Successfully opened AVC stream.");
+
 #endif // defined(USE_LIBAV)
        recording = true;
 }
index f430112..3490417 100644 (file)
 
 #if defined(USE_LIBAV)
 extern "C" {
+       #include "libavutil/channel_layout.h"
+       #include "libavutil/opt.h"
+       #include "libavutil/mathematics.h"
+       #include "libavutil/timestamp.h"
        #include "libavformat/avformat.h"
+       #include "libswscale/swscale.h"
+       #include "libswresample/swresample.h"
 }
 #endif
 
@@ -34,8 +40,16 @@ protected:
        AVCodecContext *video_codec;
        AVStream *audio_stream;
        AVStream *video_stream;
-       
+
+       AVFrame *audio_frame_data;
+       AVFrame *audio_tmp_frame;
        struct AVCodec codec_real;
+       struct SwrContext *audio_swr_context;
+       int audio_nb_samples;
+       int audio_samples_count;
+       
+       int64_t audio_dst_nb_samples;
+       int64_t audio_next_pts;
 #endif   
        QString _filename;
        bool bRunThread;
@@ -72,6 +86,10 @@ protected:
        bool dequeue_audio(int16_t *);
        bool dequeue_video(uint32_t *);
        QString create_date_file_name(void);
+       int write_audio_frame(const void *_time_base, void *_pkt);
+       AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
+                                                          uint64_t channel_layout,
+                                                          int sample_rate, int nb_samples);
        
 public:
        MOVIE_SAVER(int width, int height, int fps, OSD *osd);
@@ -83,7 +101,7 @@ public slots:
        void enqueue_video(QByteArray *p, int width, int height);
        void enqueue_audio(QByteArray *p);
        void do_close();
-       void do_open(QString filename);
+       void do_open(QString filename, int);
        void do_set_width(int width);
        void do_set_height(int height);
        void do_set_record_fps(int fps);
index f267dac..f13da44 100644 (file)
@@ -1170,6 +1170,8 @@ void EmuThreadClass::doWork(const QString &params)
        int opengl_filter_num_bak = config.opengl_filter_num;
        //uint32_t key_mod_old = 0xffffffff;
        int no_draw_count = 0;  
+       bool prevRecordReq;
+
        doing_debug_command = false;
        
        ctext.clear();
@@ -1181,7 +1183,9 @@ void EmuThreadClass::doWork(const QString &params)
        bUpdateConfigReq = false;
        bStartRecordSoundReq = false;
        bStopRecordSoundReq = false;
-       
+       bStartRecordMovieReq = false;
+       record_fps = -1;
+
        next_time = 0;
        mouse_flag = false;
 
@@ -1274,6 +1278,21 @@ void EmuThreadClass::doWork(const QString &params)
                                bUpdateConfigReq = false;
                                req_draw = true;
                        }
+                       if(bStartRecordMovieReq != false) {
+                               if(!prevRecordReq && (record_fps > 0) && (record_fps < 75)) {           
+                                       p_emu->start_record_video(record_fps);
+                                       prevRecordReq = true;
+                               }
+                       } else {
+                               if(prevRecordReq) {
+                                       p_emu->stop_record_video();
+                                       record_fps = -1;
+                                       prevRecordReq = false;
+                               }
+                       }
+                  
+                  
+
 #if defined(USE_MOUSE) // Will fix
                        emit sig_is_enable_mouse(p_emu->is_mouse_enabled());
 #endif                 
@@ -1434,6 +1453,19 @@ void EmuThreadClass::doSaveState()
 {
        bSaveStateReq = true;
 }
+
+void EmuThreadClass::doStartRecordVideo(int fps)
+{
+       record_fps = fps;
+       bStartRecordMovieReq = true;
+}
+
+void EmuThreadClass::doStopRecordVideo()
+{
+       bStartRecordMovieReq = false;
+}
+
+
 // Debugger
 #if defined(USE_DEBUGGER)
 extern int debugger_command(debugger_thread_t *p, _TCHAR *command, _TCHAR *prev_command, bool cp932);
index 66a4200..dacfb5c 100644 (file)
@@ -67,12 +67,15 @@ private:
        bool bUpdateConfigReq;
        bool bStartRecordSoundReq;
        bool bStopRecordSoundReq;
+       bool bStartRecordMovieReq;
+
        bool draw_timing;
        bool doing_debug_command;
        bool bUpdateVolumeReq[32];
        int volume_balance[32];
        int volume_avg[32];
-       
+       int record_fps;
+
        qint64 next_time;
        qint64 update_fps_time;
        bool prev_skip;
@@ -111,6 +114,9 @@ public slots:
        void doUpdateConfig();
        void doStartRecordSound();
        void doStopRecordSound();
+       void doStartRecordVideo(int fps);
+       void doStopRecordVideo();
+
        void doSetDisplaySize(int w, int h, int ww, int wh);
        void doUpdateVolumeLevel(int num, int level);
        void doUpdateVolumeBalance(int num, int level);
index 0857af2..a6e16cc 100644 (file)
@@ -68,6 +68,7 @@ public slots:
        void delete_joy_thread(void);
        void do_set_mouse_enable(bool flag);
        void do_toggle_mouse(void);
+
        //virtual void redraw_status_bar(void);
        
 };
index da2453b..ab136b5 100644 (file)
@@ -14,6 +14,7 @@
 #include <QTextCodec>
 #include <QImage>
 #include <QImageReader>
+#include <QDateTime>
 #include <QDir>
 
 #include "common.h"
@@ -33,6 +34,7 @@
 #include "menu_disk.h"
 #include "menu_bubble.h"
 #include "menu_flags.h"
+#include "../avio/movie_saver.h"
 // emulation core
 
 EMU* emu;
@@ -98,6 +100,28 @@ void Ui_MainWindow::do_toggle_mouse(void)
 #endif 
 }
 
+void Object_Menu_Control::do_save_as_movie(void)
+{
+       int fps = 0;
+       QDateTime nowTime = QDateTime::currentDateTime();
+       QString tmps = nowTime.toString(QString::fromUtf8("yyyy-MM-dd_hh-mm-ss.zzz."));
+       QString path = QString::fromUtf8("Saved_Movie") + tmps + QString::fromUtf8("mp4");
+       if(emu->get_osd() == NULL) return;
+       path = QString::fromLocal8Bit(emu->get_osd()->get_app_path()) + path;
+
+       int num = getNumber();
+       if((num <= 0) || (num > 75)) return;
+       fps = num;
+       emit sig_start_record_movie(fps);
+       emit sig_save_as_movie(path, fps);
+}
+
+void Object_Menu_Control::do_stop_saving_movie(void)
+{
+       emit sig_stop_record_movie();
+       emit sig_stop_saving_movie();
+}
+
 void Ui_MainWindow::LaunchEmuThread(void)
 {
        QString objNameStr;
@@ -283,6 +307,31 @@ void Ui_MainWindow::LaunchEmuThread(void)
        hDrawEmu->setObjectName(objNameStr);
        hDrawEmu->start();
        AGAR_DebugLog(AGAR_LOG_DEBUG, "DrawThread : Launch done.");
+
+       hSaveMovieThread = new MOVIE_SAVER(640, 400,  30, emu->get_osd());
+       for(int i = 0; i < (CSP_MAINWIDGET_SAVE_MOVIE_END - 1); i++) {
+               connect(action_SaveAsMovie[i]->binds, SIGNAL(sig_save_as_movie(QString, int)), hSaveMovieThread, SLOT(do_open(QString, int)));
+               connect(action_SaveAsMovie[i]->binds, SIGNAL(sig_start_record_movie(int)), hRunEmu, SLOT(doStartRecordVideo(int)));
+               connect(action_SaveAsMovie[i], SIGNAL(triggered()), action_SaveAsMovie[i]->binds, SLOT(do_save_as_movie()));
+               //connect(action_SaveAsMovie[i]->binds, SIGNAL(sig_stop_record_movie()), hRunEmu, SLOT(doStopRecordVideo()));
+               //connect(action_SaveAsMovie[i]->binds, SIGNAL(sig_stop_saving_movie()), hSaveMovieThread, SLOT(do_close()));
+       }
+       //connect(action_StopSavingMovie->binds, SIGNAL(sig_start_save_as_movie(QString, int)), hSaveMovieThread, SLOT(do_open(QString, int)));
+       //connect(action_StopSavingMovie->binds, SIGNAL(sig_start_record_movie(int)), hRunEmu, SLOT(doStartRecordVideo(int)));
+       connect(action_StopSavingMovie->binds, SIGNAL(sig_stop_record_movie()), hRunEmu, SLOT(doStopRecordVideo()));
+       connect(action_StopSavingMovie->binds, SIGNAL(sig_stop_saving_movie()), hSaveMovieThread, SLOT(do_close()));
+       connect(action_StopSavingMovie, SIGNAL(triggered()), action_StopSavingMovie->binds, SLOT(do_stop_saving_movie()));
+
+   
+
+       connect(emu->get_osd(), SIGNAL(sig_enqueue_audio(QByteArray *)), hSaveMovieThread, SLOT(enqueue_audio(QByteArray *)));
+       connect(emu->get_osd(), SIGNAL(sig_enqueue_video(QByteArray *, int, int)), hSaveMovieThread, SLOT(enqueue_video(QByteArray *, int, int)));
+       connect(this, SIGNAL(sig_quit_movie_thread()), hSaveMovieThread, SLOT(do_exit()));
+
+       objNameStr = QString("EmuMovieThread");
+       hSaveMovieThread->setObjectName(objNameStr);
+       hSaveMovieThread->start();
+       AGAR_DebugLog(AGAR_LOG_DEBUG, "MovieThread : Launch done.");
        
        hRunEmu->start();
        AGAR_DebugLog(AGAR_LOG_DEBUG, "EmuThread : Launch done.");
@@ -362,8 +411,14 @@ void Ui_MainWindow::OnMainWindowClosed(void)
        emit quit_draw_thread();
        emit quit_joy_thread();
        emit quit_emu_thread();
+       emit sig_quit_movie_thread();
        emit sig_quit_widgets();
        
+       if(hSaveMovieThread != NULL) {
+               hSaveMovieThread->wait();
+               delete hSaveMovieThread;
+       }
+   
        if(hDrawEmu != NULL) {
                hDrawEmu->wait();
                delete hDrawEmu;
index fe3a80c..c0e22c6 100644 (file)
@@ -119,8 +119,8 @@ add_library(CSPgui SHARED
 )
 
 set_target_properties(CSPgui PROPERTIES 
-                            SOVERSION 1.2.0
-                            VERSION 1.2.0
+                            SOVERSION 1.2.1
+                            VERSION 1.2.1
                             )
 INSTALL(TARGETS CSPgui DESTINATION ${LIBCSP_INSTALL_DIR})
 endif()
index f43ae9f..a9a737d 100644 (file)
@@ -195,6 +195,15 @@ public slots:
    
        bool isWriteProtect(void) { return write_protect; }
        void setWriteProtect(bool b) {write_protect = b;}
+public slots:
+       void do_save_as_movie(void);
+       void do_stop_saving_movie(void);
+
+signals:
+       int sig_save_as_movie(QString, int);
+       int sig_stop_record_movie();
+       int sig_start_record_movie(int);
+       int sig_stop_saving_movie();
 } Object_Menu_Control ;
 
 typedef class Action_Control: public QAction {
index 22f3b44..b6e3946 100644 (file)
 #include "qt_main.h"
 #define _MAX_DEBUGGER 8
 
+enum {
+       CSP_MAINWIDGET_SAVE_MOVIE_STOP = 0,
+       CSP_MAINWIDGET_SAVE_MOVIE_15FPS = 1,
+       CSP_MAINWIDGET_SAVE_MOVIE_24FPS,
+       CSP_MAINWIDGET_SAVE_MOVIE_30FPS,
+       CSP_MAINWIDGET_SAVE_MOVIE_60FPS,
+       CSP_MAINWIDGET_SAVE_MOVIE_END,
+};
+
 QT_BEGIN_NAMESPACE
 
 class Ui_SoundDialog;
@@ -63,6 +72,7 @@ class Menu_BinaryClass;
 class Menu_BubbleClass;
 class Menu_CompactDiscClass;
 class USING_FLAGS;
+class MOVIE_SAVER;
 
 extern         USING_FLAGS *using_flags;
 
@@ -288,6 +298,11 @@ class Ui_MainWindowBase : public QMainWindow
        // Emulator
        class Action_Control *action_SetupJoystick;
        class Action_Control *action_SetupKeyboard;
+
+       QMenu *menuSaveAsMovie;
+       class Action_Control *action_SaveAsMovie[4]; // 15, 24, 30, 60
+       class Action_Control *action_StopSavingMovie;
+       QActionGroup *actionGroup_SaveAsMovie;
        
        // Menus    
        QMenu *menuControl;
@@ -372,6 +387,7 @@ class Ui_MainWindowBase : public QMainWindow
        class EmuThreadClass *hRunEmu;
        class DrawThreadClass *hDrawEmu;
        class JoyThreadClass *hRunJoy;
+       class MOVIE_SAVER *hSaveMovieThread;
 public:
        Ui_MainWindowBase(QWidget *parent = 0);
        ~Ui_MainWindowBase();
@@ -422,10 +438,8 @@ public slots:
        virtual void delete_joy_thread(void);
        virtual void do_set_window_title(QString s);
        virtual void redraw_status_bar(void);
-//#ifdef USE_LED_DEVICE
        virtual void redraw_leds(void);
        void do_recv_data_led(quint32 d);
-//#endif
 
        void do_update_volume(int level);
        void set_screen_aspect(int num);
@@ -563,12 +577,14 @@ public slots:
        void set_printer_device(int);
        void do_show_about(void);
        void do_browse_document(QString);
+   
 signals:
        int message_changed(QString);
        int quit_emu_thread();
        int call_joy_thread(EMU *);
        int quit_joy_thread();
        int quit_draw_thread();
+       int sig_quit_movie_thread();
        int on_boot_mode(int);
        int on_cpu_type(int);
        int on_cpu_power(int);
@@ -623,6 +639,7 @@ signals:
        int sig_led_update(QRectF);
        int sig_start_auto_key(QString);
        int sig_stop_auto_key(void);
+   
        int quit_debugger_thread(void);
        int sig_quit_widgets(void);
 };
index c5ae003..47f9571 100644 (file)
@@ -483,7 +483,7 @@ void Ui_MainWindowBase::setupUi(void)
 
 void Ui_MainWindowBase::retranslateEmulatorMenu(void)
 {
-
+       int i;
        menuEmulator->setTitle(QApplication::translate("MainWindow", "Emulator", 0));
        if(using_flags->is_use_joystick()) {
                action_SetupJoystick->setText(QApplication::translate("MainWindow", "Configure Joysticks", 0));
@@ -491,21 +491,78 @@ void Ui_MainWindowBase::retranslateEmulatorMenu(void)
        }
        action_SetupKeyboard->setText(QApplication::translate("MainWindow", "Configure Keyboard", 0));
        action_SetupKeyboard->setIcon(QIcon(":/icon_keyboard.png"));
+       for(int i = 0; i < (CSP_MAINWIDGET_SAVE_MOVIE_END - 1); i++) {
+               switch(i + 1) {
+                       case CSP_MAINWIDGET_SAVE_MOVIE_15FPS:
+                               action_SaveAsMovie[i]->setText(QApplication::translate("MainWindow", "15fps", 0));
+                               break;
+                       case CSP_MAINWIDGET_SAVE_MOVIE_24FPS:
+                               action_SaveAsMovie[i]->setText(QApplication::translate("MainWindow", "24fps", 0));
+                               break;
+                       case CSP_MAINWIDGET_SAVE_MOVIE_30FPS:
+                               action_SaveAsMovie[i]->setText(QApplication::translate("MainWindow", "30fps", 0));
+                               break;
+                       case CSP_MAINWIDGET_SAVE_MOVIE_60FPS:
+                               action_SaveAsMovie[i]->setText(QApplication::translate("MainWindow", "60fps", 0));
+                               break;
+               }
+       }
+       action_StopSavingMovie->setText(QApplication::translate("MainWindow", "Stop Recording", 0));
+       action_StopSavingMovie->setIcon(QIcon(":/icon_process_stop.png"));
+       menuSaveAsMovie->setTitle(QApplication::translate("MainWindow", "Record to Movie", 0));
 }
+
 void Ui_MainWindowBase::CreateEmulatorMenu(void)
 {
        if(using_flags->is_use_joystick()) {
                menuEmulator->addAction(action_SetupJoystick);
        }
        menuEmulator->addAction(action_SetupKeyboard);
+       menuEmulator->addAction(menuSaveAsMovie->menuAction());
 }
 
 void Ui_MainWindowBase::ConfigEmulatorMenu(void)
 {
+       int i;
+       QString tmps;
        if(using_flags->is_use_joystick()) {
                action_SetupJoystick = new Action_Control(this);
        }
        action_SetupKeyboard = new Action_Control(this);
+
+       menuSaveAsMovie = new QMenu(this);
+       actionGroup_SaveAsMovie = new QActionGroup(this);
+       for(int i = 0; i < (CSP_MAINWIDGET_SAVE_MOVIE_END - 1); i++) {
+               action_SaveAsMovie[i] = new Action_Control(menuSaveAsMovie);
+               switch(i + 1) {
+                       case CSP_MAINWIDGET_SAVE_MOVIE_15FPS:
+                               tmps.setNum(15);
+                               action_SaveAsMovie[i]->binds->setNumber(15);
+                               break;
+                       case CSP_MAINWIDGET_SAVE_MOVIE_24FPS:
+                               tmps.setNum(24);
+                               action_SaveAsMovie[i]->binds->setNumber(24);
+                               break;
+                       case CSP_MAINWIDGET_SAVE_MOVIE_30FPS:
+                               tmps.setNum(30);
+                               action_SaveAsMovie[i]->binds->setNumber(30);
+                               break;
+                       case CSP_MAINWIDGET_SAVE_MOVIE_60FPS:
+                               tmps.setNum(60);
+                               action_SaveAsMovie[i]->binds->setNumber(60);
+                               break;
+               }
+               tmps = QString::fromUtf8("action_SaveAsMovie") + tmps;
+               action_SaveAsMovie[i]->setObjectName(tmps);
+               actionGroup_SaveAsMovie->addAction(action_SaveAsMovie[i]);
+               menuSaveAsMovie->addAction(action_SaveAsMovie[i]);
+       }
+       action_StopSavingMovie = new Action_Control(menuSaveAsMovie);
+       action_StopSavingMovie->setObjectName(QString::fromUtf8("actionStopRecordingMovie"));
+       action_StopSavingMovie->binds->setNumber(0);
+       actionGroup_SaveAsMovie->addAction(action_StopSavingMovie);
+       menuSaveAsMovie->addAction(action_StopSavingMovie);
+  
 }
 
 void Ui_MainWindowBase::rise_joystick_dialog(void)
index 6c53c44..c4e4433 100644 (file)
@@ -78,6 +78,11 @@ void OSD_BASE::restore()
        }
 }
 
+_TCHAR *OSD_BASE::get_app_path(void)
+{
+       return app_path;
+}
+
 _TCHAR* OSD_BASE::bios_path(const _TCHAR* file_name)
 {
        static _TCHAR file_path[_MAX_PATH];
index 95f6cb7..9ec76e8 100644 (file)
@@ -281,7 +281,7 @@ public:
        void get_host_time(cur_time_t* time);
        void sleep(uint32_t ms);
        void create_date_file_name(_TCHAR *name, int length, const _TCHAR *extension);
-       
+       _TCHAR  *get_app_path(void);
        // common console
        void open_console(_TCHAR* title);
        void close_console();
index 2c3b13e..b6148de 100644 (file)
@@ -185,6 +185,7 @@ bool OSD_BASE::start_record_video(int fps)
                rec_video_fps = fps;
                rec_video_run_frames = rec_video_frames = 0;
        }
+
 #if 0  
        bool show_dialog = (fps > 0);
        
index 3e3016e..8904b8f 100644 (file)
@@ -204,54 +204,56 @@ void OSD_BASE::update_sound(int* extra_frames)
                //SDL_UnlockAudio();
                // sound buffer must be updated
                Sint16* sound_buffer = (Sint16 *)this->create_sound(extra_frames);
-               if(now_record_video) {
-                       if(sound_samples > rec_sound_buffer_ptr) {
-                               int samples = sound_samples - rec_sound_buffer_ptr;
-                               int length = samples * sizeof(int16_t) * 2; // stereo
-                               //QByteArray *p = new QByteArray((const char *)sound_buffer + rec_sound_buffer_ptr * 2, length);
-                               //emit sig_enqueue_audio(p);
+               if(now_record_sound || now_record_video) {
+                       int samples = sound_samples - rec_sound_buffer_ptr;
+                       int length = samples * sizeof(int16_t) * 2; // stereo
+                       if(now_record_video) {
+                               if(sound_samples > rec_sound_buffer_ptr) {
+                                       QByteArray *p = new QByteArray((const char *)sound_buffer + rec_sound_buffer_ptr * 2, length);
+                                       emit sig_enqueue_audio(p);
+                               }
                        }
-               }
-               if(now_record_sound) {
                        // record sound
-                       if(sound_samples > rec_sound_buffer_ptr) {
-                               int samples = sound_samples - rec_sound_buffer_ptr;
-                               int length = samples * sizeof(int16_t) * 2; // stereo
-                               rec_sound_fio->Fwrite(sound_buffer + rec_sound_buffer_ptr * 2, length, 1);
-                               rec_sound_bytes += length;
-#if 0                          
-                               if(now_record_video) {
-                                       // sync video recording
-                                       static double frames = 0;
-                                       static int prev_samples = -1;
-                                       if(this->get_support_variable_timing()) {
-                                               static double prev_fps = -1;
-                                               double fps = this->vm_frame_rate();
-                                               if(prev_samples != samples || prev_fps != fps) {
-                                                       prev_samples = samples;
-                                                       prev_fps = fps;
-                                                       frames = fps * (double)samples / (double)sound_rate;
-                                               }
-                                       } else {
-                                               if(prev_samples != samples) {
-                                                       prev_samples = samples;
-                                                       frames = vm_frame_rate() * (double)samples / (double)sound_rate;
-                                               }
+                       if(now_record_sound) {
+                               if(sound_samples > rec_sound_buffer_ptr) {
+                                       rec_sound_fio->Fwrite(sound_buffer + rec_sound_buffer_ptr * 2, length, 1);
+                                       rec_sound_bytes += length;
+                               }
+                       }
+                  
+#if 1                          
+                       if(now_record_video) {
+                               // sync video recording
+                               static double frames = 0;
+                               static int prev_samples = -1;
+                               if(this->get_support_variable_timing()) {
+                                       static double prev_fps = -1;
+                                       double fps = this->vm_frame_rate();
+                                       if(prev_samples != samples || prev_fps != fps) {
+                                               prev_samples = samples;
+                                               prev_fps = fps;
+                                               frames = fps * (double)samples / (double)sound_rate;
                                        }
-                                       rec_video_frames -= frames;
-                                       if(rec_video_frames > 2) {
-                                               rec_video_run_frames -= (rec_video_frames - 2);
-                                       } else if(rec_video_frames < -2) {
-                                               rec_video_run_frames -= (rec_video_frames + 2);
+                               } else {
+                                       if(prev_samples != samples) {
+                                               prev_samples = samples;
+                                               frames = vm_frame_rate() * (double)samples / (double)sound_rate;
                                        }
-//                                     rec_video_run_frames -= rec_video_frames;
                                }
-#endif                    
-//                             printf("Wrote %d samples\n", samples);
-                               rec_sound_buffer_ptr += samples;
-                               if(rec_sound_buffer_ptr >= sound_samples) rec_sound_buffer_ptr = 0;
+                               rec_video_frames -= frames;
+                               if(rec_video_frames > 2) {
+                                       rec_video_run_frames -= (rec_video_frames - 2);
+                               } else if(rec_video_frames < -2) {
+                                       rec_video_run_frames -= (rec_video_frames + 2);
+                               }
+//                     rec_video_run_frames -= rec_video_frames;
                        }
+#endif                    
+                       //printf("Wrote %d samples ptr=%d\n", samples, rec_sound_buffer_ptr);
+                       rec_sound_buffer_ptr += samples;
+                       if(rec_sound_buffer_ptr >= sound_samples) rec_sound_buffer_ptr = 0;
                }
+          
                
                if(sound_buffer) {
                        int ssize;
index 4c89605..673d919 100755 (executable)
@@ -7,7 +7,7 @@ LDCONFIG=/sbin/ldconfig
 CSP_ARCH="x86_64-linux-gnu"
 MULTIARCH="Yes"
 CSP_PREFIX=/usr/local
-CSP_GUILIB="libCSPgui.so.1.2.0 libCSPosd.so.1.1.1 libCSPemu_utils.so.1.0.0 libCSPavio.1.0.0"
+CSP_GUILIB="libCSPgui.so.1.2.1 libCSPosd.so.1.1.1 libCSPemu_utils.so.1.0.0 libCSPavio.1.0.0"
 
 for i in "$@"; do
   case "$1" in