1 From 71691fad8654031328f4af077fc32aaf29cdb7d0 Mon Sep 17 00:00:00 2001
2 From: Pekka Ristola <pekkarr@protonmail.com>
3 Date: Tue, 9 May 2023 20:11:47 +0300
4 Subject: [PATCH] Add support for ffmpeg 6.0
6 - Use the new send_frame/receive_packet API for encoding
7 - Use the new channel layout API for audio
9 - Copy codec parameters to the stream parameters
10 - Set correct pts for audio frames
11 - Read audio samples from file directly to the refcounted AVFrame buffer instead of the `g_pSamples` buffer
12 - Use global AVPackets allocated with `av_packet_alloc`
13 - Stop trying to write more audio frames when `WriteAudioFrame` fails with a negative error code
14 - Fix segfault with `g_pContainer->url`. The field has to be allocated with `av_malloc` before writing to it. It's set to `NULL` by default.
15 - Properly free allocations with `avcodec_free_context` and `avformat_free_context`
17 hedgewars/avwrapper/avwrapper.c | 234 +++++++++++++++++++++++++++-----
18 1 file changed, 203 insertions(+), 31 deletions(-)
20 diff --git a/hedgewars/avwrapper/avwrapper.c b/hedgewars/avwrapper/avwrapper.c
21 index 6c0fe739b4..3daeb07b75 100644
22 --- a/hedgewars/avwrapper/avwrapper.c
23 +++ b/hedgewars/avwrapper/avwrapper.c
25 #define UNUSED(x) (void)(x)
27 static AVFormatContext* g_pContainer;
28 -static AVOutputFormat* g_pFormat;
29 +static const AVOutputFormat* g_pFormat;
30 static AVStream* g_pAStream;
31 static AVStream* g_pVStream;
32 static AVFrame* g_pAFrame;
33 static AVFrame* g_pVFrame;
34 -static AVCodec* g_pACodec;
35 -static AVCodec* g_pVCodec;
36 +static const AVCodec* g_pACodec;
37 +static const AVCodec* g_pVCodec;
38 static AVCodecContext* g_pAudio;
39 static AVCodecContext* g_pVideo;
40 +#if LIBAVCODEC_VERSION_MAJOR >= 58
41 +static AVPacket* g_pAPacket;
42 +static AVPacket* g_pVPacket;
45 static int g_Width, g_Height;
46 static uint32_t g_Frequency, g_Channels;
47 @@ -58,8 +62,13 @@ static int g_VQuality;
48 static AVRational g_Framerate;
50 static FILE* g_pSoundFile;
51 +#if LIBAVUTIL_VERSION_MAJOR < 53
52 static int16_t* g_pSamples;
54 static int g_NumSamples;
55 +#if LIBAVCODEC_VERSION_MAJOR >= 53
56 +static int64_t g_NextAudioPts;
60 // compatibility section
61 @@ -93,6 +102,8 @@ static void rescale_ts(AVPacket *pkt, AVRational ctb, AVRational stb)
62 if (pkt->duration > 0)
63 pkt->duration = av_rescale_q(pkt->duration, ctb, stb);
66 +#define avcodec_free_context(ctx) do { avcodec_close(*ctx); av_freep(ctx); } while (0)
69 #ifndef AV_CODEC_CAP_DELAY
70 @@ -165,8 +176,42 @@ static void Log(const char* pFmt, ...)
71 AddFileLogRaw(Buffer);
74 +#if LIBAVCODEC_VERSION_MAJOR >= 58
75 +static int EncodeAndWriteFrame(
76 + const AVStream* pStream,
77 + AVCodecContext* pCodecContext,
78 + const AVFrame* pFrame,
83 + ret = avcodec_send_frame(pCodecContext, pFrame);
85 + return FatalError("avcodec_send_frame failed: %d", ret);
88 + ret = avcodec_receive_packet(pCodecContext, pPacket);
89 + if (ret == AVERROR(EAGAIN))
91 + else if (ret == AVERROR_EOF)
94 + return FatalError("avcodec_receive_packet failed: %d", ret);
96 + av_packet_rescale_ts(pPacket, pCodecContext->time_base, pStream->time_base);
98 + // Write the compressed frame to the media file.
99 + pPacket->stream_index = pStream->index;
100 + ret = av_interleaved_write_frame(g_pContainer, pPacket);
102 + return FatalError("Error while writing frame: %d", ret);
107 static void AddAudioStream()
110 g_pAStream = avformat_new_stream(g_pContainer, g_pACodec);
113 @@ -176,20 +221,44 @@ static void AddAudioStream()
116 #if LIBAVCODEC_VERSION_MAJOR >= 59
117 - const AVCodec *audio_st_codec = avcodec_find_decoder(g_pAStream->codecpar->codec_id);
118 - g_pAudio = avcodec_alloc_context3(audio_st_codec);
119 - avcodec_parameters_to_context(g_pAudio, g_pAStream->codecpar);
120 + g_pAudio = avcodec_alloc_context3(g_pACodec);
122 g_pAudio = g_pAStream->codec;
125 avcodec_get_context_defaults3(g_pAudio, g_pACodec);
126 g_pAudio->codec_id = g_pACodec->id;
130 g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16;
131 g_pAudio->sample_rate = g_Frequency;
132 +#if LIBAVCODEC_VERSION_MAJOR >= 60
133 + const AVChannelLayout* pChLayout = g_pACodec->ch_layouts;
136 + for (; pChLayout->nb_channels; pChLayout++)
138 + if (pChLayout->nb_channels == g_Channels)
140 + ret = av_channel_layout_copy(&g_pAudio->ch_layout, pChLayout);
143 + Log("Channel layout copy failed: %d\n", ret);
150 + if (!g_pAudio->ch_layout.nb_channels)
152 + // no suitable layout found
153 + g_pAudio->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
154 + g_pAudio->ch_layout.nb_channels = g_Channels;
157 g_pAudio->channels = g_Channels;
160 // set time base as invers of sample rate
161 g_pAudio->time_base.den = g_pAStream->time_base.den = g_Frequency;
162 @@ -213,6 +282,15 @@ static void AddAudioStream()
166 +#if LIBAVCODEC_VERSION_MAJOR >= 58
167 + ret = avcodec_parameters_from_context(g_pAStream->codecpar, g_pAudio);
170 + Log("Could not copy parameters from codec context: %d\n", ret);
175 #if LIBAVCODEC_VERSION_MAJOR >= 54
176 if (g_pACodec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
178 @@ -221,13 +299,46 @@ static void AddAudioStream()
181 g_NumSamples = g_pAudio->frame_size;
182 - g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t));
183 g_pAFrame = av_frame_alloc();
186 Log("Could not allocate frame\n");
189 +#if LIBAVUTIL_VERSION_MAJOR >= 53
190 +#if LIBAVCODEC_VERSION_MAJOR >= 60
191 + ret = av_channel_layout_copy(&g_pAFrame->ch_layout, &g_pAudio->ch_layout);
194 + Log("Channel layout copy for frame failed: %d\n", ret);
198 + g_pAFrame->channels = g_pAudio->channels;
200 + g_pAFrame->format = g_pAudio->sample_fmt;
201 + g_pAFrame->sample_rate = g_pAudio->sample_rate;
202 + g_pAFrame->nb_samples = g_NumSamples;
203 + ret = av_frame_get_buffer(g_pAFrame, 1);
206 + Log("Failed to allocate frame buffer: %d\n", ret);
210 + g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t));
212 +#if LIBAVCODEC_VERSION_MAJOR >= 58
213 + g_pAPacket = av_packet_alloc();
216 + Log("Could not allocate audio packet\n");
220 +#if LIBAVCODEC_VERSION_MAJOR >= 53
221 + g_NextAudioPts = 0;
225 // returns non-zero if there is more sound, -1 in case of error
226 @@ -236,22 +347,46 @@ static int WriteAudioFrame()
231 - av_init_packet(&Packet);
232 - Packet.data = NULL;
236 +#if LIBAVUTIL_VERSION_MAJOR >= 53
237 + ret = av_frame_make_writable(g_pAFrame);
239 + return FatalError("Could not make audio frame writable: %d", ret);
240 + pData = (int16_t*) g_pAFrame->data[0];
242 + pData = g_pSamples;
245 - int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile);
246 + int NumSamples = fread(pData, 2*g_Channels, g_NumSamples, g_pSoundFile);
248 #if LIBAVCODEC_VERSION_MAJOR >= 53
249 AVFrame* pFrame = NULL;
252 g_pAFrame->nb_samples = NumSamples;
253 + g_pAFrame->pts = g_NextAudioPts;
254 + g_NextAudioPts += NumSamples;
255 +#if LIBAVUTIL_VERSION_MAJOR < 53
256 avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16,
257 - (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1);
258 + (uint8_t*)pData, NumSamples*2*g_Channels, 1);
264 +#if LIBAVCODEC_VERSION_MAJOR >= 58
265 + ret = EncodeAndWriteFrame(g_pAStream, g_pAudio, pFrame, g_pAPacket);
267 + return FatalError("Audio frame processing failed");
271 + av_init_packet(&Packet);
272 + Packet.data = NULL;
275 +#if LIBAVCODEC_VERSION_MAJOR >= 53
276 // when NumSamples == 0 we still need to call encode_audio2 to flush
278 if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0)
279 @@ -266,7 +401,7 @@ static int WriteAudioFrame()
280 int BufferSize = OUTBUFFER_SIZE;
281 if (g_pAudio->frame_size == 0)
282 BufferSize = NumSamples*g_Channels*2;
283 - Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples);
284 + Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, pData);
285 if (Packet.size == 0)
287 if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE)
288 @@ -280,25 +415,25 @@ static int WriteAudioFrame()
289 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0)
290 return FatalError("Error while writing audio frame");
295 // add a video output stream
296 static int AddVideoStream()
299 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec);
301 return FatalError("Could not allocate video stream");
303 #if LIBAVCODEC_VERSION_MAJOR >= 59
304 - const AVCodec *video_st_codec = avcodec_find_decoder(g_pVStream->codecpar->codec_id);
305 - g_pVideo = avcodec_alloc_context3(video_st_codec);
306 - avcodec_parameters_to_context(g_pVideo, g_pVStream->codecpar);
307 + g_pVideo = avcodec_alloc_context3(g_pVCodec);
309 g_pVideo = g_pVStream->codec;
312 avcodec_get_context_defaults3(g_pVideo, g_pVCodec);
313 g_pVideo->codec_id = g_pVCodec->id;
317 // resolution must be a multiple of two
318 @@ -361,6 +496,12 @@ static int AddVideoStream()
319 if (avcodec_open2(g_pVideo, g_pVCodec, NULL) < 0)
320 return FatalError("Could not open video codec %s", g_pVCodec->long_name);
322 +#if LIBAVCODEC_VERSION_MAJOR >= 58
323 + ret = avcodec_parameters_from_context(g_pVStream->codecpar, g_pVideo);
325 + return FatalError("Could not copy parameters from codec context: %d", ret);
328 g_pVFrame = av_frame_alloc();
330 return FatalError("Could not allocate frame");
331 @@ -370,6 +511,12 @@ static int AddVideoStream()
332 g_pVFrame->height = g_Height;
333 g_pVFrame->format = AV_PIX_FMT_YUV420P;
335 +#if LIBAVCODEC_VERSION_MAJOR >= 58
336 + g_pVPacket = av_packet_alloc();
338 + return FatalError("Could not allocate packet");
341 return avcodec_default_get_buffer2(g_pVideo, g_pVFrame, 0);
344 @@ -380,6 +527,10 @@ static int WriteFrame(AVFrame* pFrame)
345 // write interleaved audio frame
348 +#if LIBAVCODEC_VERSION_MAJOR >= 58
350 + return FatalError("Error while writing video frame: g_pAPacket does not exist");
352 VideoTime = (double)g_pVFrame->pts * g_pVStream->time_base.num/g_pVStream->time_base.den;
355 @@ -388,7 +539,7 @@ static int WriteFrame(AVFrame* pFrame)
356 AudioTime = (double)g_pAFrame->pts * g_pAStream->time_base.num/g_pAStream->time_base.den;
357 ret = WriteAudioFrame();
359 - while (AudioTime < VideoTime && ret);
360 + while (AudioTime < VideoTime && ret > 0);
364 @@ -396,13 +547,18 @@ static int WriteFrame(AVFrame* pFrame)
369 +#if LIBAVCODEC_VERSION_MAJOR >= 58
370 + ret = EncodeAndWriteFrame(g_pVStream, g_pVideo, pFrame, g_pVPacket);
372 + return FatalError("Video frame processing failed");
376 av_init_packet(&Packet);
381 -#if LIBAVCODEC_VERSION_MAJOR < 58
382 if (g_pFormat->flags & AVFMT_RAWPICTURE)
384 /* raw video case. The API will change slightly in the near
385 @@ -417,7 +573,6 @@ static int WriteFrame(AVFrame* pFrame)
391 #if LIBAVCODEC_VERSION_MAJOR >= 54
393 @@ -447,6 +602,7 @@ static int WriteFrame(AVFrame* pFrame)
400 AVWRAP_DECL int AVWrapper_WriteFrame(uint8_t *buf)
401 @@ -539,9 +695,13 @@ AVWRAP_DECL int AVWrapper_Init(
403 strncpy(ext, g_pFormat->extensions, 16);
405 - ext[strcspn(ext,",")] = 0;
406 + size_t extLen = strcspn(ext, ",");
408 #if LIBAVCODEC_VERSION_MAJOR >= 59
409 - snprintf(g_pContainer->url, sizeof(g_pContainer->url), "%s.%s", pFilename, ext);
410 + // pFilename + dot + ext + null byte
411 + size_t urlLen = strlen(pFilename) + 1 + extLen + 1;
412 + g_pContainer->url = av_malloc(urlLen);
413 + snprintf(g_pContainer->url, urlLen, "%s.%s", pFilename, ext);
415 snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext);
417 @@ -636,21 +796,33 @@ AVWRAP_DECL int AVWrapper_Close()
421 - avcodec_close(g_pVideo);
423 - av_free(g_pVStream);
424 + avcodec_free_context(&g_pVideo);
425 av_frame_free(&g_pVFrame);
426 +#if LIBAVCODEC_VERSION_MAJOR >= 58
427 + av_packet_free(&g_pVPacket);
432 - avcodec_close(g_pAudio);
434 - av_free(g_pAStream);
435 + avcodec_free_context(&g_pAudio);
436 av_frame_free(&g_pAFrame);
437 +#if LIBAVCODEC_VERSION_MAJOR >= 58
438 + av_packet_free(&g_pAPacket);
440 +#if LIBAVUTIL_VERSION_MAJOR < 53
443 fclose(g_pSoundFile);
446 +#if LIBAVCODEC_VERSION_MAJOR >= 59
447 + avformat_free_context(g_pContainer);
450 + av_free(g_pVStream);
452 + av_free(g_pAStream);
453 av_free(g_pContainer);