From: Rudolf Polzer Date: Mon, 3 Jan 2011 18:42:50 +0000 (+0100) Subject: libavcodec start X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=018999feb1e77fff523a0ff6c054f820d6fdfbae;p=xonotic%2Fdarkplaces.git libavcodec start --- diff --git a/cap_lavc.c b/cap_lavc.c new file mode 100644 index 00000000..90b4fe82 --- /dev/null +++ b/cap_lavc.c @@ -0,0 +1,222 @@ +#ifndef _MSC_VER +#include +#endif +#include + +#include "quakedef.h" +#include "client.h" +#include "cap_lavc.h" + +#include +#include +#include +#include + +qboolean SCR_CaptureVideo_Lavc_OpenLibrary(void) +{ + return 1; +} + +void SCR_CaptureVideo_Lavc_Init(void) +{ +} + +qboolean SCR_CaptureVideo_Lavc_Available(void) +{ + return 1; +} + +void SCR_CaptureVideo_Lavc_CloseDLL(void) +{ +} + +typedef struct capturevideostate_lavc_formatspecific_s +{ + AVFormatContext *avf; + int apts; + int vpts; + unsigned char *buffer; + size_t bufsize; +} +capturevideostate_lavc_formatspecific_t; +#define LOAD_FORMATSPECIFIC_LAVC() capturevideostate_lavc_formatspecific_t *format = (capturevideostate_lavc_formatspecific_t *) cls.capturevideo.formatspecific + +static void SCR_CaptureVideo_Lavc_EndVideo(void) +{ + LOAD_FORMATSPECIFIC_LAVC(); + + av_write_trailer(format->avf); + { + unsigned int i; + for (i = 0; i < format->avf->nb_streams; i++) { + avcodec_close(format->avf->streams[i]->codec); + av_free(format->avf->streams[i]->codec); + av_free(format->avf->streams[i]->info); + av_free(format->avf->streams[i]); + } + av_free(format->avf); + format->avf = NULL; + } + Mem_Free(format); + + FS_Close(cls.capturevideo.videofile); + cls.capturevideo.videofile = NULL; +} + +static void SCR_CaptureVideo_Lavc_VideoFrames(int num) +{ + LOAD_FORMATSPECIFIC_LAVC(); + + // data is in cls.capturevideo.outbuffer as BGRA and has size width*height + AVCodecContext *avc = format->avf->streams[0]->codec; + AVFrame frame; + int size; + + avcodec_get_frame_defaults(&frame); + frame.data[0] = cls.capturevideo.outbuffer; + frame.linesize[0] = 4*cls.capturevideo.width; + frame.pts = format->vpts; + size = avcodec_encode_video(avc, format->buffer, format->bufsize, &frame); + if(size < 0) + Con_Printf("error encoding\n"); + if(size > 0) + { + AVPacket packet; + av_init_packet(&packet); + packet.stream_index = 0; + packet.data = format->buffer; + packet.size = size; + packet.pts = format->vpts; + if(av_interleaved_write_frame(format->avf, &packet) < 0) + Con_Printf("error writing\n"); + } + + format->vpts += num; +} + +typedef int channelmapping_t[8]; +static channelmapping_t mapping[8] = +{ + { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono + { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo + { 0, 1, 2, -1, -1, -1, -1, -1 }, // L C R + { 0, 1, 2, 3, -1, -1, -1, -1 }, // surround40 + { 0, 2, 3, 4, 1, -1, -1, -1 }, // FL FC FR RL RR + { 0, 2, 3, 4, 1, 5, -1, -1 }, // surround51 + { 0, 2, 3, 4, 1, 5, 6, -1 }, // (not defined by vorbis spec) + { 0, 2, 3, 4, 1, 5, 6, 7 } // surround71 (not defined by vorbis spec) +}; + +static void SCR_CaptureVideo_Lavc_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length) +{ + LOAD_FORMATSPECIFIC_LAVC(); + +#if 0 + if(cls.capturevideo.soundrate) + { + AVCodecContext *avc = format->avf->streams[1]->codec; + int size; + size_t i; + int *map = mapping[bound(1, cls.capturevideo.soundchannels, 8) - 1]; + + short *shortpaintbuffer = Z_Malloc(length * cls.capturevideo.soundchannels * sizeof(short)); + for(i = 0; i < length; ++i) + for(j = 0; j < cls.capturevideo.soundchannels; ++j) + shortpaintbuffer[i*cls.capturevideo.soundchannels+map[j]] = paintbuffer[i].sample[j]; + + for(;;) + { + size = avcodec_encode_audio(avc, format->buffer, format->bufsize, shortpaintbuffer); + if(size < 0) + Con_Printf("error encoding\n"); + if(size > 0) + { + AVPacket packet; + av_init_packet(&packet); + packet.stream_index = 0; + packet.data = format->buffer; + packet.size = size; + packet.pts = format->vpts; + if(av_interleaved_write_frame(format->avf, &packet) < 0) + Con_Printf("error writing\n"); + } + } + } +#endif +} + +void SCR_CaptureVideo_Lavc_BeginVideo(void) +{ + cls.capturevideo.format = CAPTUREVIDEOFORMAT_LAVC; + cls.capturevideo.formatextension = "ogv"; + cls.capturevideo.videofile = FS_OpenRealFile(va("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false); + cls.capturevideo.endvideo = SCR_CaptureVideo_Lavc_EndVideo; + cls.capturevideo.videoframes = SCR_CaptureVideo_Lavc_VideoFrames; + cls.capturevideo.soundframe = SCR_CaptureVideo_Lavc_SoundFrame; + cls.capturevideo.formatspecific = Mem_Alloc(tempmempool, sizeof(capturevideostate_lavc_formatspecific_t)); + { + LOAD_FORMATSPECIFIC_LAVC(); + AVStream *video_str; + AVCodec *encoder; + int num, denom; + + format->avf = avformat_alloc_context(); + format->avf->oformat = av_guess_format("avi", va("%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), NULL); + strlcpy(format->avf->filename, "/tmp/foo.avi", sizeof(format->avf->filename)); // TODO use the real file + + video_str = av_new_stream(format->avf, 0); + video_str->codec->codec_type = AVMEDIA_TYPE_VIDEO; + video_str->codec->codec_id = CODEC_ID_MPEG4; + + FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &num, &denom, 1001); + video_str->codec->time_base.num = denom; + video_str->codec->time_base.den = num; + + video_str->codec->width = cls.capturevideo.width; + video_str->codec->height = cls.capturevideo.height; + video_str->codec->pix_fmt = PIX_FMT_BGR32_1; + + FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000); + video_str->sample_aspect_ratio.num = num; + video_str->sample_aspect_ratio.den = denom; + + if(format->avf->oformat->flags & AVFMT_GLOBALHEADER) + video_str->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + + encoder = avcodec_find_encoder(video_str->codec->codec_id); + avcodec_open(video_str->codec, encoder); + + format->vpts = 0; + +#if 0 + if(cls.capturevideo.soundrate) + { + AVStream *audio_str; + audio_str = av_new_stream(format->avf, 0); + audio_str->codec->codec_type = AVMEDIA_TYPE_AUDIO; + audio_str->codec->codec_id = CODEC_ID_PCM_S16LE; + + audio_str->codec->time_base.num = 1; + audio_str->codec->time_base.den = cls.capturevideo.soundrate; + + audio_str->codec->sample_rate = cls.capturevideo.soundrate; + audio_str->codec->channels = cls.capturevideo.soundchannels; + audio_str->codec->sample_fmt = AV_SAMPLE_FMT_S16; + + if(format->avf->oformat->flags & AVFMT_GLOBALHEADER) + audio_str->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + + encoder = avcodec_find_encoder(audio_str->codec->codec_id); + avcodec_open(audio_str->codec, encoder); + + format->apts = 0; + } +#endif + + url_fopen(&format->avf->pb, format->avf->filename, URL_WRONLY); // FIXME + av_write_header(format->avf); + + format->bufsize = cls.capturevideo.width * cls.capturevideo.height * 6 + 200; + format->buffer = Z_Malloc(format->bufsize); + } +} diff --git a/cap_ogg.c b/cap_ogg.c index 3318c356..c72ecf13 100644 --- a/cap_ogg.c +++ b/cap_ogg.c @@ -886,7 +886,7 @@ static void SCR_CaptureVideo_Ogg_VideoFrames(int num) } typedef int channelmapping_t[8]; -channelmapping_t mapping[8] = +static channelmapping_t mapping[8] = { { 0, -1, -1, -1, -1, -1, -1, -1 }, // mono { 0, 1, -1, -1, -1, -1, -1, -1 }, // stereo diff --git a/cl_screen.c b/cl_screen.c index 611bd82f..dabfd623 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -60,6 +60,7 @@ cvar_t cl_capturevideo_fps = {CVAR_SAVE, "cl_capturevideo_fps", "30", "how many cvar_t cl_capturevideo_nameformat = {CVAR_SAVE, "cl_capturevideo_nameformat", "dpvideo", "prefix for saved videos (the date is encoded using strftime escapes)"}; cvar_t cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"}; cvar_t cl_capturevideo_ogg = {CVAR_SAVE, "cl_capturevideo_ogg", "1", "save captured video data as Ogg/Vorbis/Theora streams"}; +cvar_t cl_capturevideo_lavc = {CVAR_SAVE, "cl_capturevideo_lavc", "1", "save captured video data as libavcodec streams"}; cvar_t cl_capturevideo_framestep = {CVAR_SAVE, "cl_capturevideo_framestep", "1", "when set to n >= 1, render n frames to capture one (useful for motion blur like effects)"}; cvar_t r_letterbox = {0, "r_letterbox", "0", "reduces vertical height of view to simulate a letterboxed movie effect (can be used by mods for cutscenes)"}; cvar_t r_stereo_separation = {0, "r_stereo_separation", "4", "separation distance of eyes in the world (negative values are only useful for cross-eyed viewing)"}; @@ -933,6 +934,7 @@ void CL_Screen_Init(void) Cvar_RegisterVariable (&cl_capturevideo_nameformat); Cvar_RegisterVariable (&cl_capturevideo_number); Cvar_RegisterVariable (&cl_capturevideo_ogg); + Cvar_RegisterVariable (&cl_capturevideo_lavc); Cvar_RegisterVariable (&cl_capturevideo_framestep); Cvar_RegisterVariable (&r_letterbox); Cvar_RegisterVariable(&r_stereo_separation); @@ -960,6 +962,7 @@ void CL_Screen_Init(void) Cmd_AddCommand ("infobar", SCR_InfoBar_f, "display a text in the infobar (usage: infobar expiretime string)"); SCR_CaptureVideo_Ogg_Init(); + SCR_CaptureVideo_Lavc_Init(); scr_initialized = true; } @@ -1160,6 +1163,17 @@ Cr = R * .500 + G * -.419 + B * -.0813 + 128.; cls.capturevideo.yuvnormalizetable[2][i] = 16 + i * (240-16) / 256; } + if (cl_capturevideo_lavc.integer) + { + if(SCR_CaptureVideo_Lavc_Available()) + { + SCR_CaptureVideo_Lavc_BeginVideo(); + return; + } + else + Con_Print("cl_capturevideo_lavc: libraries not available. Capturing in Ogg instead.\n"); + } + if (cl_capturevideo_ogg.integer) { if(SCR_CaptureVideo_Ogg_Available()) diff --git a/client.h b/client.h index f3d1ccce..2adb4e28 100644 --- a/client.h +++ b/client.h @@ -537,7 +537,8 @@ qw_downloadtype_t; typedef enum capturevideoformat_e { CAPTUREVIDEOFORMAT_AVI_I420, - CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA + CAPTUREVIDEOFORMAT_OGG_VORBIS_THEORA, + CAPTUREVIDEOFORMAT_LAVC } capturevideoformat_t; diff --git a/makefile.inc b/makefile.inc index a85df801..ef5900e7 100644 --- a/makefile.inc +++ b/makefile.inc @@ -99,6 +99,7 @@ OBJ_NOCD=cd_null.o OBJ_COMMON= \ bih.o \ cap_avi.o \ + cap_lavc.o \ cap_ogg.o \ cd_shared.o \ crypto.o \ @@ -220,7 +221,7 @@ LDFLAGS_RELEASE=$(OPTIM_RELEASE) -DSVNREVISION=`test -d .svn && svnversion || ec OBJ_GLX= builddate.c sys_linux.o vid_glx.o keysym2ucs.o $(OBJ_SOUND) $(OBJ_CD) $(OBJ_COMMON) -LDFLAGS_UNIXCOMMON=-lm $(LIB_ODE) $(LIB_CG) $(LIB_JPEG) $(LIB_CRYPTO) $(LIB_CRYPTO_RIJNDAEL) +LDFLAGS_UNIXCOMMON=-lavcodec -lavformat -lavutil -lm $(LIB_ODE) $(LIB_CG) $(LIB_JPEG) $(LIB_CRYPTO) $(LIB_CRYPTO_RIJNDAEL) LDFLAGS_UNIXCL=-L$(UNIX_X11LIBPATH) -lX11 -lXpm -lXext -lXxf86dga -lXxf86vm $(LIB_SOUND) LDFLAGS_UNIXCL_PRELOAD=-lz -ljpeg -lpng -logg -ltheora -lvorbis -lvorbisenc -lvorbisfile -lcurl -lmodplug LDFLAGS_UNIXSV_PRELOAD=-lz -ljpeg -lpng -lcurl