hedgewars/avwrapper.c
branchcmake_pascal
changeset 8811 dcdfcddf37ee
parent 8809 8ce66f1106f1
child 8813 a932b10fc1d0
equal deleted inserted replaced
8809:8ce66f1106f1 8811:dcdfcddf37ee
     1 /*
       
     2  * Hedgewars, a free turn based strategy game
       
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License as published by
       
     7  * the Free Software Foundation; version 2 of the License
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
       
    17  */
       
    18 
       
    19 #include <stdlib.h>
       
    20 #include <stdio.h>
       
    21 #include <stdint.h>
       
    22 #include <string.h>
       
    23 #include <stdarg.h>
       
    24 #include "libavformat/avformat.h"
       
    25 #include "libavutil/mathematics.h"
       
    26 
       
    27 #ifndef AVIO_FLAG_WRITE
       
    28 #define AVIO_FLAG_WRITE AVIO_WRONLY
       
    29 #endif
       
    30 
       
    31 static AVFormatContext* g_pContainer;
       
    32 static AVOutputFormat* g_pFormat;
       
    33 static AVStream* g_pAStream;
       
    34 static AVStream* g_pVStream;
       
    35 static AVFrame* g_pAFrame;
       
    36 static AVFrame* g_pVFrame;
       
    37 static AVCodec* g_pACodec;
       
    38 static AVCodec* g_pVCodec;
       
    39 static AVCodecContext* g_pAudio;
       
    40 static AVCodecContext* g_pVideo;
       
    41 
       
    42 static int g_Width, g_Height;
       
    43 static uint32_t g_Frequency, g_Channels;
       
    44 static int g_VQuality;
       
    45 static AVRational g_Framerate;
       
    46 
       
    47 static FILE* g_pSoundFile;
       
    48 static int16_t* g_pSamples;
       
    49 static int g_NumSamples;
       
    50 
       
    51 
       
    52 #if LIBAVCODEC_VERSION_MAJOR < 54
       
    53 #define OUTBUFFER_SIZE 200000
       
    54 static uint8_t g_OutBuffer[OUTBUFFER_SIZE];
       
    55 #endif
       
    56 
       
    57 // pointer to function from hwengine (uUtils.pas)
       
    58 static void (*AddFileLogRaw)(const char* pString);
       
    59 
       
    60 static void FatalError(const char* pFmt, ...)
       
    61 {
       
    62     char Buffer[1024];
       
    63     va_list VaArgs;
       
    64 
       
    65     va_start(VaArgs, pFmt);
       
    66     vsnprintf(Buffer, 1024, pFmt, VaArgs);
       
    67     va_end(VaArgs);
       
    68 
       
    69     AddFileLogRaw("Error in av-wrapper: ");
       
    70     AddFileLogRaw(Buffer);
       
    71     AddFileLogRaw("\n");
       
    72     exit(1);
       
    73 }
       
    74 
       
    75 // Function to be called from libav for logging.
       
    76 // Note: libav can call LogCallback from different threads
       
    77 // (there is mutex in AddFileLogRaw).
       
    78 static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs)
       
    79 {
       
    80     char Buffer[1024];
       
    81 
       
    82     vsnprintf(Buffer, 1024, pFmt, VaArgs);
       
    83     AddFileLogRaw(Buffer);
       
    84 }
       
    85 
       
    86 static void Log(const char* pFmt, ...)
       
    87 {
       
    88     char Buffer[1024];
       
    89     va_list VaArgs;
       
    90 
       
    91     va_start(VaArgs, pFmt);
       
    92     vsnprintf(Buffer, 1024, pFmt, VaArgs);
       
    93     va_end(VaArgs);
       
    94 
       
    95     AddFileLogRaw(Buffer);
       
    96 }
       
    97 
       
    98 static void AddAudioStream()
       
    99 {
       
   100 #if LIBAVFORMAT_VERSION_MAJOR >= 53
       
   101     g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
       
   102 #else
       
   103     g_pAStream = av_new_stream(g_pContainer, 1);
       
   104 #endif
       
   105     if(!g_pAStream)
       
   106     {
       
   107         Log("Could not allocate audio stream\n");
       
   108         return;
       
   109     }
       
   110     g_pAStream->id = 1;
       
   111 
       
   112     g_pAudio = g_pAStream->codec;
       
   113 
       
   114     avcodec_get_context_defaults3(g_pAudio, g_pACodec);
       
   115     g_pAudio->codec_id = g_pACodec->id;
       
   116 
       
   117     // put parameters
       
   118     g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
       
   119     g_pAudio->sample_rate = g_Frequency;
       
   120     g_pAudio->channels = g_Channels;
       
   121 
       
   122     // set quality
       
   123     g_pAudio->bit_rate = 160000;
       
   124 
       
   125     // for codecs that support variable bitrate use it, it should be better
       
   126     g_pAudio->flags |= CODEC_FLAG_QSCALE;
       
   127     g_pAudio->global_quality = 1*FF_QP2LAMBDA;
       
   128 
       
   129     // some formats want stream headers to be separate
       
   130     if (g_pFormat->flags & AVFMT_GLOBALHEADER)
       
   131         g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER;
       
   132 
       
   133     // open it
       
   134 #if LIBAVCODEC_VERSION_MAJOR >= 53
       
   135     if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0)
       
   136 #else
       
   137     if (avcodec_open(g_pAudio, g_pACodec) < 0)
       
   138 #endif
       
   139     {
       
   140         Log("Could not open audio codec %s\n", g_pACodec->long_name);
       
   141         return;
       
   142     }
       
   143 
       
   144 #if LIBAVCODEC_VERSION_MAJOR >= 54
       
   145     if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
       
   146 #else
       
   147     if (g_pAudio->frame_size == 0)
       
   148 #endif
       
   149         g_NumSamples = 4096;
       
   150     else
       
   151         g_NumSamples = g_pAudio->frame_size;
       
   152     g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t));
       
   153     g_pAFrame = avcodec_alloc_frame();
       
   154     if (!g_pAFrame)
       
   155     {
       
   156         Log("Could not allocate frame\n");
       
   157         return;
       
   158     }
       
   159 }
       
   160 
       
   161 // returns non-zero if there is more sound
       
   162 static int WriteAudioFrame()
       
   163 {
       
   164     if (!g_pAStream)
       
   165         return 0;
       
   166 
       
   167     AVPacket Packet = { 0 };
       
   168     av_init_packet(&Packet);
       
   169 
       
   170     int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
       
   171 
       
   172 #if LIBAVCODEC_VERSION_MAJOR >= 53
       
   173     AVFrame* pFrame = NULL;
       
   174     if (NumSamples > 0)
       
   175     {
       
   176         g_pAFrame->nb_samples = NumSamples;
       
   177         avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16,
       
   178                                  (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1);
       
   179         pFrame = g_pAFrame;
       
   180     }
       
   181     // when NumSamples == 0 we still need to call encode_audio2 to flush
       
   182     int got_packet;
       
   183     if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
       
   184         FatalError("avcodec_encode_audio2 failed");
       
   185     if (!got_packet)
       
   186         return 0;
       
   187 #else
       
   188     if (NumSamples == 0)
       
   189         return 0;
       
   190     int BufferSize = OUTBUFFER_SIZE;
       
   191     if (g_pAudio->frame_size == 0)
       
   192         BufferSize = NumSamples*g_Channels*2;
       
   193     Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples);
       
   194     if (Packet.size == 0)
       
   195         return 1;
       
   196     if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE)
       
   197         Packet.pts = av_rescale_q(g_pAudio->coded_frame->pts, g_pAudio->time_base, g_pAStream->time_base);
       
   198     Packet.flags |= AV_PKT_FLAG_KEY;
       
   199     Packet.data = g_OutBuffer;
       
   200 #endif
       
   201 
       
   202     // Write the compressed frame to the media file.
       
   203     Packet.stream_index = g_pAStream->index;
       
   204     if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) 
       
   205         FatalError("Error while writing audio frame");
       
   206     return 1;
       
   207 }
       
   208 
       
   209 // add a video output stream
       
   210 static void AddVideoStream()
       
   211 {
       
   212 #if LIBAVFORMAT_VERSION_MAJOR >= 53
       
   213     g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
       
   214 #else
       
   215     g_pVStream = av_new_stream(g_pContainer, 0);
       
   216 #endif
       
   217     if (!g_pVStream)
       
   218         FatalError("Could not allocate video stream");
       
   219 
       
   220     g_pVideo = g_pVStream->codec;
       
   221 
       
   222     avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
       
   223     g_pVideo->codec_id = g_pVCodec->id;
       
   224 
       
   225     // put parameters
       
   226     // resolution must be a multiple of two
       
   227     g_pVideo->width  = g_Width  & ~1; // make even (dimensions should be even)
       
   228     g_pVideo->height = g_Height & ~1; // make even
       
   229     /* time base: this is the fundamental unit of time (in seconds) in terms
       
   230        of which frame timestamps are represented. for fixed-fps content,
       
   231        timebase should be 1/framerate and timestamp increments should be
       
   232        identically 1. */
       
   233     g_pVideo->time_base.den = g_Framerate.num;
       
   234     g_pVideo->time_base.num = g_Framerate.den;
       
   235     //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */
       
   236     g_pVideo->pix_fmt = PIX_FMT_YUV420P;
       
   237 
       
   238     // set quality
       
   239     if (g_VQuality > 100)
       
   240         g_pVideo->bit_rate = g_VQuality;
       
   241     else
       
   242     {
       
   243         g_pVideo->flags |= CODEC_FLAG_QSCALE;
       
   244         g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA;
       
   245     }
       
   246 
       
   247     // some formats want stream headers to be separate
       
   248     if (g_pFormat->flags & AVFMT_GLOBALHEADER)
       
   249         g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
       
   250 
       
   251 #if LIBAVCODEC_VERSION_MAJOR < 53
       
   252     // for some versions of ffmpeg x264 options must be set explicitly
       
   253     if (strcmp(g_pVCodec->name, "libx264") == 0)
       
   254     {
       
   255         g_pVideo->coder_type = FF_CODER_TYPE_AC;
       
   256         g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER;
       
   257         g_pVideo->crf = 23;
       
   258         g_pVideo->thread_count = 3;
       
   259         g_pVideo->me_cmp = FF_CMP_CHROMA;
       
   260         g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8;
       
   261         g_pVideo->me_method = ME_HEX;
       
   262         g_pVideo->me_subpel_quality = 7;
       
   263         g_pVideo->me_range = 16;
       
   264         g_pVideo->gop_size = 250;
       
   265         g_pVideo->keyint_min = 25;
       
   266         g_pVideo->scenechange_threshold = 40;
       
   267         g_pVideo->i_quant_factor = 0.71;
       
   268         g_pVideo->b_frame_strategy = 1;
       
   269         g_pVideo->qcompress = 0.6;
       
   270         g_pVideo->qmin = 10;
       
   271         g_pVideo->qmax = 51;
       
   272         g_pVideo->max_qdiff = 4;
       
   273         g_pVideo->max_b_frames = 3;
       
   274         g_pVideo->refs = 3;
       
   275         g_pVideo->directpred = 1;
       
   276         g_pVideo->trellis = 1;
       
   277         g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP;
       
   278         g_pVideo->weighted_p_pred = 2;
       
   279     }
       
   280 #endif
       
   281 
       
   282     // open the codec
       
   283 #if LIBAVCODEC_VERSION_MAJOR >= 53
       
   284     AVDictionary* pDict = NULL;
       
   285     if (strcmp(g_pVCodec->name, "libx264") == 0)
       
   286         av_dict_set(&pDict, "preset", "medium", 0);
       
   287 
       
   288     if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
       
   289 #else
       
   290     if (avcodec_open(g_pVideo, g_pVCodec) < 0)
       
   291 #endif
       
   292         FatalError("Could not open video codec %s", g_pVCodec->long_name);
       
   293 
       
   294     g_pVFrame = avcodec_alloc_frame();
       
   295     if (!g_pVFrame)
       
   296         FatalError("Could not allocate frame");
       
   297 
       
   298     g_pVFrame->linesize[0] = g_Width;
       
   299     g_pVFrame->linesize[1] = g_Width/2;
       
   300     g_pVFrame->linesize[2] = g_Width/2;
       
   301     g_pVFrame->linesize[3] = 0;
       
   302 }
       
   303 
       
   304 static int WriteFrame(AVFrame* pFrame)
       
   305 {
       
   306     double AudioTime, VideoTime;
       
   307 
       
   308     // write interleaved audio frame
       
   309     if (g_pAStream)
       
   310     {
       
   311         VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
       
   312         do
       
   313             AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
       
   314         while (AudioTime < VideoTime && WriteAudioFrame());
       
   315     }
       
   316     
       
   317     if (!g_pVStream)
       
   318         return 0;
       
   319 
       
   320     AVPacket Packet;
       
   321     av_init_packet(&Packet);
       
   322     Packet.data = NULL;
       
   323     Packet.size = 0;
       
   324 
       
   325     g_pVFrame->pts++;
       
   326     if (g_pFormat->flags & AVFMT_RAWPICTURE)
       
   327     {
       
   328         /* raw video case. The API will change slightly in the near
       
   329            future for that. */
       
   330         Packet.flags |= AV_PKT_FLAG_KEY;
       
   331         Packet.stream_index = g_pVStream->index;
       
   332         Packet.data = (uint8_t*)pFrame;
       
   333         Packet.size = sizeof(AVPicture);
       
   334 
       
   335         if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
       
   336             FatalError("Error while writing video frame");
       
   337         return 0;
       
   338     }
       
   339     else
       
   340     {
       
   341 #if LIBAVCODEC_VERSION_MAJOR >= 54
       
   342         int got_packet;
       
   343         if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0)
       
   344             FatalError("avcodec_encode_video2 failed");
       
   345         if (!got_packet)
       
   346             return 0;
       
   347 
       
   348         if (Packet.pts != AV_NOPTS_VALUE)
       
   349             Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base);
       
   350         if (Packet.dts != AV_NOPTS_VALUE)
       
   351             Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base);
       
   352 #else 
       
   353         Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame);
       
   354         if (Packet.size < 0)
       
   355             FatalError("avcodec_encode_video failed");
       
   356         if (Packet.size == 0)
       
   357             return 0;
       
   358 
       
   359         if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE)
       
   360             Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base);
       
   361         if( g_pVideo->coded_frame->key_frame )
       
   362             Packet.flags |= AV_PKT_FLAG_KEY;
       
   363         Packet.data = g_OutBuffer;
       
   364 #endif
       
   365         // write the compressed frame in the media file
       
   366         Packet.stream_index = g_pVStream->index;
       
   367         if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
       
   368             FatalError("Error while writing video frame");
       
   369             
       
   370         return 1;
       
   371     }
       
   372 }
       
   373 
       
   374 void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr)
       
   375 {
       
   376     g_pVFrame->data[0] = pY;
       
   377     g_pVFrame->data[1] = pCb;
       
   378     g_pVFrame->data[2] = pCr;
       
   379     WriteFrame(g_pVFrame);
       
   380 }
       
   381 
       
   382 void AVWrapper_Init(
       
   383          void (*pAddFileLogRaw)(const char*),
       
   384          const char* pFilename,
       
   385          const char* pDesc,
       
   386          const char* pSoundFile,
       
   387          const char* pFormatName,
       
   388          const char* pVCodecName,
       
   389          const char* pACodecName,
       
   390          int Width, int Height,
       
   391          int FramerateNum, int FramerateDen,
       
   392          int VQuality)
       
   393 {    
       
   394     AddFileLogRaw = pAddFileLogRaw;
       
   395     av_log_set_callback( &LogCallback );
       
   396 
       
   397     g_Width  = Width;
       
   398     g_Height = Height;
       
   399     g_Framerate.num = FramerateNum;
       
   400     g_Framerate.den = FramerateDen;
       
   401     g_VQuality = VQuality;
       
   402 
       
   403     // initialize libav and register all codecs and formats
       
   404     av_register_all();
       
   405 
       
   406     // find format
       
   407     g_pFormat = av_guess_format(pFormatName, NULL, NULL);
       
   408     if (!g_pFormat)
       
   409         FatalError("Format \"%s\" was not found", pFormatName);
       
   410 
       
   411     // allocate the output media context
       
   412     g_pContainer = avformat_alloc_context();
       
   413     if (!g_pContainer)
       
   414         FatalError("Could not allocate output context");
       
   415 
       
   416     g_pContainer->oformat = g_pFormat;
       
   417 
       
   418     // store description of file
       
   419     av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0);
       
   420 
       
   421     // append extesnion to filename
       
   422     char ext[16];
       
   423     strncpy(ext, g_pFormat->extensions, 16);
       
   424     ext[15] = 0;
       
   425     ext[strcspn(ext,",")] = 0;
       
   426     snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext);
       
   427 
       
   428     // find codecs
       
   429     g_pVCodec = avcodec_find_encoder_by_name(pVCodecName);
       
   430     g_pACodec = avcodec_find_encoder_by_name(pACodecName);
       
   431 
       
   432     // add audio and video stream to container
       
   433     g_pVStream = NULL;
       
   434     g_pAStream = NULL;
       
   435 
       
   436     if (g_pVCodec)
       
   437         AddVideoStream();
       
   438     else
       
   439         Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
       
   440 
       
   441     if (g_pACodec)
       
   442     {
       
   443         g_pSoundFile = fopen(pSoundFile, "rb");
       
   444         if (g_pSoundFile)
       
   445         {
       
   446             fread(&g_Frequency, 4, 1, g_pSoundFile);
       
   447             fread(&g_Channels, 4, 1, g_pSoundFile);
       
   448             AddAudioStream();
       
   449         }
       
   450         else
       
   451             Log("Could not open %s\n", pSoundFile);
       
   452     }
       
   453     else
       
   454         Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
       
   455 
       
   456     if (!g_pAStream && !g_pVStream)
       
   457         FatalError("No video, no audio, aborting...");
       
   458 
       
   459     // write format info to log
       
   460     av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
       
   461 
       
   462     // open the output file, if needed
       
   463     if (!(g_pFormat->flags & AVFMT_NOFILE))
       
   464     {
       
   465         if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
       
   466             FatalError("Could not open output file (%s)", g_pContainer->filename);
       
   467     }
       
   468 
       
   469     // write the stream header, if any
       
   470     avformat_write_header(g_pContainer, NULL);
       
   471 
       
   472     g_pVFrame->pts = -1;
       
   473 }
       
   474 
       
   475 void AVWrapper_Close()
       
   476 {
       
   477     // output buffered frames
       
   478     if (g_pVCodec->capabilities & CODEC_CAP_DELAY)
       
   479         while( WriteFrame(NULL) );
       
   480     // output any remaining audio
       
   481     while( WriteAudioFrame() );
       
   482 
       
   483     // write the trailer, if any.
       
   484     av_write_trailer(g_pContainer);
       
   485 
       
   486     // close the output file
       
   487     if (!(g_pFormat->flags & AVFMT_NOFILE))
       
   488         avio_close(g_pContainer->pb);
       
   489 
       
   490     // free everything
       
   491     if (g_pVStream)
       
   492     {
       
   493         avcodec_close(g_pVideo);
       
   494         av_free(g_pVideo);
       
   495         av_free(g_pVStream);
       
   496         av_free(g_pVFrame);
       
   497     }
       
   498     if (g_pAStream)
       
   499     {
       
   500         avcodec_close(g_pAudio);
       
   501         av_free(g_pAudio);
       
   502         av_free(g_pAStream);
       
   503         av_free(g_pAFrame);
       
   504         av_free(g_pSamples);
       
   505         fclose(g_pSoundFile);
       
   506     }
       
   507 
       
   508     av_free(g_pContainer);
       
   509 }