diff -r 4fba5519c37f -r 5debd5fe526e hedgewars/avwrapper.c --- a/hedgewars/avwrapper.c Fri Jun 08 02:41:14 2012 +0400 +++ b/hedgewars/avwrapper.c Fri Jun 08 02:52:35 2012 +0400 @@ -16,8 +16,11 @@ static AVCodecContext* g_pAudio; static AVCodecContext* g_pVideo; -static int g_Width, g_Height, g_Framerate; +static int g_Width, g_Height; static int g_Frequency, g_Channels; +static int g_VQuality, g_AQuality; +static AVRational g_Framerate; +static const char* g_pPreset; static FILE* g_pSoundFile; static int16_t* g_pSamples; @@ -77,7 +80,7 @@ AddFileLogRaw(Buffer); } -static void AddAudioStream(enum CodecID codec_id) +static void AddAudioStream() { #if LIBAVCODEC_VERSION_MAJOR >= 54 g_pAStream = avformat_new_stream(g_pContainer, g_pACodec); @@ -89,15 +92,24 @@ g_pAStream->id = 1; g_pAudio = g_pAStream->codec; + avcodec_get_context_defaults3(g_pAudio, g_pACodec); - g_pAudio->codec_id = codec_id; + g_pAudio->codec_id = g_pACodec->id; // put parameters g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16; - // pContext->bit_rate = 128000; g_pAudio->sample_rate = g_Frequency; g_pAudio->channels = g_Channels; + // set quality + if (g_AQuality > 100) + g_pAudio->bit_rate = g_AQuality; + else + { + g_pAudio->flags |= CODEC_FLAG_QSCALE; + g_pAudio->global_quality = g_AQuality*FF_QP2LAMBDA; + } + // some formats want stream headers to be separate if (g_pFormat->flags & AVFMT_GLOBALHEADER) g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER; @@ -123,6 +135,9 @@ // returns non-zero if there is more sound static int WriteAudioFrame() { + if (!g_pAStream) + return 0; + AVPacket Packet = { 0 }; av_init_packet(&Packet); @@ -166,7 +181,7 @@ } // add a video output stream -static void AddVideoStream(enum CodecID codec_id) +static void AddVideoStream() { #if LIBAVCODEC_VERSION_MAJOR >= 54 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); @@ -177,8 +192,9 @@ FatalError("Could not allocate video stream"); g_pVideo = g_pVStream->codec; - avcodec_get_context_defaults3( g_pVideo, g_pVCodec ); - g_pVideo->codec_id = codec_id; + + avcodec_get_context_defaults3(g_pVideo, g_pVCodec); + g_pVideo->codec_id = g_pVCodec->id; // put parameters // resolution must be a multiple of two @@ -188,29 +204,28 @@ 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; - g_pVideo->time_base.num = 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; + } + + AVDictionary* pDict = NULL; + if (strcmp(g_pVCodec->name, "libx264") == 0) + av_dict_set(&pDict, "preset", g_pPreset, 0); + // some formats want stream headers to be separate if (g_pFormat->flags & AVFMT_GLOBALHEADER) g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER; - AVDictionary* pDict = NULL; - if (codec_id == CODEC_ID_H264) - { - // av_dict_set(&pDict, "tune", "animation", 0); - // av_dict_set(&pDict, "preset", "veryslow", 0); - av_dict_set(&pDict, "crf", "20", 0); - } - else - { - g_pVideo->flags |= CODEC_FLAG_QSCALE; - // g_pVideo->bit_rate = g_Width*g_Height*g_Framerate/4; - g_pVideo->global_quality = 15*FF_QP2LAMBDA; - } - // open the codec if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) FatalError("Could not open video codec %s", g_pVCodec->long_name); @@ -237,6 +252,9 @@ 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); @@ -300,111 +318,73 @@ WriteFrame(g_pVFrame); } -void AVWrapper_GetList() -{ - // initialize libav and register all codecs and formats - av_register_all(); - -#if 0 - AVOutputFormat* pFormat = NULL; - while (pFormat = av_oformat_next(pFormat)) - { - Log("%s; %s; %s;\n", pFormat->name, pFormat->long_name, pFormat->mime_type); - - AVCodec* pCodec = NULL; - while (pCodec = av_codec_next(pCodec)) - { - if (!av_codec_is_encoder(pCodec)) - continue; - if (avformat_query_codec(pFormat, pCodec->id, FF_COMPLIANCE_NORMAL) != 1) - continue; - if (pCodec->type = AVMEDIA_TYPE_VIDEO) - { - if (pCodec->supported_framerate != NULL) - continue; - Log(" Video: %s; %s;\n", pCodec->name, pCodec->long_name); - } - if (pCodec->type = AVMEDIA_TYPE_AUDIO) - { - /* if (pCodec->supported_samplerates == NULL) - continue; - int i; - for(i = 0; i <) - supported_samplerates*/ - Log(" Audio: %s; %s;\n", pCodec->name, pCodec->long_name); - } - } - /* struct AVCodecTag** pTags = pCur->codec_tag; - int i; - for (i = 0; ; i++) - { - enum CodecID id = av_codec_get_id(pTags, i); - if (id == CODEC_ID_NONE) - break; - AVCodec* pCodec = avcodec_find_encoder(id); - Log(" %i: %s; %s;\n", id, pCodec->name, pCodec->long_name); - }*/ - } -#endif -} - -void AVWrapper_Init(void (*pAddFileLogRaw)(const char*), const char* pFilename, const char* pSoundFile, int Width, int Height, int Framerate, int Frequency, int Channels) +void AVWrapper_Init( + void (*pAddFileLogRaw)(const char*), + const char* pFilename, + const char* pSoundFile, + const char* pFormatName, + const char* pVCodecName, + const char* pACodecName, + const char* pVPreset, + int Width, int Height, + int FramerateNum, int FramerateDen, + int Frequency, int Channels, + int VQuality, int AQuality) { AddFileLogRaw = pAddFileLogRaw; av_log_set_callback( &LogCallback ); g_Width = Width; g_Height = Height; - g_Framerate = Framerate; + g_Framerate.num = FramerateNum; + g_Framerate.den = FramerateDen; g_Frequency = Frequency; g_Channels = Channels; + g_VQuality = VQuality; + g_AQuality = AQuality; + g_pPreset = pVPreset; // initialize libav and register all codecs and formats av_register_all(); - - AVWrapper_GetList(); - // allocate the output media context -#if LIBAVCODEC_VERSION_MAJOR >= 54 - avformat_alloc_output_context2(&g_pContainer, NULL, "mp4", pFilename); -#else - g_pFormat = av_guess_format(NULL, pFilename, NULL); + // find format + g_pFormat = av_guess_format(pFormatName, NULL, NULL); if (!g_pFormat) - FatalError("guess_format"); + FatalError("Format \"%s\" was not found", pFormatName); // allocate the output media context g_pContainer = avformat_alloc_context(); - if (g_pContainer) - { - g_pContainer->oformat = g_pFormat; - snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s", pFilename); - } -#endif if (!g_pContainer) FatalError("Could not allocate output context"); - g_pFormat = g_pContainer->oformat; + g_pContainer->oformat = g_pFormat; - enum CodecID VideoCodecID = g_pFormat->video_codec;//CODEC_ID_H264; - enum CodecID AudioCodecID = g_pFormat->audio_codec; + // append extesnion to filename + snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), + "%s.%*s", + pFilename, + strcspn(g_pFormat->extensions, ","), g_pFormat->extensions); + // 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 (VideoCodecID != CODEC_ID_NONE) - { - g_pVCodec = avcodec_find_encoder(VideoCodecID); - if (!g_pVCodec) - FatalError("Video codec not found"); - AddVideoStream(VideoCodecID); - } + + if (g_pVCodec) + AddVideoStream(); + else + Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName); - if (AudioCodecID != CODEC_ID_NONE) - { - g_pACodec = avcodec_find_encoder(AudioCodecID); - if (!g_pACodec) - FatalError("Audio codec not found"); - AddAudioStream(AudioCodecID); - } + if (g_pACodec) + AddAudioStream(); + 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..."); if (g_pAStream) { @@ -414,17 +394,18 @@ } // write format info to log - av_dump_format(g_pContainer, 0, pFilename, 1); + 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, pFilename, AVIO_FLAG_WRITE) < 0) + if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0) FatalError("Could not open output file (%s)", pFilename); } // write the stream header, if any avformat_write_header(g_pContainer, NULL); + g_pVFrame->pts = -1; } @@ -439,32 +420,27 @@ // write the trailer, if any. av_write_trailer(g_pContainer); - // close each codec - if( g_pVStream ) + // close the output file + if (!(g_pFormat->flags & AVFMT_NOFILE)) + avio_close(g_pContainer->pb); + + // free everything + if (g_pVStream) { - avcodec_close(g_pVStream->codec); + avcodec_close(g_pVideo); + av_free(g_pVideo); + av_free(g_pVStream); av_free(g_pVFrame); } - if( g_pAStream ) + if (g_pAStream) { - avcodec_close(g_pAStream->codec); + avcodec_close(g_pAudio); + av_free(g_pAudio); + av_free(g_pAStream); av_free(g_pAFrame); av_free(g_pSamples); fclose(g_pSoundFile); } - // free the streams - int i; - for (i = 0; i < g_pContainer->nb_streams; i++) - { - av_freep(&g_pContainer->streams[i]->codec); - av_freep(&g_pContainer->streams[i]); - } - - // close the output file - if (!(g_pFormat->flags & AVFMT_NOFILE)) - avio_close(g_pContainer->pb); - - // free the stream av_free(g_pContainer); }