hedgewars/avwrapper/avwrapper.c
branch0.9.20
changeset 9901 e33178322a8f
parent 9224 bce8cf41d666
child 9903 dae338c8c19c
equal deleted inserted replaced
9899:5b8bde62a8ef 9901:e33178322a8f
    63 #endif
    63 #endif
    64 
    64 
    65 // pointer to function from hwengine (uUtils.pas)
    65 // pointer to function from hwengine (uUtils.pas)
    66 static void (*AddFileLogRaw)(const char* pString);
    66 static void (*AddFileLogRaw)(const char* pString);
    67 
    67 
    68 static void FatalError(const char* pFmt, ...)
    68 static int FatalError(const char* pFmt, ...)
    69 {
    69 {
    70     char Buffer[1024];
    70     char Buffer[1024];
    71     va_list VaArgs;
    71     va_list VaArgs;
    72 
    72 
    73     va_start(VaArgs, pFmt);
    73     va_start(VaArgs, pFmt);
    75     va_end(VaArgs);
    75     va_end(VaArgs);
    76 
    76 
    77     AddFileLogRaw("Error in av-wrapper: ");
    77     AddFileLogRaw("Error in av-wrapper: ");
    78     AddFileLogRaw(Buffer);
    78     AddFileLogRaw(Buffer);
    79     AddFileLogRaw("\n");
    79     AddFileLogRaw("\n");
    80     exit(1);
    80     return(-1);
    81 }
    81 }
    82 
    82 
    83 // Function to be called from libav for logging.
    83 // Function to be called from libav for logging.
    84 // Note: libav can call LogCallback from different threads
    84 // Note: libav can call LogCallback from different threads
    85 // (there is mutex in AddFileLogRaw).
    85 // (there is mutex in AddFileLogRaw).
   164         Log("Could not allocate frame\n");
   164         Log("Could not allocate frame\n");
   165         return;
   165         return;
   166     }
   166     }
   167 }
   167 }
   168 
   168 
   169 // returns non-zero if there is more sound
   169 // returns non-zero if there is more sound, -1 in case of error
   170 static int WriteAudioFrame()
   170 static int WriteAudioFrame()
   171 {
   171 {
   172     if (!g_pAStream)
   172     if (!g_pAStream)
   173         return 0;
   173         return 0;
   174 
   174 
   187         pFrame = g_pAFrame;
   187         pFrame = g_pAFrame;
   188     }
   188     }
   189     // when NumSamples == 0 we still need to call encode_audio2 to flush
   189     // when NumSamples == 0 we still need to call encode_audio2 to flush
   190     int got_packet;
   190     int got_packet;
   191     if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
   191     if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
   192         FatalError("avcodec_encode_audio2 failed");
   192         return FatalError("avcodec_encode_audio2 failed");
   193     if (!got_packet)
   193     if (!got_packet)
   194         return 0;
   194         return 0;
   195 #else
   195 #else
   196     if (NumSamples == 0)
   196     if (NumSamples == 0)
   197         return 0;
   197         return 0;
   208 #endif
   208 #endif
   209 
   209 
   210     // Write the compressed frame to the media file.
   210     // Write the compressed frame to the media file.
   211     Packet.stream_index = g_pAStream->index;
   211     Packet.stream_index = g_pAStream->index;
   212     if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
   212     if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
   213         FatalError("Error while writing audio frame");
   213         return FatalError("Error while writing audio frame");
   214     return 1;
   214     return 1;
   215 }
   215 }
   216 
   216 
   217 // add a video output stream
   217 // add a video output stream
   218 static void AddVideoStream()
   218 static int AddVideoStream()
   219 {
   219 {
   220 #if LIBAVFORMAT_VERSION_MAJOR >= 53
   220 #if LIBAVFORMAT_VERSION_MAJOR >= 53
   221     g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
   221     g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
   222 #else
   222 #else
   223     g_pVStream = av_new_stream(g_pContainer, 0);
   223     g_pVStream = av_new_stream(g_pContainer, 0);
   224 #endif
   224 #endif
   225     if (!g_pVStream)
   225     if (!g_pVStream)
   226         FatalError("Could not allocate video stream");
   226         return FatalError("Could not allocate video stream");
   227 
   227 
   228     g_pVideo = g_pVStream->codec;
   228     g_pVideo = g_pVStream->codec;
   229 
   229 
   230     avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
   230     avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
   231     g_pVideo->codec_id = g_pVCodec->id;
   231     g_pVideo->codec_id = g_pVCodec->id;
   295 
   295 
   296     if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
   296     if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0)
   297 #else
   297 #else
   298     if (avcodec_open(g_pVideo, g_pVCodec) < 0)
   298     if (avcodec_open(g_pVideo, g_pVCodec) < 0)
   299 #endif
   299 #endif
   300         FatalError("Could not open video codec %s", g_pVCodec->long_name);
   300         return FatalError("Could not open video codec %s", g_pVCodec->long_name);
   301 
   301 
   302     g_pVFrame = avcodec_alloc_frame();
   302     g_pVFrame = avcodec_alloc_frame();
   303     if (!g_pVFrame)
   303     if (!g_pVFrame)
   304         FatalError("Could not allocate frame");
   304         return FatalError("Could not allocate frame");
   305 
   305 
   306     g_pVFrame->linesize[0] = g_Width;
   306     g_pVFrame->linesize[0] = g_Width;
   307     g_pVFrame->linesize[1] = g_Width/2;
   307     g_pVFrame->linesize[1] = g_Width/2;
   308     g_pVFrame->linesize[2] = g_Width/2;
   308     g_pVFrame->linesize[2] = g_Width/2;
   309     g_pVFrame->linesize[3] = 0;
   309     g_pVFrame->linesize[3] = 0;
       
   310     return 0;
   310 }
   311 }
   311 
   312 
   312 static int WriteFrame(AVFrame* pFrame)
   313 static int WriteFrame(AVFrame* pFrame)
   313 {
   314 {
   314     double AudioTime, VideoTime;
   315     double AudioTime, VideoTime;
   315 
   316     int ret;
   316     // write interleaved audio frame
   317     // write interleaved audio frame
   317     if (g_pAStream)
   318     if (g_pAStream)
   318     {
   319     {
   319         VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
   320         VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den;
   320         do
   321         do
       
   322         {
   321             AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
   323             AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den;
   322         while (AudioTime < VideoTime && WriteAudioFrame());
   324             ret = WriteAudioFrame();
       
   325         }
       
   326         while (AudioTime < VideoTime && ret);
       
   327         if (ret < 0)
       
   328             return ret;
   323     }
   329     }
   324 
   330 
   325     if (!g_pVStream)
   331     if (!g_pVStream)
   326         return 0;
   332         return 0;
   327 
   333 
   339         Packet.stream_index = g_pVStream->index;
   345         Packet.stream_index = g_pVStream->index;
   340         Packet.data = (uint8_t*)pFrame;
   346         Packet.data = (uint8_t*)pFrame;
   341         Packet.size = sizeof(AVPicture);
   347         Packet.size = sizeof(AVPicture);
   342 
   348 
   343         if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
   349         if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
   344             FatalError("Error while writing video frame");
   350             return FatalError("Error while writing video frame");
   345         return 0;
   351         return 0;
   346     }
   352     }
   347     else
   353     else
   348     {
   354     {
   349 #if LIBAVCODEC_VERSION_MAJOR >= 54
   355 #if LIBAVCODEC_VERSION_MAJOR >= 54
   350         int got_packet;
   356         int got_packet;
   351         if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0)
   357         if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0)
   352             FatalError("avcodec_encode_video2 failed");
   358             return FatalError("avcodec_encode_video2 failed");
   353         if (!got_packet)
   359         if (!got_packet)
   354             return 0;
   360             return 0;
   355 
   361 
   356         if (Packet.pts != AV_NOPTS_VALUE)
   362         if (Packet.pts != AV_NOPTS_VALUE)
   357             Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base);
   363             Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base);
   358         if (Packet.dts != AV_NOPTS_VALUE)
   364         if (Packet.dts != AV_NOPTS_VALUE)
   359             Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base);
   365             Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base);
   360 #else
   366 #else
   361         Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame);
   367         Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame);
   362         if (Packet.size < 0)
   368         if (Packet.size < 0)
   363             FatalError("avcodec_encode_video failed");
   369             return FatalError("avcodec_encode_video failed");
   364         if (Packet.size == 0)
   370         if (Packet.size == 0)
   365             return 0;
   371             return 0;
   366 
   372 
   367         if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE)
   373         if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE)
   368             Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base);
   374             Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base);
   371         Packet.data = g_OutBuffer;
   377         Packet.data = g_OutBuffer;
   372 #endif
   378 #endif
   373         // write the compressed frame in the media file
   379         // write the compressed frame in the media file
   374         Packet.stream_index = g_pVStream->index;
   380         Packet.stream_index = g_pVStream->index;
   375         if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
   381         if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
   376             FatalError("Error while writing video frame");
   382             return FatalError("Error while writing video frame");
   377 
   383 
   378         return 1;
   384         return 1;
   379     }
   385     }
   380 }
   386 }
   381 
   387 
   382 AVWRAP_DECL void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr)
   388 AVWRAP_DECL int AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr)
   383 {
   389 {
   384     g_pVFrame->data[0] = pY;
   390     g_pVFrame->data[0] = pY;
   385     g_pVFrame->data[1] = pCb;
   391     g_pVFrame->data[1] = pCb;
   386     g_pVFrame->data[2] = pCr;
   392     g_pVFrame->data[2] = pCr;
   387     WriteFrame(g_pVFrame);
   393     return WriteFrame(g_pVFrame);
   388 }
   394 }
   389 
   395 
   390 AVWRAP_DECL void AVWrapper_Init(
   396 AVWRAP_DECL int AVWrapper_Init(
   391          void (*pAddFileLogRaw)(const char*),
   397          void (*pAddFileLogRaw)(const char*),
   392          const char* pFilename,
   398          const char* pFilename,
   393          const char* pDesc,
   399          const char* pDesc,
   394          const char* pSoundFile,
   400          const char* pSoundFile,
   395          const char* pFormatName,
   401          const char* pFormatName,
   397          const char* pACodecName,
   403          const char* pACodecName,
   398          int Width, int Height,
   404          int Width, int Height,
   399          int FramerateNum, int FramerateDen,
   405          int FramerateNum, int FramerateDen,
   400          int VQuality)
   406          int VQuality)
   401 {
   407 {
       
   408     int ret;
   402     AddFileLogRaw = pAddFileLogRaw;
   409     AddFileLogRaw = pAddFileLogRaw;
   403     av_log_set_callback( &LogCallback );
   410     av_log_set_callback( &LogCallback );
   404 
   411 
   405     g_Width  = Width;
   412     g_Width  = Width;
   406     g_Height = Height;
   413     g_Height = Height;
   412     av_register_all();
   419     av_register_all();
   413 
   420 
   414     // find format
   421     // find format
   415     g_pFormat = av_guess_format(pFormatName, NULL, NULL);
   422     g_pFormat = av_guess_format(pFormatName, NULL, NULL);
   416     if (!g_pFormat)
   423     if (!g_pFormat)
   417         FatalError("Format \"%s\" was not found", pFormatName);
   424         return FatalError("Format \"%s\" was not found", pFormatName);
   418 
   425 
   419     // allocate the output media context
   426     // allocate the output media context
   420     g_pContainer = avformat_alloc_context();
   427     g_pContainer = avformat_alloc_context();
   421     if (!g_pContainer)
   428     if (!g_pContainer)
   422         FatalError("Could not allocate output context");
   429         return FatalError("Could not allocate output context");
   423 
   430 
   424     g_pContainer->oformat = g_pFormat;
   431     g_pContainer->oformat = g_pFormat;
   425 
   432 
   426     // store description of file
   433     // store description of file
   427     av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0);
   434     av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0);
   440     // add audio and video stream to container
   447     // add audio and video stream to container
   441     g_pVStream = NULL;
   448     g_pVStream = NULL;
   442     g_pAStream = NULL;
   449     g_pAStream = NULL;
   443 
   450 
   444     if (g_pVCodec)
   451     if (g_pVCodec)
   445         AddVideoStream();
   452     {
       
   453         ret = AddVideoStream();
       
   454         if (ret < 0)
       
   455             return ret;
       
   456     }
   446     else
   457     else
   447         Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
   458         Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName);
   448 
   459 
   449     if (g_pACodec)
   460     if (g_pACodec)
   450     {
   461     {
   460     }
   471     }
   461     else
   472     else
   462         Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
   473         Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName);
   463 
   474 
   464     if (!g_pAStream && !g_pVStream)
   475     if (!g_pAStream && !g_pVStream)
   465         FatalError("No video, no audio, aborting...");
   476         return FatalError("No video, no audio, aborting...");
   466 
   477 
   467     // write format info to log
   478     // write format info to log
   468     av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
   479     av_dump_format(g_pContainer, 0, g_pContainer->filename, 1);
   469 
   480 
   470     // open the output file, if needed
   481     // open the output file, if needed
   471     if (!(g_pFormat->flags & AVFMT_NOFILE))
   482     if (!(g_pFormat->flags & AVFMT_NOFILE))
   472     {
   483     {
   473         if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
   484         if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0)
   474             FatalError("Could not open output file (%s)", g_pContainer->filename);
   485             return FatalError("Could not open output file (%s)", g_pContainer->filename);
   475     }
   486     }
   476 
   487 
   477     // write the stream header, if any
   488     // write the stream header, if any
   478     avformat_write_header(g_pContainer, NULL);
   489     avformat_write_header(g_pContainer, NULL);
   479 
   490 
   480     g_pVFrame->pts = -1;
   491     g_pVFrame->pts = -1;
   481 }
   492     return 0;
   482 
   493 }
   483 AVWRAP_DECL void AVWrapper_Close()
   494 
   484 {
   495 AVWRAP_DECL int AVWrapper_Close()
       
   496 {
       
   497     int ret;
   485     // output buffered frames
   498     // output buffered frames
   486     if (g_pVCodec->capabilities & CODEC_CAP_DELAY)
   499     if (g_pVCodec->capabilities & CODEC_CAP_DELAY)
   487         while( WriteFrame(NULL) );
   500     {
       
   501         do
       
   502             ret = WriteFrame(NULL);
       
   503         while (ret);
       
   504         if (ret < 0)
       
   505             return ret;
       
   506     }
   488     // output any remaining audio
   507     // output any remaining audio
   489     while( WriteAudioFrame() );
   508     do
       
   509     {
       
   510         ret = WriteAudioFrame();
       
   511     }
       
   512     while(ret);
       
   513     if (ret < 0)
       
   514         return ret;
   490 
   515 
   491     // write the trailer, if any.
   516     // write the trailer, if any.
   492     av_write_trailer(g_pContainer);
   517     av_write_trailer(g_pContainer);
   493 
   518 
   494     // close the output file
   519     // close the output file
   512         av_free(g_pSamples);
   537         av_free(g_pSamples);
   513         fclose(g_pSoundFile);
   538         fclose(g_pSoundFile);
   514     }
   539     }
   515 
   540 
   516     av_free(g_pContainer);
   541     av_free(g_pContainer);
   517 }
   542     return 0;
       
   543 }