hedgewars/avwrapper.c
changeset 7198 5debd5fe526e
parent 7180 53ffc8853008
child 7235 baa69bd025d9
equal deleted inserted replaced
7196:4fba5519c37f 7198:5debd5fe526e
    14 static AVCodec* g_pACodec;
    14 static AVCodec* g_pACodec;
    15 static AVCodec* g_pVCodec;
    15 static AVCodec* g_pVCodec;
    16 static AVCodecContext* g_pAudio;
    16 static AVCodecContext* g_pAudio;
    17 static AVCodecContext* g_pVideo;
    17 static AVCodecContext* g_pVideo;
    18 
    18 
    19 static int g_Width, g_Height, g_Framerate;
    19 static int g_Width, g_Height;
    20 static int g_Frequency, g_Channels;
    20 static int g_Frequency, g_Channels;
       
    21 static int g_VQuality, g_AQuality;
       
    22 static AVRational g_Framerate;
       
    23 static const char* g_pPreset;
    21 
    24 
    22 static FILE* g_pSoundFile;
    25 static FILE* g_pSoundFile;
    23 static int16_t* g_pSamples;
    26 static int16_t* g_pSamples;
    24 static int g_NumSamples;
    27 static int g_NumSamples;
    25 
    28 
    75     va_end(VaArgs);
    78     va_end(VaArgs);
    76 
    79 
    77     AddFileLogRaw(Buffer);
    80     AddFileLogRaw(Buffer);
    78 }
    81 }
    79 
    82 
    80 static void AddAudioStream(enum CodecID codec_id)
    83 static void AddAudioStream()
    81 {
    84 {
    82 #if LIBAVCODEC_VERSION_MAJOR >= 54
    85 #if LIBAVCODEC_VERSION_MAJOR >= 54
    83     g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
    86     g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
    84 #else
    87 #else
    85     g_pAStream = av_new_stream(g_pContainer, 1);
    88     g_pAStream = av_new_stream(g_pContainer, 1);
    87     if(!g_pAStream)
    90     if(!g_pAStream)
    88         FatalError("Could not allocate audio stream");
    91         FatalError("Could not allocate audio stream");
    89     g_pAStream->id = 1;
    92     g_pAStream->id = 1;
    90 
    93 
    91     g_pAudio = g_pAStream->codec;
    94     g_pAudio = g_pAStream->codec;
       
    95 
    92     avcodec_get_context_defaults3(g_pAudio, g_pACodec);
    96     avcodec_get_context_defaults3(g_pAudio, g_pACodec);
    93     g_pAudio->codec_id = codec_id;
    97     g_pAudio->codec_id = g_pACodec->id;
    94 
    98 
    95     // put parameters
    99     // put parameters
    96     g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
   100     g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
    97  //   pContext->bit_rate = 128000;
       
    98     g_pAudio->sample_rate = g_Frequency;
   101     g_pAudio->sample_rate = g_Frequency;
    99     g_pAudio->channels = g_Channels;
   102     g_pAudio->channels = g_Channels;
       
   103 
       
   104     // set quality
       
   105     if (g_AQuality > 100)
       
   106         g_pAudio->bit_rate = g_AQuality;
       
   107     else
       
   108     {
       
   109         g_pAudio->flags |= CODEC_FLAG_QSCALE;
       
   110         g_pAudio->global_quality = g_AQuality*FF_QP2LAMBDA;
       
   111     }
   100 
   112 
   101     // some formats want stream headers to be separate
   113     // some formats want stream headers to be separate
   102     if (g_pFormat->flags & AVFMT_GLOBALHEADER)
   114     if (g_pFormat->flags & AVFMT_GLOBALHEADER)
   103         g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER;
   115         g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER;
   104 
   116 
   121 }
   133 }
   122 
   134 
   123 // returns non-zero if there is more sound
   135 // returns non-zero if there is more sound
   124 static int WriteAudioFrame()
   136 static int WriteAudioFrame()
   125 {
   137 {
       
   138     if (!g_pAStream)
       
   139         return 0;
       
   140 
   126     AVPacket Packet = { 0 };
   141     AVPacket Packet = { 0 };
   127     av_init_packet(&Packet);
   142     av_init_packet(&Packet);
   128 
   143 
   129     int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
   144     int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
   130 
   145 
   164         FatalError("Error while writing audio frame");
   179         FatalError("Error while writing audio frame");
   165     return 1;
   180     return 1;
   166 }
   181 }
   167 
   182 
   168 // add a video output stream
   183 // add a video output stream
   169 static void AddVideoStream(enum CodecID codec_id)
   184 static void AddVideoStream()
   170 {
   185 {
   171 #if LIBAVCODEC_VERSION_MAJOR >= 54
   186 #if LIBAVCODEC_VERSION_MAJOR >= 54
   172     g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
   187     g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
   173 #else
   188 #else
   174     g_pVStream = av_new_stream(g_pContainer, 0);
   189     g_pVStream = av_new_stream(g_pContainer, 0);
   175 #endif
   190 #endif
   176     if (!g_pVStream)
   191     if (!g_pVStream)
   177         FatalError("Could not allocate video stream");
   192         FatalError("Could not allocate video stream");
   178 
   193 
   179     g_pVideo = g_pVStream->codec;
   194     g_pVideo = g_pVStream->codec;
   180     avcodec_get_context_defaults3( g_pVideo, g_pVCodec );
   195     
   181     g_pVideo->codec_id = codec_id;
   196     avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
       
   197     g_pVideo->codec_id = g_pVCodec->id;
   182 
   198 
   183     // put parameters
   199     // put parameters
   184     // resolution must be a multiple of two
   200     // resolution must be a multiple of two
   185     g_pVideo->width = g_Width;
   201     g_pVideo->width = g_Width;
   186     g_pVideo->height = g_Height;
   202     g_pVideo->height = g_Height;
   187     /* time base: this is the fundamental unit of time (in seconds) in terms
   203     /* time base: this is the fundamental unit of time (in seconds) in terms
   188        of which frame timestamps are represented. for fixed-fps content,
   204        of which frame timestamps are represented. for fixed-fps content,
   189        timebase should be 1/framerate and timestamp increments should be
   205        timebase should be 1/framerate and timestamp increments should be
   190        identically 1. */
   206        identically 1. */
   191     g_pVideo->time_base.den = g_Framerate;
   207     g_pVideo->time_base.den = g_Framerate.num;
   192     g_pVideo->time_base.num = 1;
   208     g_pVideo->time_base.num = g_Framerate.den;
   193     //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */
   209     //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */
   194     g_pVideo->pix_fmt = PIX_FMT_YUV420P;
   210     g_pVideo->pix_fmt = PIX_FMT_YUV420P;
       
   211 
       
   212     // set quality
       
   213     if (g_VQuality > 100)
       
   214         g_pVideo->bit_rate = g_VQuality;
       
   215     else
       
   216     {
       
   217         g_pVideo->flags |= CODEC_FLAG_QSCALE;
       
   218         g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA;
       
   219     }
       
   220 
       
   221     AVDictionary* pDict = NULL;
       
   222     if (strcmp(g_pVCodec->name, "libx264") == 0)
       
   223         av_dict_set(&pDict, "preset", g_pPreset, 0);
   195 
   224 
   196     // some formats want stream headers to be separate
   225     // some formats want stream headers to be separate
   197     if (g_pFormat->flags & AVFMT_GLOBALHEADER)
   226     if (g_pFormat->flags & AVFMT_GLOBALHEADER)
   198         g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
   227         g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER;
   199 
       
   200     AVDictionary* pDict = NULL;
       
   201     if (codec_id == CODEC_ID_H264)
       
   202     {
       
   203        // av_dict_set(&pDict, "tune", "animation", 0);
       
   204        // av_dict_set(&pDict, "preset", "veryslow", 0);
       
   205        av_dict_set(&pDict, "crf", "20", 0);
       
   206     }
       
   207     else
       
   208     {
       
   209         g_pVideo->flags |= CODEC_FLAG_QSCALE;
       
   210        // g_pVideo->bit_rate = g_Width*g_Height*g_Framerate/4;
       
   211         g_pVideo->global_quality = 15*FF_QP2LAMBDA;
       
   212     }
       
   213 
   228 
   214     // open the codec
   229     // open the codec
   215     if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
   230     if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
   216         FatalError("Could not open video codec %s", g_pVCodec->long_name);
   231         FatalError("Could not open video codec %s", g_pVCodec->long_name);
   217 
   232 
   235         VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
   250         VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
   236         do
   251         do
   237             AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
   252             AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
   238         while (AudioTime < VideoTime && WriteAudioFrame());
   253         while (AudioTime < VideoTime && WriteAudioFrame());
   239     }
   254     }
       
   255     
       
   256     if (!g_pVStream)
       
   257         return 0;
   240 
   258 
   241     AVPacket Packet;
   259     AVPacket Packet;
   242     av_init_packet(&Packet);
   260     av_init_packet(&Packet);
   243     Packet.data = NULL;
   261     Packet.data = NULL;
   244     Packet.size = 0;
   262     Packet.size = 0;
   298     g_pVFrame->data[1] = pCb;
   316     g_pVFrame->data[1] = pCb;
   299     g_pVFrame->data[2] = pCr;
   317     g_pVFrame->data[2] = pCr;
   300     WriteFrame(g_pVFrame);
   318     WriteFrame(g_pVFrame);
   301 }
   319 }
   302 
   320 
   303 void AVWrapper_GetList()
   321 void AVWrapper_Init(
   304 {
   322          void (*pAddFileLogRaw)(const char*),
   305     // initialize libav and register all codecs and formats
   323          const char* pFilename,
   306     av_register_all();
   324          const char* pSoundFile,
   307 
   325          const char* pFormatName,
   308 #if 0
   326          const char* pVCodecName,
   309     AVOutputFormat* pFormat = NULL;
   327          const char* pACodecName,
   310     while (pFormat = av_oformat_next(pFormat))
   328          const char* pVPreset,
   311     {
   329          int Width, int Height,
   312         Log("%s; %s; %s;\n", pFormat->name, pFormat->long_name, pFormat->mime_type);
   330          int FramerateNum, int FramerateDen,
   313         
   331          int Frequency, int Channels,
   314         AVCodec* pCodec = NULL;
   332          int VQuality, int AQuality)
   315         while (pCodec = av_codec_next(pCodec))
       
   316         {
       
   317             if (!av_codec_is_encoder(pCodec))
       
   318                 continue;
       
   319             if (avformat_query_codec(pFormat, pCodec->id, FF_COMPLIANCE_NORMAL) != 1)
       
   320                 continue;
       
   321             if (pCodec->type = AVMEDIA_TYPE_VIDEO)
       
   322             {
       
   323                 if (pCodec->supported_framerate != NULL)
       
   324                     continue;
       
   325                 Log("    Video: %s; %s;\n", pCodec->name, pCodec->long_name);
       
   326             }
       
   327             if (pCodec->type = AVMEDIA_TYPE_AUDIO)
       
   328             {
       
   329                /* if (pCodec->supported_samplerates == NULL)
       
   330                     continue;
       
   331                 int i;
       
   332                 for(i = 0; i <)
       
   333                     supported_samplerates*/
       
   334                 Log("    Audio: %s; %s;\n", pCodec->name, pCodec->long_name);
       
   335             }
       
   336         }
       
   337    /*     struct AVCodecTag** pTags = pCur->codec_tag;
       
   338         int i;
       
   339         for (i = 0; ; i++)
       
   340         {
       
   341             enum CodecID id = av_codec_get_id(pTags, i);
       
   342             if (id == CODEC_ID_NONE)
       
   343                 break;
       
   344             AVCodec* pCodec = avcodec_find_encoder(id);
       
   345             Log("    %i: %s; %s;\n", id, pCodec->name, pCodec->long_name);
       
   346         }*/
       
   347     }
       
   348 #endif
       
   349 }
       
   350 
       
   351 void AVWrapper_Init(void (*pAddFileLogRaw)(const char*), const char* pFilename, const char* pSoundFile, int Width, int Height, int Framerate, int Frequency, int Channels)
       
   352 {    
   333 {    
   353     AddFileLogRaw = pAddFileLogRaw;
   334     AddFileLogRaw = pAddFileLogRaw;
   354     av_log_set_callback( &LogCallback );
   335     av_log_set_callback( &LogCallback );
   355 
   336 
   356     g_Width = Width;
   337     g_Width = Width;
   357     g_Height = Height;
   338     g_Height = Height;
   358     g_Framerate = Framerate;
   339     g_Framerate.num = FramerateNum;
       
   340     g_Framerate.den = FramerateDen;
   359     g_Frequency = Frequency;
   341     g_Frequency = Frequency;
   360     g_Channels = Channels;
   342     g_Channels = Channels;
       
   343     g_VQuality = VQuality;
       
   344     g_AQuality = AQuality;
       
   345     g_pPreset = pVPreset;
   361 
   346 
   362     // initialize libav and register all codecs and formats
   347     // initialize libav and register all codecs and formats
   363     av_register_all();
   348     av_register_all();
   364     
   349 
   365     AVWrapper_GetList();
   350     // find format
   366 
   351     g_pFormat = av_guess_format(pFormatName, NULL, NULL);
   367     // allocate the output media context
       
   368 #if LIBAVCODEC_VERSION_MAJOR >= 54
       
   369     avformat_alloc_output_context2(&g_pContainer, NULL, "mp4", pFilename);
       
   370 #else
       
   371     g_pFormat = av_guess_format(NULL, pFilename, NULL);
       
   372     if (!g_pFormat)
   352     if (!g_pFormat)
   373         FatalError("guess_format");
   353         FatalError("Format \"%s\" was not found", pFormatName);
   374 
   354 
   375     // allocate the output media context
   355     // allocate the output media context
   376     g_pContainer = avformat_alloc_context();
   356     g_pContainer = avformat_alloc_context();
   377     if (g_pContainer)
       
   378     {
       
   379         g_pContainer->oformat = g_pFormat;
       
   380         snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s", pFilename);
       
   381     }
       
   382 #endif
       
   383     if (!g_pContainer)
   357     if (!g_pContainer)
   384         FatalError("Could not allocate output context");
   358         FatalError("Could not allocate output context");
   385 
   359 
   386     g_pFormat = g_pContainer->oformat;
   360     g_pContainer->oformat = g_pFormat;
   387 
   361 
   388     enum CodecID VideoCodecID = g_pFormat->video_codec;//CODEC_ID_H264;
   362     // append extesnion to filename
   389     enum CodecID AudioCodecID = g_pFormat->audio_codec;
   363     snprintf(g_pContainer->filename, sizeof(g_pContainer->filename),
   390 
   364              "%s.%*s",
       
   365              pFilename,
       
   366              strcspn(g_pFormat->extensions, ","), g_pFormat->extensions);
       
   367 
       
   368     // find codecs
       
   369     g_pVCodec = avcodec_find_encoder_by_name(pVCodecName);
       
   370     g_pACodec = avcodec_find_encoder_by_name(pACodecName);
       
   371 
       
   372     // add audio and video stream to container
   391     g_pVStream = NULL;
   373     g_pVStream = NULL;
   392     g_pAStream = NULL;
   374     g_pAStream = NULL;
   393     if (VideoCodecID != CODEC_ID_NONE)
   375 
   394     {
   376     if (g_pVCodec)
   395         g_pVCodec = avcodec_find_encoder(VideoCodecID);
   377         AddVideoStream();
   396         if (!g_pVCodec)
   378     else
   397             FatalError("Video codec not found");
   379         Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
   398         AddVideoStream(VideoCodecID);
   380 
   399     }
   381     if (g_pACodec)
   400 
   382         AddAudioStream();
   401     if (AudioCodecID != CODEC_ID_NONE)
   383     else
   402     {
   384         Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
   403         g_pACodec = avcodec_find_encoder(AudioCodecID);
   385 
   404         if (!g_pACodec)
   386     if (!g_pAStream && !g_pVStream)
   405             FatalError("Audio codec not found");
   387         FatalError("No video, no audio, aborting...");
   406         AddAudioStream(AudioCodecID);
       
   407     }
       
   408 
   388 
   409     if (g_pAStream)
   389     if (g_pAStream)
   410     {
   390     {
   411         g_pSoundFile = fopen(pSoundFile, "rb");
   391         g_pSoundFile = fopen(pSoundFile, "rb");
   412         if (!g_pSoundFile)
   392         if (!g_pSoundFile)
   413             FatalError("Could not open %s", pSoundFile);
   393             FatalError("Could not open %s", pSoundFile);
   414     }
   394     }
   415 
   395 
   416     // write format info to log
   396     // write format info to log
   417     av_dump_format(g_pContainer, 0, pFilename, 1);
   397     av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
   418 
   398 
   419     // open the output file, if needed
   399     // open the output file, if needed
   420     if (!(g_pFormat->flags & AVFMT_NOFILE))
   400     if (!(g_pFormat->flags & AVFMT_NOFILE))
   421     {
   401     {
   422         if (avio_open(&g_pContainer->pb, pFilename, AVIO_FLAG_WRITE) < 0)
   402         if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
   423             FatalError("Could not open output file (%s)", pFilename);
   403             FatalError("Could not open output file (%s)", pFilename);
   424     }
   404     }
   425 
   405 
   426     // write the stream header, if any
   406     // write the stream header, if any
   427     avformat_write_header(g_pContainer, NULL);
   407     avformat_write_header(g_pContainer, NULL);
       
   408 
   428     g_pVFrame->pts = -1;
   409     g_pVFrame->pts = -1;
   429 }
   410 }
   430 
   411 
   431 void AVWrapper_Close()
   412 void AVWrapper_Close()
   432 {
   413 {
   437     while( WriteAudioFrame() );
   418     while( WriteAudioFrame() );
   438 
   419 
   439     // write the trailer, if any.
   420     // write the trailer, if any.
   440     av_write_trailer(g_pContainer);
   421     av_write_trailer(g_pContainer);
   441 
   422 
   442     // close each codec
   423     // close the output file
   443     if( g_pVStream )
   424     if (!(g_pFormat->flags & AVFMT_NOFILE))
   444     {
   425         avio_close(g_pContainer->pb);
   445         avcodec_close(g_pVStream->codec);
   426 
       
   427     // free everything
       
   428     if (g_pVStream)
       
   429     {
       
   430         avcodec_close(g_pVideo);
       
   431         av_free(g_pVideo);
       
   432         av_free(g_pVStream);
   446         av_free(g_pVFrame);
   433         av_free(g_pVFrame);
   447     }
   434     }
   448     if( g_pAStream )
   435     if (g_pAStream)
   449     {
   436     {
   450         avcodec_close(g_pAStream->codec);
   437         avcodec_close(g_pAudio);
       
   438         av_free(g_pAudio);
       
   439         av_free(g_pAStream);
   451         av_free(g_pAFrame);
   440         av_free(g_pAFrame);
   452         av_free(g_pSamples);
   441         av_free(g_pSamples);
   453         fclose(g_pSoundFile);
   442         fclose(g_pSoundFile);
   454     }
   443     }
   455 
   444 
   456     // free the streams
       
   457     int i;
       
   458     for (i = 0; i < g_pContainer->nb_streams; i++)
       
   459     {
       
   460         av_freep(&g_pContainer->streams[i]->codec);
       
   461         av_freep(&g_pContainer->streams[i]);
       
   462     }
       
   463 
       
   464     // close the output file
       
   465     if (!(g_pFormat->flags & AVFMT_NOFILE))
       
   466         avio_close(g_pContainer->pb);
       
   467 
       
   468     // free the stream 
       
   469     av_free(g_pContainer);
   445     av_free(g_pContainer);
   470 }
   446 }