From: Rudolf Polzer Date: Mon, 3 Jan 2011 19:43:48 +0000 (+0100) Subject: more libavcodec X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=5d9a9302a418360995ee2996129d3169d7dd5bf6;p=xonotic%2Fdarkplaces.git more libavcodec --- diff --git a/cap_lavc.c b/cap_lavc.c index 90b4fe82..79019756 100644 --- a/cap_lavc.c +++ b/cap_lavc.c @@ -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); } }