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