pcsx2/plugins/gs/GSsoft/Src/Rec.c

286 lines
8.6 KiB
C

/* GSsoft
* Copyright (C) 2002-2005 GSsoft Team
*
* This program 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 program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <ffmpeg/avformat.h>
#include "GS.h"
#include "Draw.h"
#include "Rec.h"
AVFormatContext *output = NULL;
AVStream *stream;
AVFrame *picture;
AVFrame *yuv420p;
u8 *picture_buf;
int picture_size;
u8 *outbuf;
int outbuf_size;
#define av_register_all _av_register_all
#define av_new_stream _av_new_stream
#define av_set_parameters _av_set_parameters
#define av_write_header _av_write_header
#define av_write_frame _av_write_frame
#define av_write_trailer _av_write_trailer
#define avpicture_fill _avpicture_fill
#define avpicture_get_size _avpicture_get_size
#define img_convert _img_convert
#define avcodec_alloc_frame _avcodec_alloc_frame
#define avcodec_open _avcodec_open
#define avcodec_find_encoder _avcodec_find_encoder
#define avcodec_encode_video _avcodec_encode_video
#define avcodec_close _avcodec_close
#define av_mallocz _av_mallocz
#define av_free _av_free
#define __av_freep ___av_freep
#define url_fopen _url_fopen
#define url_fclose _url_fclose
#define first_oformat _first_oformat
void *avcodeclib;
void *avformatlib;
#ifdef __WIN32__
#define AVCODECLIB "avcodec.dll"
#define AVFORMATLIB "avformat.dll"
#else
#define AVCODECLIB "libavcodec.so"
#define AVFORMATLIB "libavformat.so"
#endif
void (*av_register_all)(void);
AVStream *(*av_new_stream)(AVFormatContext *s, int id);
int (*av_set_parameters)(AVFormatContext *s, AVFormatParameters *ap);
int (*av_write_header)(AVFormatContext *s);
int (*av_write_frame)(AVFormatContext *s, int stream_index, const uint8_t *buf,
int size);
int (*av_write_trailer)(AVFormatContext *s);
int (*avpicture_fill)(AVPicture *picture, uint8_t *ptr,
int pix_fmt, int width, int height);
int (*avpicture_get_size)(int pix_fmt, int width, int height);
int (*img_convert)(AVPicture *dst, int dst_pix_fmt,
AVPicture *src, int pix_fmt,
int width, int height);
AVFrame *(*avcodec_alloc_frame)(void);
int (*avcodec_open)(AVCodecContext *avctx, AVCodec *codec);
AVCodec *(*avcodec_find_encoder)(enum CodecID id);
int (*avcodec_encode_video)(AVCodecContext *avctx, uint8_t *buf, int buf_size,
const AVFrame *pict);
int (*avcodec_close)(AVCodecContext *avctx);
void *(*av_mallocz)(unsigned int size);
void (*av_free)(void *ptr);
void (*__av_freep)(void **ptr);
int (*url_fopen)(URLContext **h, const char *filename, int flags);
int (*url_fclose)(URLContext *h);
AVOutputFormat **first_oformat;
int recLoad() {
avcodeclib = SysLoadLibrary(AVCODECLIB);
if (avcodeclib == NULL) {
printf("Couldn't load %s: %s\n", AVCODECLIB, SysLibError());
return -1;
}
avformatlib = SysLoadLibrary(AVFORMATLIB);
if (avformatlib == NULL) {
printf("Couldn't load %s: %s\n", AVFORMATLIB, SysLibError());
return -1;
}
av_register_all = SysLoadSym(avformatlib, "av_register_all");
av_new_stream = SysLoadSym(avformatlib, "av_new_stream");
av_set_parameters = SysLoadSym(avformatlib, "av_set_parameters");
av_write_header = SysLoadSym(avformatlib, "av_write_header");
av_write_frame = SysLoadSym(avformatlib, "av_write_frame");
av_write_trailer = SysLoadSym(avformatlib, "av_write_trailer");
avpicture_fill = SysLoadSym(avcodeclib, "avpicture_fill");
avpicture_get_size = SysLoadSym(avcodeclib, "avpicture_get_size");
img_convert = SysLoadSym(avcodeclib, "img_convert");
avcodec_alloc_frame = SysLoadSym(avcodeclib, "avcodec_alloc_frame");
avcodec_open = SysLoadSym(avcodeclib, "avcodec_open");
avcodec_find_encoder = SysLoadSym(avcodeclib, "avcodec_find_encoder");
avcodec_encode_video = SysLoadSym(avcodeclib, "avcodec_encode_video");
avcodec_close = SysLoadSym(avcodeclib, "avcodec_close");
av_mallocz = SysLoadSym(avcodeclib, "av_mallocz");
av_free = SysLoadSym(avcodeclib, "av_free");
__av_freep = SysLoadSym(avcodeclib, "__av_freep");
url_fopen = SysLoadSym(avformatlib, "url_fopen");
url_fclose = SysLoadSym(avformatlib, "url_fclose");
first_oformat = SysLoadSym(avformatlib, "first_oformat");
return 0;
}
void recUnload() {
SysLoadLibrary(avcodeclib);
SysLoadLibrary(avformatlib);
}
void recOpen() {
AVOutputFormat *fmt;
AVCodecContext *codec_ctx;
AVCodec *codec;
char filename[256];
int video_codec;
if (output != NULL) recClose();
if (recLoad() == -1) {
conf.record = 0; return;
}
av_register_all();
switch (conf.codec) {
case 1: // divx
video_codec = CODEC_ID_MPEG4;
sprintf(filename, "gssoft.avi");
break;
case 2: // mpeg2
video_codec = CODEC_ID_MPEG2VIDEO;
sprintf(filename, "gssoft.mpg");
break;
default: // mpeg1
video_codec = CODEC_ID_MPEG1VIDEO;
sprintf(filename, "gssoft.mpg");
break;
}
fmt = *first_oformat;
while (fmt != NULL) {
if (fmt->video_codec == video_codec) break;
fmt = fmt->next;
}
if (fmt == NULL) {
SysMessage("codec not found");
conf.record = 0; return;
}
output = av_mallocz(sizeof(AVFormatContext));
if (output == NULL) {
SysMessage("Out of Memory");
conf.record = 0; return;
}
output->oformat = fmt;
snprintf(output->filename, sizeof(output->filename), "%s", filename);
stream = av_new_stream(output, 0);
if (stream == NULL) {
SysMessage("Out of Memory");
conf.record = 0; return;
}
codec_ctx = &stream->codec;
codec_ctx->codec_id = video_codec;
codec_ctx->codec_type = CODEC_TYPE_VIDEO;
codec_ctx->bit_rate = 400000;
codec_ctx->width = cmode->width;
codec_ctx->height = cmode->height;
codec_ctx->frame_rate = gs.SMODE1.cmod & 1 ? 50 : 60;
codec_ctx->frame_rate_base = 1;
if (conf.codec == 0) {
codec_ctx->gop_size = 10;
codec_ctx->max_b_frames = 1;
}
if (av_set_parameters(output, NULL) < 0) {
SysMessage("set parameters failed");
conf.record = 0; return;
}
codec = avcodec_find_encoder(codec_ctx->codec_id);
if (codec == NULL) {
SysMessage("codec not found");
conf.record = 0; return;
}
if (avcodec_open(codec_ctx, codec) < 0) {
SysMessage("Unable to open codec");
conf.record = 0; return;
}
if (url_fopen(&output->pb, filename, URL_WRONLY) < 0) {
SysMessage("Unable to open %s for writing", filename);
conf.record = 0; return;
}
av_write_header(output);
picture = avcodec_alloc_frame();
yuv420p = avcodec_alloc_frame();
outbuf_size = 100000;
outbuf = malloc(outbuf_size);
if (outbuf == NULL) {
SysMessage("Out of Memory");
conf.record = 0; return;
}
picture_size = avpicture_get_size(PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height);
picture_buf = malloc(picture_size);
if (picture_buf == NULL) {
SysMessage("Out of Memory");
conf.record = 0; return;
}
avpicture_fill((AVPicture*)yuv420p, picture_buf, PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height);
}
void recFrame(char *sbuff, int lPitch, int bpp) {
int size;
int pix_fmt;
picture->data[0] = sbuff;
picture->linesize[0] = lPitch;
switch (bpp) {
case 15: pix_fmt = PIX_FMT_RGB555; break;
case 16: pix_fmt = PIX_FMT_RGB565; break;
case 24: pix_fmt = PIX_FMT_RGB24; break;
case 32: pix_fmt = PIX_FMT_RGBA32; break;
default: return;
}
img_convert((AVPicture*)yuv420p, PIX_FMT_YUV420P, (AVPicture*)picture, pix_fmt, stream->codec.width, stream->codec.height);
size = avcodec_encode_video(&stream->codec, outbuf, outbuf_size, yuv420p);
if (size == -1) {
printf("error encoding frame\n"); return;
}
av_write_frame(output, stream->index, outbuf, size);
}
int recExist() {
if (recLoad() == -1) return -1;
recUnload();
return 0;
}
void recClose() {
avcodec_close(&stream->codec);
free(outbuf);
free(picture_buf);
free(picture);
free(yuv420p);
av_write_trailer(output);
url_fclose(&output->pb);
av_freep(&output->streams[0]);
av_free(output); output = NULL;
recUnload();
}