From 4e775736832db8453806495f6d961e5627644c9c Mon Sep 17 00:00:00 2001 From: Themaister Date: Mon, 3 Jan 2011 20:46:50 +0100 Subject: [PATCH] more progress, but still borked --- Makefile | 4 +-- general.h | 3 ++ record/ffemu.c | 82 ++++++++++++++++++++++++++++++++++++++++++-------- record/ffemu.h | 10 +++++- ssnes.c | 42 ++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 3972d52e75..1ec3db790e 100644 --- a/Makefile +++ b/Makefile @@ -2,9 +2,9 @@ include config.mk TARGET = ssnes -OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o +OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o record/ffemu.o -LIBS = -lsamplerate +LIBS = -lsamplerate -lavformat -lavutil -lavcodec -lswscale ifeq ($(HAVE_RSOUND), 1) OBJ += audio/rsound.o diff --git a/general.h b/general.h index af97152d12..6ecd3bf543 100644 --- a/general.h +++ b/general.h @@ -23,6 +23,7 @@ #include #include "driver.h" #include +#include "record/ffemu.h" #define MAX_PLAYERS 2 @@ -81,6 +82,8 @@ struct global char savefile_name_srm[256]; char config_path[256]; char basename[256]; + + ffemu_t *rec; }; void parse_config(void); diff --git a/record/ffemu.c b/record/ffemu.c index caa9bd5c6a..3ad378fa73 100644 --- a/record/ffemu.c +++ b/record/ffemu.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -12,7 +13,11 @@ struct video_info { bool enabled; AVCodecContext *codec; - AVFrame *frame; + + AVFrame *conv_frame; + uint8_t *conv_frame_buf; + int64_t frame_count; + FILE *file; char *file_name; @@ -44,19 +49,18 @@ struct ffemu struct ffemu_params params; }; -static int init_video(struct video_info *video, struct ffemu_params *param) -{ - (void)video; - (void)param; - return -1; -} - static int map_audio_codec(ffemu_audio_codec codec) { (void)codec; return CODEC_ID_AAC; } +static int map_video_codec(ffemu_video_codec codec) +{ + (void)codec; + return CODEC_ID_MPEG2VIDEO; +} + static int init_audio(struct audio_info *audio, struct ffemu_params *param) { AVCodec *codec = avcodec_find_encoder(map_audio_codec(param->acodec)); @@ -87,6 +91,37 @@ static int init_audio(struct audio_info *audio, struct ffemu_params *param) return 0; } +static int init_video(struct video_info *video, struct ffemu_params *param) +{ + AVCodec *codec = avcodec_find_encoder(map_video_codec(param->vcodec)); + if (!codec) + return -1; + + video->codec = avcodec_alloc_context(); + video->codec->bit_rate = 400000; + video->codec->width = param->out_width; + video->codec->height = param->out_height; + video->codec->time_base = (AVRational) {param->fps.den, param->fps.num}; + video->codec->gop_size = 10; + video->codec->max_b_frames = 1; + video->codec->pix_fmt = PIX_FMT_YUV420P; + + if (avcodec_open(video->codec, codec) != 0) + return -1; + + video->outbuf_size = 100000; + video->outbuf = av_malloc(video->outbuf_size); + + int size = avpicture_get_size(PIX_FMT_YUV420P, param->out_width, param->out_height); + video->conv_frame_buf = av_malloc(size); + video->conv_frame = avcodec_alloc_frame(); + avpicture_fill((AVPicture*)video->conv_frame, video->conv_frame_buf, PIX_FMT_YUV420P, param->out_width, param->out_height); + + video->file = fopen("/tmp/video.mpg", "wb"); + + return 0; +} + ffemu_t *ffemu_new(const struct ffemu_params *params) { avcodec_init(); @@ -136,8 +171,11 @@ void ffemu_free(ffemu_t *handle) av_free(handle->video.codec); } - if (handle->video.frame) - av_free(handle->video.frame); + if (handle->video.conv_frame) + av_free(handle->video.conv_frame); + + if (handle->video.conv_frame_buf) + av_free(handle->video.conv_frame_buf); if (handle->video.file) fclose(handle->video.file); @@ -150,15 +188,35 @@ void ffemu_free(ffemu_t *handle) int ffemu_push_video(ffemu_t *handle, const struct ffemu_video_data *data) { - (void)handle; - (void)data; if (!handle->video.enabled) return -1; + + struct SwsContext *conv_ctx = sws_getContext(data->width, data->height, PIX_FMT_RGB555LE, + handle->params.out_width, handle->params.out_height, PIX_FMT_YUV420P, SWS_BICUBIC, + NULL, NULL, NULL); + + int linesize = data->pitch; + + sws_scale(conv_ctx, (const uint8_t* const*)&data->data, &linesize, 0, handle->params.out_width, handle->video.conv_frame->data, handle->video.conv_frame->linesize); + + handle->video.conv_frame->pts = handle->video.frame_count; + handle->video.conv_frame->display_picture_number = handle->video.frame_count; + handle->video.frame_count++; + + int outsize = avcodec_encode_video(handle->video.codec, handle->video.outbuf, handle->video.outbuf_size, handle->video.conv_frame); + + fwrite(handle->video.outbuf, 1, outsize, handle->video.file); + + sws_freeContext(conv_ctx); + return 0; } int ffemu_push_audio(ffemu_t *handle, const struct ffemu_audio_data *data) { + if (!handle->audio.enabled) + return -1; + size_t written_frames = 0; while (written_frames < data->frames) { diff --git a/record/ffemu.h b/record/ffemu.h index 738a8bfd62..5979bde596 100644 --- a/record/ffemu.h +++ b/record/ffemu.h @@ -39,6 +39,12 @@ typedef enum ffemu_container FFEMU_CONTAINER_MP4 } ffemu_container; +struct ffemu_rational +{ + unsigned num; + unsigned den; +}; + // Parameters passed to ffemu_new() struct ffemu_params { @@ -48,12 +54,13 @@ struct ffemu_params // Desired output resolution. unsigned out_width; unsigned out_height; + float aspect_ratio; // Pixel format for video input. ffemu_pixel_format format; // FPS of video input. - double fps; + struct ffemu_rational fps; // Relative video quality. 0 is lossless (if available), 10 is very low quality. // A value over 10 is codec defined if it will give even worse quality. @@ -88,6 +95,7 @@ struct ffemu_video_data const void *data; unsigned width; unsigned height; + unsigned pitch; }; struct ffemu_audio_data diff --git a/ssnes.c b/ssnes.c index cc0c518b10..f8a5b0c70f 100644 --- a/ssnes.c +++ b/ssnes.c @@ -29,6 +29,8 @@ #include "hqflt/filters.h" #include "general.h" #include "dynamic.h" +#include "record/ffemu.h" +#include struct global g_extern = { .video_active = true, @@ -83,6 +85,16 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height) if ( !g_extern.video_active ) return; + ///////////// + struct ffemu_video_data ffemu_data = { + .data = data, + .pitch = 2048, + .width = width, + .height = height + }; + ffemu_push_video(g_extern.rec, &ffemu_data); + ///////////// + #ifdef HAVE_FILTER uint16_t output_filter[width * height * 4 * 4]; uint16_t output[width * height]; @@ -130,6 +142,17 @@ static void audio_sample(uint16_t left, uint16_t right) if ( !g_extern.audio_active ) return; + ///////// + static int16_t static_data[2]; + static_data[0] = left; + static_data[1] = right; + struct ffemu_audio_data ffemu_data = { + .data = static_data, + .frames = 1 + }; + ffemu_push_audio(g_extern.rec, &ffemu_data); + ////////// + static float data[AUDIO_CHUNK_SIZE_NONBLOCKING]; static int data_ptr = 0; @@ -335,6 +358,21 @@ int main(int argc, char *argv[]) load_save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); load_save_file(savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC); + //////// + struct ffemu_params params = { + .vcodec = FFEMU_VIDEO_H264, + .acodec = FFEMU_AUDIO_AAC, + .out_width = 512, + .out_height = 448, + .channels = 2, + .samplerate = 32040, + .fps = {60000, 1001}, + .aspect_ratio = 4.0/3 + }; + g_extern.rec = ffemu_new(¶ms); + assert(g_extern.rec); + ///////// + ///// TODO: Modular friendly!!! for(;;) { @@ -361,6 +399,10 @@ int main(int argc, char *argv[]) psnes_run(); } + /////////// + ffemu_free(g_extern.rec); + /////////// + save_file(g_extern.savefile_name_srm, SNES_MEMORY_CARTRIDGE_RAM); save_file(savefile_name_rtc, SNES_MEMORY_CARTRIDGE_RTC);