--- 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);
}