move avwraper compilation in its own folder cmake_pascal
authorkoda
Tue, 19 Mar 2013 17:14:10 +0100
branchcmake_pascal
changeset 8811 dcdfcddf37ee
parent 8809 8ce66f1106f1
child 8813 a932b10fc1d0
move avwraper compilation in its own folder
hedgewars/CMakeLists.txt
hedgewars/avwrapper.c
hedgewars/avwrapper/CMakeLists.txt
hedgewars/avwrapper/avwrapper.c
--- a/hedgewars/CMakeLists.txt	Tue Mar 19 16:47:53 2013 +0100
+++ b/hedgewars/CMakeLists.txt	Tue Mar 19 17:14:10 2013 +0100
@@ -140,7 +140,6 @@
         set(powerpc_build "powerpc")
     endif()
 
-
     #on OSX we need to provide the SDL_main() function when building as executable
     if(NOT ${BUILD_ENGINE_LIBRARY})
         add_subdirectory(sdlmain)
@@ -150,20 +149,7 @@
 
 
 if(${FFMPEG_FOUND})
-    # TODO: this check is only for SDL < 2
-    # fpc will take care of linking but we need to have this library installed
-    find_package(GLUT REQUIRED)
-
-    #TODO: convert avwrapper to .pas unit so we can skip this step
-    include_directories(${FFMPEG_INCLUDE_DIR})
-    if(WIN32)
-        # there are some problems with linking our avwrapper as static lib, so link it as shared
-        add_library(avwrapper SHARED avwrapper.c)
-        target_link_libraries(avwrapper ${FFMPEG_LIBRARIES})
-        install(PROGRAMS "${LIBRARY_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_library_install_dir})
-    else()
-        add_library(avwrapper STATIC avwrapper.c)
-    endif()
+    add_subdirectory(avwrapper)
     add_definitions(-dUSE_VIDEO_RECORDING)
     add_flag_append(CMAKE_Pascal_FLAGS -Fl${LIBRARY_OUTPUT_PATH})
 endif()
--- a/hedgewars/avwrapper.c	Tue Mar 19 16:47:53 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,509 +0,0 @@
-/*
- * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
- *
- * 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; version 2 of the License
- *
- * 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 <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdarg.h>
-#include "libavformat/avformat.h"
-#include "libavutil/mathematics.h"
-
-#ifndef AVIO_FLAG_WRITE
-#define AVIO_FLAG_WRITE AVIO_WRONLY
-#endif
-
-static AVFormatContext* g_pContainer;
-static AVOutputFormat* g_pFormat;
-static AVStream* g_pAStream;
-static AVStream* g_pVStream;
-static AVFrame* g_pAFrame;
-static AVFrame* g_pVFrame;
-static AVCodec* g_pACodec;
-static AVCodec* g_pVCodec;
-static AVCodecContext* g_pAudio;
-static AVCodecContext* g_pVideo;
-
-static int g_Width, g_Height;
-static uint32_t g_Frequency, g_Channels;
-static int g_VQuality;
-static AVRational g_Framerate;
-
-static FILE* g_pSoundFile;
-static int16_t* g_pSamples;
-static int g_NumSamples;
-
-
-#if LIBAVCODEC_VERSION_MAJOR < 54
-#define OUTBUFFER_SIZE 200000
-static uint8_t g_OutBuffer[OUTBUFFER_SIZE];
-#endif
-
-// pointer to function from hwengine (uUtils.pas)
-static void (*AddFileLogRaw)(const char* pString);
-
-static void FatalError(const char* pFmt, ...)
-{
-    char Buffer[1024];
-    va_list VaArgs;
-
-    va_start(VaArgs, pFmt);
-    vsnprintf(Buffer, 1024, pFmt, VaArgs);
-    va_end(VaArgs);
-
-    AddFileLogRaw("Error in av-wrapper: ");
-    AddFileLogRaw(Buffer);
-    AddFileLogRaw("\n");
-    exit(1);
-}
-
-// Function to be called from libav for logging.
-// Note: libav can call LogCallback from different threads
-// (there is mutex in AddFileLogRaw).
-static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs)
-{
-    char Buffer[1024];
-
-    vsnprintf(Buffer, 1024, pFmt, VaArgs);
-    AddFileLogRaw(Buffer);
-}
-
-static void Log(const char* pFmt, ...)
-{
-    char Buffer[1024];
-    va_list VaArgs;
-
-    va_start(VaArgs, pFmt);
-    vsnprintf(Buffer, 1024, pFmt, VaArgs);
-    va_end(VaArgs);
-
-    AddFileLogRaw(Buffer);
-}
-
-static void AddAudioStream()
-{
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
-    g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
-#else
-    g_pAStream = av_new_stream(g_pContainer, 1);
-#endif
-    if(!g_pAStream)
-    {
-        Log("Could not allocate audio stream\n");
-        return;
-    }
-    g_pAStream->id = 1;
-
-    g_pAudio = g_pAStream->codec;
-
-    avcodec_get_context_defaults3(g_pAudio, g_pACodec);
-    g_pAudio->codec_id = g_pACodec->id;
-
-    // put parameters
-    g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
-    g_pAudio->sample_rate = g_Frequency;
-    g_pAudio->channels = g_Channels;
-
-    // set quality
-    g_pAudio->bit_rate = 160000;
-
-    // for codecs that support variable bitrate use it, it should be better
-    g_pAudio->flags |= CODEC_FLAG_QSCALE;
-    g_pAudio->global_quality = 1*FF_QP2LAMBDA;
-
-    // some formats want stream headers to be separate
-    if (g_pFormat->flags & AVFMT_GLOBALHEADER)
-        g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
-    // open it
-#if LIBAVCODEC_VERSION_MAJOR >= 53
-    if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0)
-#else
-    if (avcodec_open(g_pAudio, g_pACodec) < 0)
-#endif
-    {
-        Log("Could not open audio codec %s\n", g_pACodec->long_name);
-        return;
-    }
-
-#if LIBAVCODEC_VERSION_MAJOR >= 54
-    if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
-#else
-    if (g_pAudio->frame_size == 0)
-#endif
-        g_NumSamples = 4096;
-    else
-        g_NumSamples = g_pAudio->frame_size;
-    g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t));
-    g_pAFrame = avcodec_alloc_frame();
-    if (!g_pAFrame)
-    {
-        Log("Could not allocate frame\n");
-        return;
-    }
-}
-
-// returns non-zero if there is more sound
-static int WriteAudioFrame()
-{
-    if (!g_pAStream)
-        return 0;
-
-    AVPacket Packet = { 0 };
-    av_init_packet(&Packet);
-
-    int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
-
-#if LIBAVCODEC_VERSION_MAJOR >= 53
-    AVFrame* pFrame = NULL;
-    if (NumSamples > 0)
-    {
-        g_pAFrame->nb_samples = NumSamples;
-        avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16,
-                                 (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1);
-        pFrame = g_pAFrame;
-    }
-    // when NumSamples == 0 we still need to call encode_audio2 to flush
-    int got_packet;
-    if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
-        FatalError("avcodec_encode_audio2 failed");
-    if (!got_packet)
-        return 0;
-#else
-    if (NumSamples == 0)
-        return 0;
-    int BufferSize = OUTBUFFER_SIZE;
-    if (g_pAudio->frame_size == 0)
-        BufferSize = NumSamples*g_Channels*2;
-    Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples);
-    if (Packet.size == 0)
-        return 1;
-    if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE)
-        Packet.pts = av_rescale_q(g_pAudio->coded_frame->pts, g_pAudio->time_base, g_pAStream->time_base);
-    Packet.flags |= AV_PKT_FLAG_KEY;
-    Packet.data = g_OutBuffer;
-#endif
-
-    // Write the compressed frame to the media file.
-    Packet.stream_index = g_pAStream->index;
-    if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) 
-        FatalError("Error while writing audio frame");
-    return 1;
-}
-
-// add a video output stream
-static void AddVideoStream()
-{
-#if LIBAVFORMAT_VERSION_MAJOR >= 53
-    g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
-#else
-    g_pVStream = av_new_stream(g_pContainer, 0);
-#endif
-    if (!g_pVStream)
-        FatalError("Could not allocate video stream");
-
-    g_pVideo = g_pVStream->codec;
-
-    avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
-    g_pVideo->codec_id = g_pVCodec->id;
-
-    // put parameters
-    // resolution must be a multiple of two
-    g_pVideo->width  = g_Width  & ~1; // make even (dimensions should be even)
-    g_pVideo->height = g_Height & ~1; // make even
-    /* time base: this is the fundamental unit of time (in seconds) in terms
-       of which frame timestamps are represented. for fixed-fps content,
-       timebase should be 1/framerate and timestamp increments should be
-       identically 1. */
-    g_pVideo->time_base.den = g_Framerate.num;
-    g_pVideo->time_base.num = g_Framerate.den;
-    //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */
-    g_pVideo->pix_fmt = PIX_FMT_YUV420P;
-
-    // set quality
-    if (g_VQuality > 100)
-        g_pVideo->bit_rate = g_VQuality;
-    else
-    {
-        g_pVideo->flags |= CODEC_FLAG_QSCALE;
-        g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA;
-    }
-
-    // some formats want stream headers to be separate
-    if (g_pFormat->flags & AVFMT_GLOBALHEADER)
-        g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
-#if LIBAVCODEC_VERSION_MAJOR < 53
-    // for some versions of ffmpeg x264 options must be set explicitly
-    if (strcmp(g_pVCodec->name, "libx264") == 0)
-    {
-        g_pVideo->coder_type = FF_CODER_TYPE_AC;
-        g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER;
-        g_pVideo->crf = 23;
-        g_pVideo->thread_count = 3;
-        g_pVideo->me_cmp = FF_CMP_CHROMA;
-        g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8;
-        g_pVideo->me_method = ME_HEX;
-        g_pVideo->me_subpel_quality = 7;
-        g_pVideo->me_range = 16;
-        g_pVideo->gop_size = 250;
-        g_pVideo->keyint_min = 25;
-        g_pVideo->scenechange_threshold = 40;
-        g_pVideo->i_quant_factor = 0.71;
-        g_pVideo->b_frame_strategy = 1;
-        g_pVideo->qcompress = 0.6;
-        g_pVideo->qmin = 10;
-        g_pVideo->qmax = 51;
-        g_pVideo->max_qdiff = 4;
-        g_pVideo->max_b_frames = 3;
-        g_pVideo->refs = 3;
-        g_pVideo->directpred = 1;
-        g_pVideo->trellis = 1;
-        g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP;
-        g_pVideo->weighted_p_pred = 2;
-    }
-#endif
-
-    // open the codec
-#if LIBAVCODEC_VERSION_MAJOR >= 53
-    AVDictionary* pDict = NULL;
-    if (strcmp(g_pVCodec->name, "libx264") == 0)
-        av_dict_set(&pDict, "preset", "medium", 0);
-
-    if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
-#else
-    if (avcodec_open(g_pVideo, g_pVCodec) < 0)
-#endif
-        FatalError("Could not open video codec %s", g_pVCodec->long_name);
-
-    g_pVFrame = avcodec_alloc_frame();
-    if (!g_pVFrame)
-        FatalError("Could not allocate frame");
-
-    g_pVFrame->linesize[0] = g_Width;
-    g_pVFrame->linesize[1] = g_Width/2;
-    g_pVFrame->linesize[2] = g_Width/2;
-    g_pVFrame->linesize[3] = 0;
-}
-
-static int WriteFrame(AVFrame* pFrame)
-{
-    double AudioTime, VideoTime;
-
-    // write interleaved audio frame
-    if (g_pAStream)
-    {
-        VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
-        do
-            AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
-        while (AudioTime < VideoTime && WriteAudioFrame());
-    }
-    
-    if (!g_pVStream)
-        return 0;
-
-    AVPacket Packet;
-    av_init_packet(&Packet);
-    Packet.data = NULL;
-    Packet.size = 0;
-
-    g_pVFrame->pts++;
-    if (g_pFormat->flags & AVFMT_RAWPICTURE)
-    {
-        /* raw video case. The API will change slightly in the near
-           future for that. */
-        Packet.flags |= AV_PKT_FLAG_KEY;
-        Packet.stream_index = g_pVStream->index;
-        Packet.data = (uint8_t*)pFrame;
-        Packet.size = sizeof(AVPicture);
-
-        if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
-            FatalError("Error while writing video frame");
-        return 0;
-    }
-    else
-    {
-#if LIBAVCODEC_VERSION_MAJOR >= 54
-        int got_packet;
-        if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0)
-            FatalError("avcodec_encode_video2 failed");
-        if (!got_packet)
-            return 0;
-
-        if (Packet.pts != AV_NOPTS_VALUE)
-            Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base);
-        if (Packet.dts != AV_NOPTS_VALUE)
-            Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base);
-#else 
-        Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame);
-        if (Packet.size < 0)
-            FatalError("avcodec_encode_video failed");
-        if (Packet.size == 0)
-            return 0;
-
-        if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE)
-            Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base);
-        if( g_pVideo->coded_frame->key_frame )
-            Packet.flags |= AV_PKT_FLAG_KEY;
-        Packet.data = g_OutBuffer;
-#endif
-        // write the compressed frame in the media file
-        Packet.stream_index = g_pVStream->index;
-        if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
-            FatalError("Error while writing video frame");
-            
-        return 1;
-    }
-}
-
-void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr)
-{
-    g_pVFrame->data[0] = pY;
-    g_pVFrame->data[1] = pCb;
-    g_pVFrame->data[2] = pCr;
-    WriteFrame(g_pVFrame);
-}
-
-void AVWrapper_Init(
-         void (*pAddFileLogRaw)(const char*),
-         const char* pFilename,
-         const char* pDesc,
-         const char* pSoundFile,
-         const char* pFormatName,
-         const char* pVCodecName,
-         const char* pACodecName,
-         int Width, int Height,
-         int FramerateNum, int FramerateDen,
-         int VQuality)
-{    
-    AddFileLogRaw = pAddFileLogRaw;
-    av_log_set_callback( &LogCallback );
-
-    g_Width  = Width;
-    g_Height = Height;
-    g_Framerate.num = FramerateNum;
-    g_Framerate.den = FramerateDen;
-    g_VQuality = VQuality;
-
-    // initialize libav and register all codecs and formats
-    av_register_all();
-
-    // find format
-    g_pFormat = av_guess_format(pFormatName, NULL, NULL);
-    if (!g_pFormat)
-        FatalError("Format \"%s\" was not found", pFormatName);
-
-    // allocate the output media context
-    g_pContainer = avformat_alloc_context();
-    if (!g_pContainer)
-        FatalError("Could not allocate output context");
-
-    g_pContainer->oformat = g_pFormat;
-
-    // store description of file
-    av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0);
-
-    // append extesnion to filename
-    char ext[16];
-    strncpy(ext, g_pFormat->extensions, 16);
-    ext[15] = 0;
-    ext[strcspn(ext,",")] = 0;
-    snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext);
-
-    // find codecs
-    g_pVCodec = avcodec_find_encoder_by_name(pVCodecName);
-    g_pACodec = avcodec_find_encoder_by_name(pACodecName);
-
-    // add audio and video stream to container
-    g_pVStream = NULL;
-    g_pAStream = NULL;
-
-    if (g_pVCodec)
-        AddVideoStream();
-    else
-        Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
-
-    if (g_pACodec)
-    {
-        g_pSoundFile = fopen(pSoundFile, "rb");
-        if (g_pSoundFile)
-        {
-            fread(&g_Frequency, 4, 1, g_pSoundFile);
-            fread(&g_Channels, 4, 1, g_pSoundFile);
-            AddAudioStream();
-        }
-        else
-            Log("Could not open %s\n", pSoundFile);
-    }
-    else
-        Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
-
-    if (!g_pAStream && !g_pVStream)
-        FatalError("No video, no audio, aborting...");
-
-    // write format info to log
-    av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
-
-    // open the output file, if needed
-    if (!(g_pFormat->flags & AVFMT_NOFILE))
-    {
-        if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
-            FatalError("Could not open output file (%s)", g_pContainer->filename);
-    }
-
-    // write the stream header, if any
-    avformat_write_header(g_pContainer, NULL);
-
-    g_pVFrame->pts = -1;
-}
-
-void AVWrapper_Close()
-{
-    // output buffered frames
-    if (g_pVCodec->capabilities & CODEC_CAP_DELAY)
-        while( WriteFrame(NULL) );
-    // output any remaining audio
-    while( WriteAudioFrame() );
-
-    // write the trailer, if any.
-    av_write_trailer(g_pContainer);
-
-    // close the output file
-    if (!(g_pFormat->flags & AVFMT_NOFILE))
-        avio_close(g_pContainer->pb);
-
-    // free everything
-    if (g_pVStream)
-    {
-        avcodec_close(g_pVideo);
-        av_free(g_pVideo);
-        av_free(g_pVStream);
-        av_free(g_pVFrame);
-    }
-    if (g_pAStream)
-    {
-        avcodec_close(g_pAudio);
-        av_free(g_pAudio);
-        av_free(g_pAStream);
-        av_free(g_pAFrame);
-        av_free(g_pSamples);
-        fclose(g_pSoundFile);
-    }
-
-    av_free(g_pContainer);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/avwrapper/CMakeLists.txt	Tue Mar 19 17:14:10 2013 +0100
@@ -0,0 +1,20 @@
+#FFMPEG/Libav libraries have been searched already in main CMakeLists.txt
+
+# TODO: this check is only for SDL < 2
+# fpc will take care of linking but we need to have this library installed
+find_package(GLUT REQUIRED)
+
+#TODO: convert avwrapper to .pas unit so we can skip this step
+include_directories(${FFMPEG_INCLUDE_DIR})
+
+if(WIN32)
+    # it's not possible to statically link libraries on windows, so let's build a shared version here
+    add_library(avwrapper SHARED avwrapper.c)
+
+    target_link_libraries(avwrapper ${FFMPEG_LIBRARIES})
+
+    install(PROGRAMS "${LIBRARY_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}avwrapper${CMAKE_SHARED_LIBRARY_SUFFIX}" DESTINATION ${target_library_install_dir})
+else()
+    add_library(avwrapper STATIC avwrapper.c)
+endif()
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hedgewars/avwrapper/avwrapper.c	Tue Mar 19 17:14:10 2013 +0100
@@ -0,0 +1,509 @@
+/*
+ * Hedgewars, a free turn based strategy game
+ * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ *
+ * 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; version 2 of the License
+ *
+ * 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 <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include "libavformat/avformat.h"
+#include "libavutil/mathematics.h"
+
+#ifndef AVIO_FLAG_WRITE
+#define AVIO_FLAG_WRITE AVIO_WRONLY
+#endif
+
+static AVFormatContext* g_pContainer;
+static AVOutputFormat* g_pFormat;
+static AVStream* g_pAStream;
+static AVStream* g_pVStream;
+static AVFrame* g_pAFrame;
+static AVFrame* g_pVFrame;
+static AVCodec* g_pACodec;
+static AVCodec* g_pVCodec;
+static AVCodecContext* g_pAudio;
+static AVCodecContext* g_pVideo;
+
+static int g_Width, g_Height;
+static uint32_t g_Frequency, g_Channels;
+static int g_VQuality;
+static AVRational g_Framerate;
+
+static FILE* g_pSoundFile;
+static int16_t* g_pSamples;
+static int g_NumSamples;
+
+
+#if LIBAVCODEC_VERSION_MAJOR < 54
+#define OUTBUFFER_SIZE 200000
+static uint8_t g_OutBuffer[OUTBUFFER_SIZE];
+#endif
+
+// pointer to function from hwengine (uUtils.pas)
+static void (*AddFileLogRaw)(const char* pString);
+
+static void FatalError(const char* pFmt, ...)
+{
+    char Buffer[1024];
+    va_list VaArgs;
+
+    va_start(VaArgs, pFmt);
+    vsnprintf(Buffer, 1024, pFmt, VaArgs);
+    va_end(VaArgs);
+
+    AddFileLogRaw("Error in av-wrapper: ");
+    AddFileLogRaw(Buffer);
+    AddFileLogRaw("\n");
+    exit(1);
+}
+
+// Function to be called from libav for logging.
+// Note: libav can call LogCallback from different threads
+// (there is mutex in AddFileLogRaw).
+static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs)
+{
+    char Buffer[1024];
+
+    vsnprintf(Buffer, 1024, pFmt, VaArgs);
+    AddFileLogRaw(Buffer);
+}
+
+static void Log(const char* pFmt, ...)
+{
+    char Buffer[1024];
+    va_list VaArgs;
+
+    va_start(VaArgs, pFmt);
+    vsnprintf(Buffer, 1024, pFmt, VaArgs);
+    va_end(VaArgs);
+
+    AddFileLogRaw(Buffer);
+}
+
+static void AddAudioStream()
+{
+#if LIBAVFORMAT_VERSION_MAJOR >= 53
+    g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
+#else
+    g_pAStream = av_new_stream(g_pContainer, 1);
+#endif
+    if(!g_pAStream)
+    {
+        Log("Could not allocate audio stream\n");
+        return;
+    }
+    g_pAStream->id = 1;
+
+    g_pAudio = g_pAStream->codec;
+
+    avcodec_get_context_defaults3(g_pAudio, g_pACodec);
+    g_pAudio->codec_id = g_pACodec->id;
+
+    // put parameters
+    g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
+    g_pAudio->sample_rate = g_Frequency;
+    g_pAudio->channels = g_Channels;
+
+    // set quality
+    g_pAudio->bit_rate = 160000;
+
+    // for codecs that support variable bitrate use it, it should be better
+    g_pAudio->flags |= CODEC_FLAG_QSCALE;
+    g_pAudio->global_quality = 1*FF_QP2LAMBDA;
+
+    // some formats want stream headers to be separate
+    if (g_pFormat->flags & AVFMT_GLOBALHEADER)
+        g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+    // open it
+#if LIBAVCODEC_VERSION_MAJOR >= 53
+    if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0)
+#else
+    if (avcodec_open(g_pAudio, g_pACodec) < 0)
+#endif
+    {
+        Log("Could not open audio codec %s\n", g_pACodec->long_name);
+        return;
+    }
+
+#if LIBAVCODEC_VERSION_MAJOR >= 54
+    if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
+#else
+    if (g_pAudio->frame_size == 0)
+#endif
+        g_NumSamples = 4096;
+    else
+        g_NumSamples = g_pAudio->frame_size;
+    g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t));
+    g_pAFrame = avcodec_alloc_frame();
+    if (!g_pAFrame)
+    {
+        Log("Could not allocate frame\n");
+        return;
+    }
+}
+
+// returns non-zero if there is more sound
+static int WriteAudioFrame()
+{
+    if (!g_pAStream)
+        return 0;
+
+    AVPacket Packet = { 0 };
+    av_init_packet(&Packet);
+
+    int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
+
+#if LIBAVCODEC_VERSION_MAJOR >= 53
+    AVFrame* pFrame = NULL;
+    if (NumSamples > 0)
+    {
+        g_pAFrame->nb_samples = NumSamples;
+        avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16,
+                                 (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1);
+        pFrame = g_pAFrame;
+    }
+    // when NumSamples == 0 we still need to call encode_audio2 to flush
+    int got_packet;
+    if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
+        FatalError("avcodec_encode_audio2 failed");
+    if (!got_packet)
+        return 0;
+#else
+    if (NumSamples == 0)
+        return 0;
+    int BufferSize = OUTBUFFER_SIZE;
+    if (g_pAudio->frame_size == 0)
+        BufferSize = NumSamples*g_Channels*2;
+    Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples);
+    if (Packet.size == 0)
+        return 1;
+    if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE)
+        Packet.pts = av_rescale_q(g_pAudio->coded_frame->pts, g_pAudio->time_base, g_pAStream->time_base);
+    Packet.flags |= AV_PKT_FLAG_KEY;
+    Packet.data = g_OutBuffer;
+#endif
+
+    // Write the compressed frame to the media file.
+    Packet.stream_index = g_pAStream->index;
+    if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
+        FatalError("Error while writing audio frame");
+    return 1;
+}
+
+// add a video output stream
+static void AddVideoStream()
+{
+#if LIBAVFORMAT_VERSION_MAJOR >= 53
+    g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
+#else
+    g_pVStream = av_new_stream(g_pContainer, 0);
+#endif
+    if (!g_pVStream)
+        FatalError("Could not allocate video stream");
+
+    g_pVideo = g_pVStream->codec;
+
+    avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
+    g_pVideo->codec_id = g_pVCodec->id;
+
+    // put parameters
+    // resolution must be a multiple of two
+    g_pVideo->width  = g_Width  & ~1; // make even (dimensions should be even)
+    g_pVideo->height = g_Height & ~1; // make even
+    /* time base: this is the fundamental unit of time (in seconds) in terms
+       of which frame timestamps are represented. for fixed-fps content,
+       timebase should be 1/framerate and timestamp increments should be
+       identically 1. */
+    g_pVideo->time_base.den = g_Framerate.num;
+    g_pVideo->time_base.num = g_Framerate.den;
+    //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */
+    g_pVideo->pix_fmt = PIX_FMT_YUV420P;
+
+    // set quality
+    if (g_VQuality > 100)
+        g_pVideo->bit_rate = g_VQuality;
+    else
+    {
+        g_pVideo->flags |= CODEC_FLAG_QSCALE;
+        g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA;
+    }
+
+    // some formats want stream headers to be separate
+    if (g_pFormat->flags & AVFMT_GLOBALHEADER)
+        g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+#if LIBAVCODEC_VERSION_MAJOR < 53
+    // for some versions of ffmpeg x264 options must be set explicitly
+    if (strcmp(g_pVCodec->name, "libx264") == 0)
+    {
+        g_pVideo->coder_type = FF_CODER_TYPE_AC;
+        g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER;
+        g_pVideo->crf = 23;
+        g_pVideo->thread_count = 3;
+        g_pVideo->me_cmp = FF_CMP_CHROMA;
+        g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8;
+        g_pVideo->me_method = ME_HEX;
+        g_pVideo->me_subpel_quality = 7;
+        g_pVideo->me_range = 16;
+        g_pVideo->gop_size = 250;
+        g_pVideo->keyint_min = 25;
+        g_pVideo->scenechange_threshold = 40;
+        g_pVideo->i_quant_factor = 0.71;
+        g_pVideo->b_frame_strategy = 1;
+        g_pVideo->qcompress = 0.6;
+        g_pVideo->qmin = 10;
+        g_pVideo->qmax = 51;
+        g_pVideo->max_qdiff = 4;
+        g_pVideo->max_b_frames = 3;
+        g_pVideo->refs = 3;
+        g_pVideo->directpred = 1;
+        g_pVideo->trellis = 1;
+        g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP;
+        g_pVideo->weighted_p_pred = 2;
+    }
+#endif
+
+    // open the codec
+#if LIBAVCODEC_VERSION_MAJOR >= 53
+    AVDictionary* pDict = NULL;
+    if (strcmp(g_pVCodec->name, "libx264") == 0)
+        av_dict_set(&pDict, "preset", "medium", 0);
+
+    if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
+#else
+    if (avcodec_open(g_pVideo, g_pVCodec) < 0)
+#endif
+        FatalError("Could not open video codec %s", g_pVCodec->long_name);
+
+    g_pVFrame = avcodec_alloc_frame();
+    if (!g_pVFrame)
+        FatalError("Could not allocate frame");
+
+    g_pVFrame->linesize[0] = g_Width;
+    g_pVFrame->linesize[1] = g_Width/2;
+    g_pVFrame->linesize[2] = g_Width/2;
+    g_pVFrame->linesize[3] = 0;
+}
+
+static int WriteFrame(AVFrame* pFrame)
+{
+    double AudioTime, VideoTime;
+
+    // write interleaved audio frame
+    if (g_pAStream)
+    {
+        VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
+        do
+            AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
+        while (AudioTime < VideoTime && WriteAudioFrame());
+    }
+
+    if (!g_pVStream)
+        return 0;
+
+    AVPacket Packet;
+    av_init_packet(&Packet);
+    Packet.data = NULL;
+    Packet.size = 0;
+
+    g_pVFrame->pts++;
+    if (g_pFormat->flags & AVFMT_RAWPICTURE)
+    {
+        /* raw video case. The API will change slightly in the near
+           future for that. */
+        Packet.flags |= AV_PKT_FLAG_KEY;
+        Packet.stream_index = g_pVStream->index;
+        Packet.data = (uint8_t*)pFrame;
+        Packet.size = sizeof(AVPicture);
+
+        if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
+            FatalError("Error while writing video frame");
+        return 0;
+    }
+    else
+    {
+#if LIBAVCODEC_VERSION_MAJOR >= 54
+        int got_packet;
+        if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0)
+            FatalError("avcodec_encode_video2 failed");
+        if (!got_packet)
+            return 0;
+
+        if (Packet.pts != AV_NOPTS_VALUE)
+            Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base);
+        if (Packet.dts != AV_NOPTS_VALUE)
+            Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base);
+#else
+        Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame);
+        if (Packet.size < 0)
+            FatalError("avcodec_encode_video failed");
+        if (Packet.size == 0)
+            return 0;
+
+        if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE)
+            Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base);
+        if( g_pVideo->coded_frame->key_frame )
+            Packet.flags |= AV_PKT_FLAG_KEY;
+        Packet.data = g_OutBuffer;
+#endif
+        // write the compressed frame in the media file
+        Packet.stream_index = g_pVStream->index;
+        if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
+            FatalError("Error while writing video frame");
+
+        return 1;
+    }
+}
+
+void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr)
+{
+    g_pVFrame->data[0] = pY;
+    g_pVFrame->data[1] = pCb;
+    g_pVFrame->data[2] = pCr;
+    WriteFrame(g_pVFrame);
+}
+
+void AVWrapper_Init(
+         void (*pAddFileLogRaw)(const char*),
+         const char* pFilename,
+         const char* pDesc,
+         const char* pSoundFile,
+         const char* pFormatName,
+         const char* pVCodecName,
+         const char* pACodecName,
+         int Width, int Height,
+         int FramerateNum, int FramerateDen,
+         int VQuality)
+{
+    AddFileLogRaw = pAddFileLogRaw;
+    av_log_set_callback( &LogCallback );
+
+    g_Width  = Width;
+    g_Height = Height;
+    g_Framerate.num = FramerateNum;
+    g_Framerate.den = FramerateDen;
+    g_VQuality = VQuality;
+
+    // initialize libav and register all codecs and formats
+    av_register_all();
+
+    // find format
+    g_pFormat = av_guess_format(pFormatName, NULL, NULL);
+    if (!g_pFormat)
+        FatalError("Format \"%s\" was not found", pFormatName);
+
+    // allocate the output media context
+    g_pContainer = avformat_alloc_context();
+    if (!g_pContainer)
+        FatalError("Could not allocate output context");
+
+    g_pContainer->oformat = g_pFormat;
+
+    // store description of file
+    av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0);
+
+    // append extesnion to filename
+    char ext[16];
+    strncpy(ext, g_pFormat->extensions, 16);
+    ext[15] = 0;
+    ext[strcspn(ext,",")] = 0;
+    snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext);
+
+    // find codecs
+    g_pVCodec = avcodec_find_encoder_by_name(pVCodecName);
+    g_pACodec = avcodec_find_encoder_by_name(pACodecName);
+
+    // add audio and video stream to container
+    g_pVStream = NULL;
+    g_pAStream = NULL;
+
+    if (g_pVCodec)
+        AddVideoStream();
+    else
+        Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
+
+    if (g_pACodec)
+    {
+        g_pSoundFile = fopen(pSoundFile, "rb");
+        if (g_pSoundFile)
+        {
+            fread(&g_Frequency, 4, 1, g_pSoundFile);
+            fread(&g_Channels, 4, 1, g_pSoundFile);
+            AddAudioStream();
+        }
+        else
+            Log("Could not open %s\n", pSoundFile);
+    }
+    else
+        Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
+
+    if (!g_pAStream && !g_pVStream)
+        FatalError("No video, no audio, aborting...");
+
+    // write format info to log
+    av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
+
+    // open the output file, if needed
+    if (!(g_pFormat->flags & AVFMT_NOFILE))
+    {
+        if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
+            FatalError("Could not open output file (%s)", g_pContainer->filename);
+    }
+
+    // write the stream header, if any
+    avformat_write_header(g_pContainer, NULL);
+
+    g_pVFrame->pts = -1;
+}
+
+void AVWrapper_Close()
+{
+    // output buffered frames
+    if (g_pVCodec->capabilities & CODEC_CAP_DELAY)
+        while( WriteFrame(NULL) );
+    // output any remaining audio
+    while( WriteAudioFrame() );
+
+    // write the trailer, if any.
+    av_write_trailer(g_pContainer);
+
+    // close the output file
+    if (!(g_pFormat->flags & AVFMT_NOFILE))
+        avio_close(g_pContainer->pb);
+
+    // free everything
+    if (g_pVStream)
+    {
+        avcodec_close(g_pVideo);
+        av_free(g_pVideo);
+        av_free(g_pVStream);
+        av_free(g_pVFrame);
+    }
+    if (g_pAStream)
+    {
+        avcodec_close(g_pAudio);
+        av_free(g_pAudio);
+        av_free(g_pAStream);
+        av_free(g_pAFrame);
+        av_free(g_pSamples);
+        fclose(g_pSoundFile);
+    }
+
+    av_free(g_pContainer);
+}