]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
libavcodec start
authorRudolf Polzer <divverent@alientrap.org>
Mon, 3 Jan 2011 18:42:50 +0000 (19:42 +0100)
committerRudolf Polzer <divverent@alientrap.org>
Mon, 3 Jan 2011 18:42:50 +0000 (19:42 +0100)
cap_lavc.c [new file with mode: 0644]
cap_ogg.c
cl_screen.c
client.h
makefile.inc

diff --git a/cap_lavc.c b/cap_lavc.c
new file mode 100644 (file)
index 0000000..90b4fe8
--- /dev/null
@@ -0,0 +1,222 @@
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <sys/types.h>
+
+#include "quakedef.h"
+#include "client.h"
+#include "cap_lavc.h"
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavutil/avstring.h>
+#include <libavutil/pixfmt.h>
+
+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);
+       }
+}
index 3318c356c4119bb34e0465ed7307d3c4de7aa568..c72ecf135a049e542a9830ca63274fc5f38d3c3c 100644 (file)
--- 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
index 611bd82f0e1dca038101cfd56f86ff14573b6e42..dabfd6232d1aa8c1603d412d1f906bb7d26ca15c 100644 (file)
@@ -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())
index f3d1cccebf2c4e621fe149f502144e3d120c670e..2adb4e283049be01933eb004a524d3dde7818f0e 100644 (file)
--- 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;
 
index a85df801b639846d8c84941d320f58f9bf46782e..ef5900e77528369897eb41645ba594252165b392 100644 (file)
@@ -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