From 98215cfb3006aed2861d640a9e585b2c844b5c9b Mon Sep 17 00:00:00 2001 From: squall-leonhart Date: Tue, 24 May 2011 07:39:29 +0000 Subject: [PATCH] buncha patches by darktjm sdl fix not applied yet --- CMakeLists.txt | 33 ++- fex/7z_C/CpuArch.c | 7 +- src/System.h | 2 +- src/Util.cpp | 1 + src/apu/Blip_Buffer.cpp | 2 +- src/apu/Gb_Oscs.h | 1 + src/common/ffmpeg.cpp | 468 +++++++++++++++++++++++++++++++++++++ src/common/ffmpeg.h | 79 +++++++ src/common/memgzio.c | 18 ++ src/common/memgzio.h | 1 + src/gb/GB.cpp | 4 + src/gb/gbPrinter.cpp | 7 +- src/gb/gbSGB.cpp | 2 +- src/gba/GBAcpu.h | 4 + src/gtk/system.cpp | 1 + src/sdl/SDL.cpp | 2 +- src/sdl/debugger.cpp | 12 +- src/win32/GBPrinterDlg.cpp | 2 + 18 files changed, 632 insertions(+), 14 deletions(-) create mode 100644 src/common/ffmpeg.cpp create mode 100644 src/common/ffmpeg.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a7c8403a..64867202 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,16 @@ option( ENABLE_ASM_CORE "Enable x86 ASM CPU cores" OFF ) option( ENABLE_ASM_SCALERS "Enable x86 ASM graphic filters" OFF ) option( ENABLE_LINK "Enable GBA linking functionality" OFF ) option( ENABLE_LIRC "Enable LIRC support" OFF ) +if(ENABLE_ASM_SCALERS) + option( ENABLE_MMX "Enable MMX" OFF ) +endif(ENABLE_ASM_SCALERS) +option( ENABLE_GBA_LOGGING "Enable extended GBA logging" ON ) +if( ENABLE_GBA_LOGGING ) + ADD_DEFINITIONS (-DGBA_LOGGING ) +endif( ENABLE_GBA_LOGGING ) +if(ENABLE_MMX) + ADD_DEFINITIONS (-DMMX) +endif(ENABLE_MMX) # The SDL port can't be built without debugging support if( NOT ENABLE_DEBUGGER AND ENABLE_SDL ) @@ -24,7 +34,13 @@ endif( NOT ENABLE_DEBUGGER AND ENABLE_SDL ) # Set the version number with -DVERSION=X.X.X-uber IF( NOT VERSION ) - SET( VERSION "1.8.0-SVN" ) + FIND_PACKAGE(Subversion) + IF(SUBVERSION_FOUND) + Subversion_WC_INFO(${CMAKE_CURRENT_SOURCE_DIR} SVN_INFO) + SET( VERSION "1.8.0-SVN${SVN_INFO_WC_REVISION}" ) + ELSE(SUBVERSION_FOUND) + SET( VERSION "1.8.0-SVN" ) + ENDIF(SUBVERSION_FOUND) ENDIF( NOT VERSION ) # Fill in SDLMAIN_LIBRARY on OS X manually to avoid using SDLMain.m @@ -62,6 +78,17 @@ IF( ENABLE_GTK ) PKG_CHECK_MODULES ( GTKGLMM REQUIRED gtkglextmm-x11-1.2 ) ENDIF( ENABLE_GTK ) +option( ENABLE_FFMPEG "Enable ffmpeg A/V recording" ON ) +if(ENABLE_FFMPEG) + FIND_PACKAGE ( PkgConfig REQUIRED ) + + PKG_CHECK_MODULES(FFMPEG REQUIRED libavcodec libavformat libswscale libavutil) +endif(ENABLE_FFMPEG) + +if(NOT ENABLE_FFMPEG) + ADD_DEFINITIONS(-DNO_FFMPEG) +endif(NOT ENABLE_FFMPEG) + IF( ENABLE_LIRC ) SET( WITHLIRC 1 ) ELSE( ENABLE_LIRC ) @@ -157,6 +184,10 @@ SET(SRC_MAIN src/common/memgzio.c ) +if(ENABLE_FFMPEG) + SET(SRC_MAIN ${SRC_MAIN} src/common/ffmpeg.cpp) +endif(ENABLE_FFMPEG) + SET(SRC_GBA src/gba/agbprint.cpp src/gba/bios.cpp diff --git a/fex/7z_C/CpuArch.c b/fex/7z_C/CpuArch.c index 260cc1f4..e7d7ad2d 100644 --- a/fex/7z_C/CpuArch.c +++ b/fex/7z_C/CpuArch.c @@ -72,13 +72,18 @@ static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) #else + // Mac cross-compile compiler: + // can't find register in class 'BREG' while reloading 'asm' + // so use class 'r' and register var binding + register _b asm("%bx"); __asm__ __volatile__ ( "cpuid" : "=a" (*a) , - "=b" (*b) , + "=r" (_b) , "=c" (*c) , "=d" (*d) : "0" (function)) ; + *b = _b; #endif diff --git a/src/System.h b/src/System.h index 9c1b384a..f23821d8 100644 --- a/src/System.h +++ b/src/System.h @@ -41,7 +41,7 @@ struct EmulatedSystem { extern void log(const char *,...); extern bool systemPauseOnFrame(); -extern void systemGbPrint(u8 *,int,int,int,int); +extern void systemGbPrint(u8 *,int,int,int,int,int); extern void systemScreenCapture(int); extern void systemDrawScreen(); // updates the joystick data diff --git a/src/Util.cpp b/src/Util.cpp index 5ca4d0f3..c77ff256 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -598,6 +598,7 @@ gzFile utilMemGzOpen(char *memory, int available, const char *mode) utilGzWriteFunc = memgzwrite; utilGzReadFunc = memgzread; utilGzCloseFunc = memgzclose; + utilGzSeekFunc = memgzseek; return memgzopen(memory, available, mode); } diff --git a/src/apu/Blip_Buffer.cpp b/src/apu/Blip_Buffer.cpp index 3b2dda93..098ab578 100644 --- a/src/apu/Blip_Buffer.cpp +++ b/src/apu/Blip_Buffer.cpp @@ -29,7 +29,7 @@ int const silent_buf_size = 1; // size used for Silent_Blip_Buffer Blip_Buffer::Blip_Buffer() { - factor_ = LONG_MAX; + factor_ = (blip_ulong)LONG_MAX; buffer_ = 0; buffer_size_ = 0; sample_rate_ = 0; diff --git a/src/apu/Gb_Oscs.h b/src/apu/Gb_Oscs.h index 175127b9..52459bea 100644 --- a/src/apu/Gb_Oscs.h +++ b/src/apu/Gb_Oscs.h @@ -50,6 +50,7 @@ public: class Gb_Env : public Gb_Osc { public: + Gb_Env() : env_enabled(false), env_delay(0) {} int env_delay; int volume; bool env_enabled; diff --git a/src/common/ffmpeg.cpp b/src/common/ffmpeg.cpp new file mode 100644 index 00000000..b98cdafa --- /dev/null +++ b/src/common/ffmpeg.cpp @@ -0,0 +1,468 @@ +// this code has been partially lifted from the output-example.c program in +// libavformat. Not much of that original code remains. + +// unlike the rest of the wx code, this has no wx dependency at all, and +// could be used by other front ends as well. + +#define __STDC_LIMIT_MACROS // required for ffmpeg +#define __STDC_CONSTANT_MACROS // required for ffmpeg + +#include "../gba/Sound.h" +extern "C" { +#include +#include +#include +#ifndef AV_PKT_FLAG_KEY +#define AV_PKT_FLAG_KEY PKT_FLAG_KEY +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(52,96,0) +// note that there is no sane way to easily free a context w/o free_context() +// so this will probably leak +static void avformat_free_context(AVFormatContext *ctx) +{ + if(ctx->pb) + url_fclose(ctx->pb); + for(int i = 0; i < ctx->nb_streams; i++) { + if(ctx->streams[i]->codec) + avcodec_close(ctx->streams[i]->codec); + av_freep(&ctx->streams[i]->codec); + av_freep(&ctx->streams[i]); + } + av_free(ctx); +} +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(52,45,0) +#define av_guess_format guess_format +#endif +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(52,105,0) +#define avio_open url_fopen +#define avio_close url_fclose +#endif +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52,64,0) +#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO +#define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO +#endif +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(50,1,0) +// this will almost definitely fail on big-endian systems +#define PIX_FMT_RGB565LE PIX_FMT_RGB565 +#endif +#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52,38,0) +#define AV_SAMPLE_FMT_S16 SAMPLE_FMT_S16 +#endif +} + +#define priv_AVFormatContext AVFormatContext +#define priv_AVStream AVStream +#define priv_AVOutputFormat AVOutputFormat +#define priv_AVFrame AVFrame +#define priv_SwsContext SwsContext +#define priv_PixelFormat PixelFormat +#include "ffmpeg.h" + +// I have no idea what size to make these buffers +// I don't see any ffmpeg functions to guess the size, either + +// use frame size, or FF_MIN_BUFFER_SIZE (that seems to be what it wants) +#define AUDIO_BUF_LEN (frame_len > FF_MIN_BUFFER_SIZE ? frame_len : FF_MIN_BUFFER_SIZE) +// use maximum frame size * 32 bpp * 2 for good measure +#define VIDEO_BUF_LEN (FF_MIN_BUFFER_SIZE + 256 * 244 * 4 * 2) + +bool MediaRecorder::did_init = false; + +MediaRecorder::MediaRecorder() : oc(0), vid_st(0), aud_st(0), video_buf(0), + audio_buf(0), audio_buf2(0), converter(0), convpic(0) +{ + if(!did_init) { + did_init = true; + av_register_all(); + } + pic = avcodec_alloc_frame(); +} + +MediaRet MediaRecorder::setup_sound_stream(const char *fname, AVOutputFormat *fmt) +{ + oc = avformat_alloc_context(); + if(!oc) + return MRET_ERR_NOMEM; + oc->oformat = fmt; + strncpy(oc->filename, fname, sizeof(oc->filename) - 1); + oc->filename[sizeof(oc->filename) - 1] = 0; + if(fmt->audio_codec == CODEC_ID_NONE) + return MRET_OK; + + AVCodecContext *ctx; + aud_st = av_new_stream(oc, 1); + if(!aud_st) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOMEM; + } + ctx = aud_st->codec; + ctx->codec_id = fmt->audio_codec; + ctx->codec_type = AVMEDIA_TYPE_AUDIO; + ctx->sample_fmt = AV_SAMPLE_FMT_S16; + ctx->bit_rate = 128000; // arbitrary; in case we're generating mp3 + ctx->sample_rate = soundGetSampleRate(); + ctx->channels = 2; + ctx->time_base.den = 60; + ctx->time_base.num = 1; + if(fmt->flags & AVFMT_GLOBALHEADER) + ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + + AVCodec *codec = avcodec_find_encoder(fmt->audio_codec); + if(!codec || avcodec_open(ctx, codec)) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOCODEC; + } + + return MRET_OK; +} + +MediaRet MediaRecorder::setup_video_stream(const char *fname, int w, int h, int d) +{ + AVCodecContext *ctx; + vid_st = av_new_stream(oc, 0); + if(!vid_st) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOMEM; + } + ctx = vid_st->codec; + ctx->codec_id = oc->oformat->video_codec; + ctx->codec_type = AVMEDIA_TYPE_VIDEO; + ctx->width = w; + ctx->height = h; + ctx->time_base.den = 60; + ctx->time_base.num = 1; + // dunno if any of these help; some output just looks plain crappy + // will have to investigate further + ctx->bit_rate = 400000; + ctx->gop_size = 12; + ctx->max_b_frames = 2; + switch(d) { + case 16: + // FIXME: test & make endian-neutral + pixfmt = PIX_FMT_RGB565LE; + break; + case 24: + pixfmt = PIX_FMT_RGB24; + break; + case 32: + default: // should never be anything else + pixfmt = PIX_FMT_RGBA; + break; + } + ctx->pix_fmt = pixfmt; + pixsize = d >> 3; + linesize = pixsize * w; + ctx->max_b_frames = 2; + if(oc->oformat->flags & AVFMT_GLOBALHEADER) + ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + + AVCodec *codec = avcodec_find_encoder(oc->oformat->video_codec); + // make sure RGB is supported (mostly not) + if(codec->pix_fmts) { + const enum PixelFormat *p; + int64_t mask = 0; + for(p = codec->pix_fmts; *p != -1; p++) { + // may get complaints about 1LL; thus the cast + mask |= ((int64_t)1) << *p; + if(*p == pixfmt) + break; + } + if(*p == -1) { + // if not supported, use a converter to the next best format + // this is swscale, the converter used by the output demo + enum PixelFormat dp = (PixelFormat)avcodec_find_best_pix_fmt(mask, pixfmt, 0, NULL); + if(dp == -1) + dp = codec->pix_fmts[0]; + if(!(convpic = avcodec_alloc_frame()) || + avpicture_alloc((AVPicture *)convpic, dp, w, h) < 0) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOMEM; + } +#if LIBSWSCALE_VERSION_INT < AV_VERSION_INT(0, 12, 0) + converter = sws_getContext(w, h, pixfmt, w, h, dp, SWS_BICUBIC, + NULL, NULL, NULL); +#else + converter = sws_alloc_context(); + // what a convoluted, inefficient way to set options + av_set_int(converter, "sws_flags", SWS_BICUBIC); + av_set_int(converter, "srcw", w); + av_set_int(converter, "srch", h); + av_set_int(converter, "dstw", w); + av_set_int(converter, "dsth", h); + av_set_int(converter, "src_format", pixfmt); + av_set_int(converter, "dst_format", dp); + sws_init_context(converter, NULL, NULL); +#endif + ctx->pix_fmt = dp; + } + } + if(!codec || avcodec_open(ctx, codec)) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOCODEC; + } + + return MRET_OK; +} + +MediaRet MediaRecorder::finish_setup(const char *fname) +{ + if(av_set_parameters(oc, NULL) < 0) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOCODEC; + } + if(audio_buf) + free(audio_buf); + if(audio_buf2) + free(audio_buf2); + audio_buf2 = NULL; + in_audio_buf2 = 0; + if(aud_st) { + frame_len = aud_st->codec->frame_size * 4; + sample_len = soundGetSampleRate() * 4 / 60; + switch(aud_st->codec->codec_id) { + case CODEC_ID_PCM_S16LE: + case CODEC_ID_PCM_S16BE: + case CODEC_ID_PCM_U16LE: + case CODEC_ID_PCM_U16BE: + frame_len = sample_len; + } + audio_buf = (u8 *)malloc(AUDIO_BUF_LEN); + if(!audio_buf) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOMEM; + } + if(frame_len != sample_len && (frame_len > sample_len || sample_len % frame_len)) { + audio_buf2 = (u16 *)malloc(frame_len); + if(!audio_buf2) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOMEM; + } + } + } else + audio_buf = NULL; + if(video_buf) + free(video_buf); + if(vid_st) { + video_buf = (u8 *)malloc(VIDEO_BUF_LEN); + if(!video_buf) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_NOMEM; + } + } else { + video_buf = NULL; + } + if(!(oc->oformat->flags & AVFMT_NOFILE)) { + if(avio_open(&oc->pb, fname, URL_WRONLY) < 0) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_FERR; + } + } + av_write_header(oc); + return MRET_OK; +} + +MediaRet MediaRecorder::Record(const char *fname, int width, int height, int depth) +{ + if(oc) + return MRET_ERR_RECORDING; + aud_st = vid_st = NULL; + AVOutputFormat *fmt = av_guess_format(NULL, fname, NULL); + if(!fmt) + fmt = av_guess_format("avi", NULL, NULL); + if(!fmt || fmt->video_codec == CODEC_ID_NONE) + return MRET_ERR_FMTGUESS; + MediaRet ret; + if((ret = setup_sound_stream(fname, fmt)) == MRET_OK && + (ret = setup_video_stream(fname, width, height, depth)) == MRET_OK) + ret = finish_setup(fname); + return ret; +} + +MediaRet MediaRecorder::Record(const char *fname) +{ + if(oc) + return MRET_ERR_RECORDING; + aud_st = vid_st = NULL; + AVOutputFormat *fmt = av_guess_format(NULL, fname, NULL); + if(!fmt) + fmt = av_guess_format("wav", NULL, NULL); + if(!fmt || fmt->audio_codec == CODEC_ID_NONE) + return MRET_ERR_FMTGUESS; + MediaRet ret; + if((ret = setup_sound_stream(fname, fmt)) == MRET_OK) + ret = finish_setup(fname); + return ret; +} + +void MediaRecorder::Stop() +{ + if(oc) { + if(in_audio_buf2) + AddFrame((u16 *)0); + av_write_trailer(oc); + avformat_free_context(oc); + oc = NULL; + } + if(audio_buf) { + free(audio_buf); + audio_buf = NULL; + } + if(video_buf) { + free(video_buf); + video_buf = NULL; + } + if(audio_buf2) { + free(audio_buf2); + audio_buf2 = NULL; + } + if(convpic) { + avpicture_free((AVPicture *)convpic); + av_free(convpic); + convpic = NULL; + } + if(converter) { + sws_freeContext(converter); + converter = NULL; + } +} + +MediaRecorder::~MediaRecorder() +{ + Stop(); +} + +MediaRet MediaRecorder::AddFrame(const u8 *vid) +{ + if(!oc || !vid_st) + return MRET_OK; + + AVCodecContext *ctx = vid_st->codec; + AVPacket pkt; + + // strip borders. inconsistent between depths for some reason + // but fortunately consistent between gb/gba. + int tbord, rbord; + switch(pixsize) { + case 2: + // 16-bit: 2 @ right, 1 @ top + tbord = 1; rbord = 2; break; + case 3: + // 24-bit: no border + tbord = rbord = 0; break; + case 4: + // 32-bit: 1 @ right, 1 @ top + tbord = 1; rbord = 1; break; + } + avpicture_fill((AVPicture *)pic, (uint8_t *)vid + tbord * (linesize + pixsize * rbord), + (PixelFormat)pixfmt, ctx->width + rbord, ctx->height); + // satisfy stupid sws_scale()'s integrity check + pic->data[1] = pic->data[2] = pic->data[3] = pic->data[0]; + pic->linesize[1] = pic->linesize[2] = pic->linesize[3] = pic->linesize[0]; + + AVFrame *f = pic; + + if(converter) { + sws_scale(converter, pic->data, pic->linesize, 0, ctx->height, + convpic->data, convpic->linesize); + f = convpic; + } + av_init_packet(&pkt); + pkt.stream_index = vid_st->index; + if(oc->oformat->flags & AVFMT_RAWPICTURE) { + // this won't work due to border + // not sure what formats set this, anyway + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.data = f->data[0]; + pkt.size = linesize * ctx->height; + } else { + pkt.size = avcodec_encode_video(ctx, video_buf, VIDEO_BUF_LEN, f); + if(!pkt.size) + return MRET_OK; + if(ctx->coded_frame && ctx->coded_frame->pts != AV_NOPTS_VALUE) + pkt.pts = av_rescale_q(ctx->coded_frame->pts, ctx->time_base, vid_st->time_base); + if(pkt.size > VIDEO_BUF_LEN) { + avformat_free_context(oc); + oc = NULL; + return MRET_ERR_BUFSIZE; + } + if(ctx->coded_frame->key_frame) + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.data = video_buf; + } + if(av_interleaved_write_frame(oc, &pkt) < 0) { + avformat_free_context(oc); + oc = NULL; + // yeah, err might not be a file error, but if it isn't, it's a + // coding error rather than a user-controllable error + // and better resolved using debugging + return MRET_ERR_FERR; + } + return MRET_OK; +} + +MediaRet MediaRecorder::AddFrame(const u16 *aud) +{ + if(!oc || !aud_st) + return MRET_OK; + // aud == NULL means just flush out last frame + if(!aud && !in_audio_buf2) + return MRET_OK; + AVCodecContext *ctx = aud_st->codec; + AVPacket pkt; + + int len = sample_len; + if(in_audio_buf2) { + int ncpy = frame_len - in_audio_buf2; + if(ncpy > len) + ncpy = len; + if(aud) { + memcpy(audio_buf2 + in_audio_buf2/2, aud, ncpy); + len -= ncpy; + aud += ncpy / 2; + } else { + memset(audio_buf2 + in_audio_buf2/2, 0, ncpy); + len = 0; + } + in_audio_buf2 += ncpy; + } + while(len + in_audio_buf2 >= frame_len) { + av_init_packet(&pkt); + pkt.size = avcodec_encode_audio(ctx, audio_buf, frame_len, + (const short *)(in_audio_buf2 ? audio_buf2 : aud)); + if(ctx->coded_frame && ctx->coded_frame->pts != AV_NOPTS_VALUE) + pkt.pts = av_rescale_q(ctx->coded_frame->pts, ctx->time_base, aud_st->time_base); + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.stream_index = aud_st->index; + pkt.data = audio_buf; + if(av_interleaved_write_frame(oc, &pkt) < 0) { + avformat_free_context(oc); + oc = NULL; + // yeah, err might not be a file error, but if it isn't, it's a + // coding error rather than a user-controllable error + // and better resolved using debugging + return MRET_ERR_FERR; + } + if(in_audio_buf2) + in_audio_buf2 = 0; + else { + aud += frame_len / 2; + len -= frame_len; + } + } + if(len > 0) { + memcpy(audio_buf2, aud, len); + in_audio_buf2 = len; + } + return MRET_OK; +} diff --git a/src/common/ffmpeg.h b/src/common/ffmpeg.h new file mode 100644 index 00000000..f27bb3d7 --- /dev/null +++ b/src/common/ffmpeg.h @@ -0,0 +1,79 @@ +#ifndef WX_FFMPEG_H +#define WX_FFMPEG_H + +// simplified interface for recording audio and/or video from emulator + +// unlike the rest of the wx code, this has no wx dependency at all, and +// could be used by other front ends as well. + +// this only supports selecting output format via file name extensions; +// maybe some future version will support specifying a format. wx-2.9 +// has an extra widget for the file selector, but 2.8 doesn't. + +// the only missing piece that I couldn't figure out how to do generically +// is the code to find the available formats & associated extensions for +// the file dialog. + +#include "../common/Types.h" + +// return codes +// probably ought to put in own namespace, but this is good enough +enum MediaRet { + MRET_OK, // no errors + MRET_ERR_NOMEM, // error allocating buffers or structures + MRET_ERR_NOCODEC, // error opening codec + MRET_ERR_FERR, // error writing output file + MRET_ERR_RECORDING, // attempt to start recording when already doing it + MRET_ERR_FMTGUESS, // can't guess format from file name + MRET_ERR_BUFSIZE // buffer overflow (fatal) +}; + +class MediaRecorder +{ +public: + MediaRecorder(); + virtual ~MediaRecorder(); + + // start audio+video (also video-only codecs) + MediaRet Record(const char *fname, int width, int height, int depth); + // start audio only + MediaRet Record(const char *fname); + // stop both + void Stop(); + bool IsRecording() { return oc != NULL; } + // add a frame of video; width+height+depth already given + // assumes a 1-pixel border on top & right + // always assumes being passed 1/60th of a second of video + MediaRet AddFrame(const u8 *vid); + // add a frame of audio; uses current sample rate to know length + // always assumes being passed 1/60th of a second of audio. + MediaRet AddFrame(const u16 *aud); + +private: + static bool did_init; + + // these are to avoid polluting things with avcodec includes +#ifndef priv_AVFormatContext +#define priv_AVFormatContext void +#define priv_AVStream void +#define priv_AVOutputFormat void +#define priv_AVFrame void +#define priv_SwsContext void +#define priv_PixelFormat int +#endif + priv_AVFormatContext *oc; + priv_AVStream *vid_st, *aud_st; + u8 *audio_buf, *video_buf; + u16 *audio_buf2; + int frame_len, sample_len, in_audio_buf2; + int linesize, pixsize; + priv_PixelFormat pixfmt; + priv_AVFrame *pic, *convpic; + priv_SwsContext *converter; + + MediaRet setup_sound_stream(const char *fname, priv_AVOutputFormat *fmt); + MediaRet setup_video_stream(const char *fname, int w, int h, int d); + MediaRet finish_setup(const char *fname); +}; + +#endif /* WX_FFMPEG_H */ diff --git a/src/common/memgzio.c b/src/common/memgzio.c index 4d0ebb32..558a2d05 100644 --- a/src/common/memgzio.c +++ b/src/common/memgzio.c @@ -697,3 +697,21 @@ long ZEXPORT memtell(file) return memTell(s->file); } + +long ZEXPORT memgzseek(gzFile file, long off, int whence) +{ + if(whence != SEEK_CUR) { + fputs("FIXME: memgzio does not support seeking\n", stderr); + exit(1); + } + // this is inefficient, but the best I can do without actually reading + // the above code + char buf[80]; + while(off > 0) { + int r = memgzread(file, buf, off > 80 ? 80 : off); + if(r <= 0) + return -1; + off -= r; + } + return memtell(file); +} diff --git a/src/common/memgzio.h b/src/common/memgzio.h index e1f69b05..1e56e44d 100644 --- a/src/common/memgzio.h +++ b/src/common/memgzio.h @@ -19,5 +19,6 @@ int ZEXPORT memgzread(gzFile file, voidp buf, unsigned len); int ZEXPORT memgzwrite(gzFile file, const voidp buf, unsigned len); int ZEXPORT memgzclose(gzFile file); long ZEXPORT memtell(gzFile file); +long ZEXPORT memgzseek(gzFile file, long offset, int whence); #endif // MEMGZIO_H diff --git a/src/gb/GB.cpp b/src/gb/GB.cpp index 2f9cdcca..2258526a 100644 --- a/src/gb/GB.cpp +++ b/src/gb/GB.cpp @@ -4976,6 +4976,8 @@ void gbEmulate(int ticksToStop) gbSgbRenderBorder(); //if (gbScreenOn) systemDrawScreen(); + if(systemPauseOnFrame()) + ticksToStop = 0; } gbFrameSkipCount = 0; } else @@ -5160,6 +5162,8 @@ void gbEmulate(int ticksToStop) gbSgbRenderBorder(); //if (gbScreenOn) systemDrawScreen(); + if(systemPauseOnFrame()) + ticksToStop = 0; } } if(systemReadJoypads()) { diff --git a/src/gb/gbPrinter.cpp b/src/gb/gbPrinter.cpp index 4bbac899..82843f29 100644 --- a/src/gb/gbPrinter.cpp +++ b/src/gb/gbPrinter.cpp @@ -38,6 +38,7 @@ void gbPrinterReset() void gbPrinterShowData() { systemGbPrint(gbPrinterData, + gbPrinterDataCount, gbPrinterPacket[6], gbPrinterPacket[7], gbPrinterPacket[8], @@ -87,6 +88,7 @@ void gbPrinterShowData() void gbPrinterReceiveData() { + int i = gbPrinterDataCount; if(gbPrinterPacket[3]) { // compressed u8 *data = &gbPrinterPacket[6]; u8 *dest = &gbPrinterData[gbPrinterDataCount]; @@ -97,16 +99,17 @@ void gbPrinterReceiveData() control &= 0x7f; control += 2; memset(dest, *data++, control); - len += control; + len += 2; dest += control; } else { // raw data control++; memcpy(dest, data, control); dest += control; data += control; - len += control; + len += control + 1; } } + gbPrinterDataCount = (int)(dest - gbPrinterData); } else { memcpy(&gbPrinterData[gbPrinterDataCount], &gbPrinterPacket[6], diff --git a/src/gb/gbSGB.cpp b/src/gb/gbSGB.cpp index 9fbdcc13..2a72bc58 100644 --- a/src/gb/gbSGB.cpp +++ b/src/gb/gbSGB.cpp @@ -40,7 +40,7 @@ u8 gbSgbScreenBuffer[4160]; inline void gbSgbDraw24Bit(u8 *p, u16 v) { - *((u32*) p) = systemColorMap32[v]; + memcpy(p, &systemColorMap32[v], 3); } inline void gbSgbDraw32Bit(u32 *p, u16 v) diff --git a/src/gba/GBAcpu.h b/src/gba/GBAcpu.h index c21597cb..3b22e007 100644 --- a/src/gba/GBAcpu.h +++ b/src/gba/GBAcpu.h @@ -5,7 +5,11 @@ extern int armExecute(); extern int thumbExecute(); #ifdef __GNUC__ +#ifndef __APPLE__ # define INSN_REGPARM __attribute__((regparm(1))) +#else +# define INSN_REGPARM /*nothing*/ +#endif # define LIKELY(x) __builtin_expect(!!(x),1) # define UNLIKELY(x) __builtin_expect(!!(x),0) #else diff --git a/src/gtk/system.cpp b/src/gtk/system.cpp index 6c3c98d0..39663a85 100644 --- a/src/gtk/system.cpp +++ b/src/gtk/system.cpp @@ -115,6 +115,7 @@ int systemGetSensorY() } void systemGbPrint(u8 * _puiData, + int _iLen, int _iPages, int _iFeed, int _iPalette, diff --git a/src/sdl/SDL.cpp b/src/sdl/SDL.cpp index 4b268693..31744bb1 100644 --- a/src/sdl/SDL.cpp +++ b/src/sdl/SDL.cpp @@ -2591,7 +2591,7 @@ u32 systemGetClock() return SDL_GetTicks(); } -void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast) +void systemGbPrint(u8 *data,int len,int pages,int feed,int palette, int contrast) { } diff --git a/src/sdl/debugger.cpp b/src/sdl/debugger.cpp index f5799f1c..e1bfc07f 100644 --- a/src/sdl/debugger.cpp +++ b/src/sdl/debugger.cpp @@ -302,26 +302,26 @@ static void debuggerPrintBaseType(Type *t, u32 value, u32 location, case DW_ATE_signed: switch(debuggerRadix) { case 0: - printf("%lld", value); + printf("%lld", (long long)value); break; case 1: - printf("0x%llx", value); + printf("0x%llx", (long long)value); break; case 2: - printf("0%llo", value); + printf("0%llo", (long long)value); break; } break; case DW_ATE_unsigned: switch(debuggerRadix) { case 0: - printf("%llu", value); + printf("%llu", (unsigned long long)value); break; case 1: - printf("0x%llx", value); + printf("0x%llx", (unsigned long long)value); break; case 2: - printf("0%llo", value); + printf("0%llo", (unsigned long long)value); break; } break; diff --git a/src/win32/GBPrinterDlg.cpp b/src/win32/GBPrinterDlg.cpp index f9c91b41..9af2a738 100644 --- a/src/win32/GBPrinterDlg.cpp +++ b/src/win32/GBPrinterDlg.cpp @@ -467,12 +467,14 @@ void GBPrinterDlg::OnPaint() } void systemGbPrint(u8 *data, + int datalen, int pages, int feed, int palette, int contrast) { GBPrinterDlg printer; + memset(data + datalen, 0, 160*144/4 - datalen); printer.processData(data); printer.DoModal(); }