]> git.rm.cloudns.org Git - xonotic/darkplaces.git/commitdiff
more libavcodec
authorRudolf Polzer <divverent@alientrap.org>
Mon, 3 Jan 2011 19:43:48 +0000 (20:43 +0100)
committerRudolf Polzer <divverent@alientrap.org>
Mon, 3 Jan 2011 19:43:48 +0000 (20:43 +0100)
cap_lavc.c

index 90b4fe823c275868546fc12955fc7f8d47e38111..7901975616298981e8dfe7b0775ccdb15788ce4d 100644 (file)
@@ -19,6 +19,8 @@ qboolean SCR_CaptureVideo_Lavc_OpenLibrary(void)
 
 void SCR_CaptureVideo_Lavc_Init(void)
 {
+       avcodec_register_all();
+       av_register_all();
 }
 
 qboolean SCR_CaptureVideo_Lavc_Available(void)
@@ -35,8 +37,11 @@ typedef struct capturevideostate_lavc_formatspecific_s
        AVFormatContext *avf;
        int apts;
        int vpts;
+       unsigned char *yuv;
        unsigned char *buffer;
        size_t bufsize;
+       short *aframe;
+       int aframepos;
 }
 capturevideostate_lavc_formatspecific_t;
 #define LOAD_FORMATSPECIFIC_LAVC() capturevideostate_lavc_formatspecific_t *format = (capturevideostate_lavc_formatspecific_t *) cls.capturevideo.formatspecific
@@ -45,17 +50,20 @@ static void SCR_CaptureVideo_Lavc_EndVideo(void)
 {
        LOAD_FORMATSPECIFIC_LAVC();
 
-       av_write_trailer(format->avf);
+       if(format->buffer)
        {
-               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_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;
                }
-               av_free(format->avf);
-               format->avf = NULL;
        }
        Mem_Free(format);
 
@@ -63,6 +71,61 @@ static void SCR_CaptureVideo_Lavc_EndVideo(void)
        cls.capturevideo.videofile = NULL;
 }
 
+static void SCR_CaptureVideo_Lavc_ConvertFrame_BGRA_to_YUV(AVFrame *frame)
+{
+       LOAD_FORMATSPECIFIC_LAVC();
+       int x, y;
+       int blockr, blockg, blockb;
+       unsigned char *b = cls.capturevideo.outbuffer;
+       int w = cls.capturevideo.width;
+       int uw = (w+1)/2;
+       int h = cls.capturevideo.height;
+       int uh = (h+1)/2;
+       int inpitch = w*4;
+
+       unsigned char *yuvy = format->yuv;
+       unsigned char *yuvu = yuvy + w*h;
+       unsigned char *yuvv = yuvu + uw*uh;
+
+       frame->data[0] = yuvy;
+       frame->linesize[0] = w;
+       frame->data[1] = yuvu;
+       frame->linesize[1] = uw;
+       frame->data[2] = yuvv;
+       frame->linesize[2] = uw;
+
+       for(y = 0; y < h; ++y)
+       {
+               for(b = cls.capturevideo.outbuffer + (h-1-y)*w*4, x = 0; x < w; ++x)
+               {
+                       blockr = b[2];
+                       blockg = b[1];
+                       blockb = b[0];
+                       yuvy[x + w * y] =
+                               cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]];
+                       b += 4;
+               }
+
+       // format->yuv = Z_Malloc(cls.capturevideo.width * cls.capturevideo.height + ((cls.capturevideo.width + 1) / 2) * ((cls.capturevideo.height + 1) / 2));
+
+               if((y & 1) == 0)
+               {
+                       for(b = cls.capturevideo.outbuffer + (h-2-y)*w*4, x = 0; x < (w+1)/2; ++x)
+                       {
+                               blockr = (b[2] + b[6] + b[inpitch+2] + b[inpitch+6]) >> 2;
+                               blockg = (b[1] + b[5] + b[inpitch+1] + b[inpitch+5]) >> 2;
+                               blockb = (b[0] + b[4] + b[inpitch+0] + b[inpitch+4]) >> 2;
+                               yuvu[x + uw * (y/2)] =
+                                       cls.capturevideo.yuvnormalizetable[1][cls.capturevideo.rgbtoyuvscaletable[1][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[1][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[1][2][blockb] + 128];
+                               yuvv[x + uw * (y/2)] =
+                                       cls.capturevideo.yuvnormalizetable[2][cls.capturevideo.rgbtoyuvscaletable[2][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[2][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[2][2][blockb] + 128];
+                               b += 8;
+                       }
+               }
+       }
+}
+
+
 static void SCR_CaptureVideo_Lavc_VideoFrames(int num)
 {
        LOAD_FORMATSPECIFIC_LAVC();
@@ -73,8 +136,7 @@ static void SCR_CaptureVideo_Lavc_VideoFrames(int num)
        int size;
 
        avcodec_get_frame_defaults(&frame);
-       frame.data[0] = cls.capturevideo.outbuffer;
-       frame.linesize[0] = 4*cls.capturevideo.width;
+       SCR_CaptureVideo_Lavc_ConvertFrame_BGRA_to_YUV(&frame);
        frame.pts = format->vpts;
        size = avcodec_encode_video(avc, format->buffer, format->bufsize, &frame);
        if(size < 0)
@@ -94,6 +156,7 @@ static void SCR_CaptureVideo_Lavc_VideoFrames(int num)
        format->vpts += num;
 }
 
+// FIXME find the correct mappings for DP to ffmpeg
 typedef int channelmapping_t[8];
 static channelmapping_t mapping[8] =
 {
@@ -111,44 +174,60 @@ static void SCR_CaptureVideo_Lavc_SoundFrame(const portable_sampleframe_t *paint
 {
        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];
+               size_t bufpos = 0;
 
-               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(;;)
+               while(bufpos < length)
                {
-                       size = avcodec_encode_audio(avc, format->buffer, format->bufsize, shortpaintbuffer);
-                       if(size < 0)
-                               Con_Printf("error encoding\n");
-                       if(size > 0)
+                       // fill up buffer
+                       while(bufpos < length && format->aframepos < avc->frame_size)
                        {
-                               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");
+                               for(i = 0; i < cls.capturevideo.soundchannels; ++i)
+                                       format->aframe[format->aframepos*cls.capturevideo.soundchannels+map[i]] = paintbuffer[bufpos].sample[i];
+                               ++bufpos;
+                               ++format->aframepos;
+                       }
+
+                       if(format->aframepos >= avc->frame_size)
+                       {
+                               size = avcodec_encode_audio(avc, format->buffer, format->bufsize, format->aframe);
+                               if(size < 0)
+                                       Con_Printf("error encoding\n");
+                               if(size > 0)
+                               {
+                                       AVPacket packet;
+                                       av_init_packet(&packet);
+                                       packet.stream_index = 1;
+                                       packet.data = format->buffer;
+                                       packet.size = size;
+                                       packet.pts = format->apts;
+                                       if(av_interleaved_write_frame(format->avf, &packet) < 0)
+                                               Con_Printf("error writing\n");
+                               }
+
+                               format->apts += avc->frame_size;
+                               format->aframepos = 0;
+                       }
+                       else
+                       {
+                               // if we get here, frame_size was not hit
+                               // this means that length has been hit!
+                               break;
                        }
                }
        }
-#endif
 }
 
+// TODO error checking in this function
 void SCR_CaptureVideo_Lavc_BeginVideo(void)
 {
        cls.capturevideo.format = CAPTUREVIDEOFORMAT_LAVC;
-       cls.capturevideo.formatextension = "ogv";
+       cls.capturevideo.formatextension = "avi";
        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;
@@ -162,7 +241,13 @@ void SCR_CaptureVideo_Lavc_BeginVideo(void)
 
                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
+               if(!format->avf->oformat)
+               {
+                       Con_Printf("Failed to find format\n");
+                       SCR_CaptureVideo_EndVideo();
+                       return;
+               }
+               strlcpy(format->avf->filename, "/tmp/foo.avi", sizeof(format->avf->filename)); // TODO use the qfile_t
 
                video_str = av_new_stream(format->avf, 0);
                video_str->codec->codec_type = AVMEDIA_TYPE_VIDEO;
@@ -174,27 +259,41 @@ void SCR_CaptureVideo_Lavc_BeginVideo(void)
 
                video_str->codec->width = cls.capturevideo.width;
                video_str->codec->height = cls.capturevideo.height;
-               video_str->codec->pix_fmt = PIX_FMT_BGR32_1;
+               video_str->codec->pix_fmt = PIX_FMT_YUV420P;
 
                FindFraction(1 / vid_pixelheight.value, &num, &denom, 1000);
                video_str->sample_aspect_ratio.num = num;
                video_str->sample_aspect_ratio.den = denom;
+               video_str->codec->sample_aspect_ratio.num = num;
+               video_str->codec->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);
+               if(!encoder)
+               {
+                       Con_Printf("Failed to find encoder\n");
+                       SCR_CaptureVideo_EndVideo();
+                       return;
+               }
+               if(avcodec_open(video_str->codec, encoder) < 0)
+               {
+                       Con_Printf("Failed to open encoder\n");
+                       SCR_CaptureVideo_EndVideo();
+                       return;
+               }
 
                format->vpts = 0;
+               format->bufsize = cls.capturevideo.width * cls.capturevideo.height * 6 + 200;
 
-#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->codec_id = CODEC_ID_PCM_S16LE;
+                       audio_str->codec->codec_id = CODEC_ID_MP3;
 
                        audio_str->codec->time_base.num = 1;
                        audio_str->codec->time_base.den = cls.capturevideo.soundrate;
@@ -207,16 +306,31 @@ void SCR_CaptureVideo_Lavc_BeginVideo(void)
                                audio_str->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
 
                        encoder = avcodec_find_encoder(audio_str->codec->codec_id);
-                       avcodec_open(audio_str->codec, encoder);
+                       if(!encoder)
+                       {
+                               Con_Printf("Failed to find encoder\n");
+                               SCR_CaptureVideo_EndVideo();
+                               return;
+                       }
+                       if(avcodec_open(audio_str->codec, encoder) < 0)
+                       {
+                               Con_Printf("Failed to open encoder\n");
+                               SCR_CaptureVideo_EndVideo();
+                               return;
+                       }
 
                        format->apts = 0;
+                       format->aframe = Z_Malloc(audio_str->codec->frame_size * sizeof(*format->aframe) * cls.capturevideo.soundchannels);
+                       format->aframepos = 0;
+
+                       format->bufsize = max(format->bufsize, audio_str->codec->frame_size * sizeof(*format->aframe) * cls.capturevideo.soundchannels * 2 + 200);
                }
-#endif
 
-               url_fopen(&format->avf->pb, format->avf->filename, URL_WRONLY); // FIXME
+               url_fopen(&format->avf->pb, format->avf->filename, URL_WRONLY); // FIXME use the qfile_t
                av_write_header(format->avf);
 
-               format->bufsize = cls.capturevideo.width * cls.capturevideo.height * 6 + 200;
                format->buffer = Z_Malloc(format->bufsize);
+
+               format->yuv = Z_Malloc(cls.capturevideo.width * cls.capturevideo.height + ((cls.capturevideo.width + 1) / 2) * ((cls.capturevideo.height + 1) / 2) * 2);
        }
 }