]>
Commit | Line | Data |
---|---|---|
64f23281 JR |
1 | From 8ccad6937177b1b92e40ab8f4447ea27bac009a7 Mon Sep 17 00:00:00 2001 |
2 | From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= <lalinsky@gmail.com> | |
3 | Date: Fri, 4 Nov 2022 21:47:38 +0100 | |
4 | Subject: [PATCH] Use FFmpeg 5.x (#120) | |
5 | ||
6 | * Use FFmpeg 5.1.2 for CI builds | |
7 | ||
8 | * Build on Ubuntu 20.04 | |
9 | ||
10 | * Upgrade code to FFmpeg 5.x APIs | |
11 | ||
12 | * Only set FFmpeg include dirs if building tools | |
13 | ||
14 | * No longer needed | |
15 | ||
16 | * Use ubuntu 20.04 | |
17 | --- | |
18 | .github/workflows/build.yml | 6 +- | |
19 | CMakeLists.txt | 16 -- | |
20 | package/build.sh | 4 +- | |
21 | src/audio/ffmpeg_audio_processor.h | 2 - | |
22 | src/audio/ffmpeg_audio_processor_avresample.h | 72 ------- | |
23 | src/audio/ffmpeg_audio_processor_swresample.h | 18 +- | |
24 | src/audio/ffmpeg_audio_reader.h | 197 +++++++++--------- | |
25 | tests/CMakeLists.txt | 6 + | |
26 | 8 files changed, 122 insertions(+), 199 deletions(-) | |
27 | delete mode 100644 src/audio/ffmpeg_audio_processor_avresample.h | |
28 | ||
29 | diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml | |
30 | index 92761d9..baf67b7 100644 | |
31 | --- a/.github/workflows/build.yml | |
32 | +++ b/.github/workflows/build.yml | |
33 | @@ -6,7 +6,7 @@ on: | |
34 | ||
35 | jobs: | |
36 | test-linux: | |
37 | - runs-on: ubuntu-18.04 | |
38 | + runs-on: ubuntu-20.04 | |
39 | strategy: | |
40 | matrix: | |
41 | fft: | |
42 | @@ -50,7 +50,7 @@ jobs: | |
43 | make check VERBOSE=1 | |
44 | ||
45 | package-linux: | |
46 | - runs-on: ubuntu-18.04 | |
47 | + runs-on: ubuntu-20.04 | |
48 | strategy: | |
49 | matrix: | |
50 | arch: | |
51 | @@ -71,7 +71,7 @@ jobs: | |
52 | path: artifacts/ | |
53 | ||
54 | package-windows: | |
55 | - runs-on: ubuntu-18.04 | |
56 | + runs-on: ubuntu-20.04 | |
57 | strategy: | |
58 | matrix: | |
59 | arch: | |
60 | diff --git a/CMakeLists.txt b/CMakeLists.txt | |
61 | index f8d6a32..4da2405 100644 | |
62 | --- a/CMakeLists.txt | |
63 | +++ b/CMakeLists.txt | |
64 | @@ -84,9 +84,6 @@ find_package(FFmpeg) | |
65 | if(FFMPEG_LIBRARIES) | |
66 | cmake_push_check_state(RESET) | |
67 | set(CMAKE_REQUIRED_LIBRARIES ${FFMPEG_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} -lm) | |
68 | - check_function_exists(av_packet_unref HAVE_AV_PACKET_UNREF) | |
69 | - check_function_exists(av_frame_alloc HAVE_AV_FRAME_ALLOC) | |
70 | - check_function_exists(av_frame_free HAVE_AV_FRAME_FREE) | |
71 | cmake_pop_check_state() | |
72 | endif() | |
73 | ||
74 | @@ -163,14 +160,11 @@ message(STATUS "Using ${FFT_LIB} for FFT calculations") | |
75 | if(NOT AUDIO_PROCESSOR_LIB) | |
76 | if(FFMPEG_LIBSWRESAMPLE_FOUND) | |
77 | set(AUDIO_PROCESSOR_LIB "swresample") | |
78 | - elseif(FFMPEG_LIBAVRESAMPLE_FOUND) | |
79 | - set(AUDIO_PROCESSOR_LIB "avresample") | |
80 | endif() | |
81 | endif() | |
82 | ||
83 | if(AUDIO_PROCESSOR_LIB STREQUAL "swresample") | |
84 | if(FFMPEG_LIBSWRESAMPLE_FOUND) | |
85 | - set(USE_AVRESAMPLE OFF) | |
86 | set(USE_SWRESAMPLE ON) | |
87 | set(AUDIO_PROCESSOR_LIBRARIES ${FFMPEG_LIBSWRESAMPLE_LIBRARIES}) | |
88 | set(AUDIO_PROCESSOR_INCLUDE_DIRS ${FFMPEG_LIBSWRESAMPLE_INCLUDE_DIRS}) | |
89 | @@ -178,16 +172,6 @@ if(AUDIO_PROCESSOR_LIB STREQUAL "swresample") | |
90 | message(FATAL_ERROR "Selected ${AUDIO_PROCESSOR_LIB} for audio processing, but the library is not found") | |
91 | endif() | |
92 | message(STATUS "Using ${AUDIO_PROCESSOR_LIB} for audio conversion") | |
93 | -elseif(AUDIO_PROCESSOR_LIB STREQUAL "avresample") | |
94 | - if(FFMPEG_LIBAVRESAMPLE_FOUND) | |
95 | - set(USE_AVRESAMPLE ON) | |
96 | - set(USE_SWRESAMPLE OFF) | |
97 | - set(AUDIO_PROCESSOR_LIBRARIES ${FFMPEG_LIBAVRESAMPLE_LIBRARIES}) | |
98 | - set(AUDIO_PROCESSOR_INCLUDE_DIRS ${FFMPEG_LIBAVRESAMPLE_INCLUDE_DIRS}) | |
99 | - else() | |
100 | - message(FATAL_ERROR "Selected ${AUDIO_PROCESSOR_LIB} for audio processing, but the library is not found") | |
101 | - endif() | |
102 | - message(STATUS "Using ${AUDIO_PROCESSOR_LIB} for audio conversion") | |
103 | else() | |
104 | message(STATUS "Building without audio conversion support, please install FFmpeg with libswresample") | |
105 | endif() | |
106 | diff --git a/package/build.sh b/package/build.sh | |
107 | index da631ae..b41d36e 100755 | |
108 | --- a/package/build.sh | |
109 | +++ b/package/build.sh | |
110 | @@ -7,8 +7,8 @@ set -eux | |
111 | ||
112 | BASE_DIR=$(cd $(dirname $0)/.. && pwd) | |
113 | ||
114 | -FFMPEG_VERSION=4.4.1 | |
115 | -FFMPEG_BUILD_TAG=v4.4.1-1 | |
116 | +FFMPEG_VERSION=5.1.2 | |
117 | +FFMPEG_BUILD_TAG=v${FFMPEG_VERSION}-1 | |
118 | ||
119 | TMP_BUILD_DIR=$BASE_DIR/$(mktemp -d build.XXXXXXXX) | |
120 | trap 'rm -rf $TMP_BUILD_DIR' EXIT | |
121 | diff --git a/src/audio/ffmpeg_audio_processor.h b/src/audio/ffmpeg_audio_processor.h | |
122 | index 7628fc7..39f4f6d 100644 | |
123 | --- a/src/audio/ffmpeg_audio_processor.h | |
124 | +++ b/src/audio/ffmpeg_audio_processor.h | |
125 | @@ -10,8 +10,6 @@ | |
126 | ||
127 | #if defined(USE_SWRESAMPLE) | |
128 | #include "audio/ffmpeg_audio_processor_swresample.h" | |
129 | -#elif defined(USE_AVRESAMPLE) | |
130 | -#include "audio/ffmpeg_audio_processor_avresample.h" | |
131 | #else | |
132 | #error "no audio processing library" | |
133 | #endif | |
134 | diff --git a/src/audio/ffmpeg_audio_processor_avresample.h b/src/audio/ffmpeg_audio_processor_avresample.h | |
135 | deleted file mode 100644 | |
136 | index bd85f92..0000000 | |
137 | --- a/src/audio/ffmpeg_audio_processor_avresample.h | |
138 | +++ /dev/null | |
139 | @@ -1,72 +0,0 @@ | |
140 | -// Copyright (C) 2016 Lukas Lalinsky | |
141 | -// Distributed under the MIT license, see the LICENSE file for details. | |
142 | - | |
143 | -#ifndef CHROMAPRINT_AUDIO_FFMPEG_AUDIO_PROCESSOR_AVRESAMPLE_H_ | |
144 | -#define CHROMAPRINT_AUDIO_FFMPEG_AUDIO_PROCESSOR_AVRESAMPLE_H_ | |
145 | - | |
146 | -extern "C" { | |
147 | -#include <libavresample/avresample.h> | |
148 | -} | |
149 | - | |
150 | -namespace chromaprint { | |
151 | - | |
152 | -class FFmpegAudioProcessor { | |
153 | -public: | |
154 | - FFmpegAudioProcessor() { | |
155 | - m_resample_ctx = avresample_alloc_context(); | |
156 | - } | |
157 | - | |
158 | - ~FFmpegAudioProcessor() { | |
159 | - avresample_free(&m_resample_ctx); | |
160 | - } | |
161 | - | |
162 | - void SetCompatibleMode() { | |
163 | - av_opt_set_int(m_resample_ctx, "filter_size", 16, 0); | |
164 | - av_opt_set_int(m_resample_ctx, "phase_shift", 8, 0); | |
165 | - av_opt_set_int(m_resample_ctx, "linear_interp", 1, 0); | |
166 | - av_opt_set_double(m_resample_ctx, "cutoff", 0.8, 0); | |
167 | - } | |
168 | - | |
169 | - void SetInputChannelLayout(int64_t channel_layout) { | |
170 | - av_opt_set_int(m_resample_ctx, "in_channel_layout", channel_layout, 0); | |
171 | - } | |
172 | - | |
173 | - void SetInputSampleFormat(AVSampleFormat sample_format) { | |
174 | - av_opt_set_int(m_resample_ctx, "in_sample_fmt", sample_format, 0); | |
175 | - } | |
176 | - | |
177 | - void SetInputSampleRate(int sample_rate) { | |
178 | - av_opt_set_int(m_resample_ctx, "in_sample_rate", sample_rate, 0); | |
179 | - } | |
180 | - | |
181 | - void SetOutputChannelLayout(int64_t channel_layout) { | |
182 | - av_opt_set_int(m_resample_ctx, "out_channel_layout", channel_layout, 0); | |
183 | - } | |
184 | - | |
185 | - void SetOutputSampleFormat(AVSampleFormat sample_format) { | |
186 | - av_opt_set_int(m_resample_ctx, "out_sample_fmt", sample_format, 0); | |
187 | - } | |
188 | - | |
189 | - void SetOutputSampleRate(int sample_rate) { | |
190 | - av_opt_set_int(m_resample_ctx, "out_sample_fmt", sample_rate, 0); | |
191 | - } | |
192 | - | |
193 | - int Init() { | |
194 | - return avresample_open(m_resample_ctx); | |
195 | - } | |
196 | - | |
197 | - int Convert(uint8_t **out, int out_count, const uint8_t **in, int in_count) { | |
198 | - return avresample_convert(m_resample_ctx, out, 0, out_count, (uint8_t **) in, 0, in_count); | |
199 | - } | |
200 | - | |
201 | - int Flush(uint8_t **out, int out_count) { | |
202 | - return avresample_read(m_resample_ctx, out, out_count); | |
203 | - } | |
204 | - | |
205 | -private: | |
206 | - AVAudioResampleContext *m_resample_ctx = nullptr; | |
207 | -}; | |
208 | - | |
209 | -}; // namespace chromaprint | |
210 | - | |
211 | -#endif | |
212 | diff --git a/src/audio/ffmpeg_audio_processor_swresample.h b/src/audio/ffmpeg_audio_processor_swresample.h | |
213 | index b86266b..b1d4bea 100644 | |
214 | --- a/src/audio/ffmpeg_audio_processor_swresample.h | |
215 | +++ b/src/audio/ffmpeg_audio_processor_swresample.h | |
216 | @@ -28,30 +28,28 @@ class FFmpegAudioProcessor { | |
217 | av_opt_set_double(m_swr_ctx, "cutoff", 0.8, 0); | |
218 | } | |
219 | ||
220 | - void SetInputChannelLayout(int64_t channel_layout) { | |
221 | - av_opt_set_int(m_swr_ctx, "icl", channel_layout, 0); | |
222 | - av_opt_set_int(m_swr_ctx, "ich", av_get_channel_layout_nb_channels(channel_layout), 0); | |
223 | + void SetInputChannelLayout(AVChannelLayout *channel_layout) { | |
224 | + av_opt_set_int(m_swr_ctx, "in_channel_layout", channel_layout->u.mask, 0); | |
225 | } | |
226 | ||
227 | void SetInputSampleFormat(AVSampleFormat sample_format) { | |
228 | - av_opt_set_int(m_swr_ctx, "isf", sample_format, 0); | |
229 | + av_opt_set_sample_fmt(m_swr_ctx, "in_sample_fmt", sample_format, 0); | |
230 | } | |
231 | ||
232 | void SetInputSampleRate(int sample_rate) { | |
233 | - av_opt_set_int(m_swr_ctx, "isr", sample_rate, 0); | |
234 | + av_opt_set_int(m_swr_ctx, "in_sample_rate", sample_rate, 0); | |
235 | } | |
236 | ||
237 | - void SetOutputChannelLayout(int64_t channel_layout) { | |
238 | - av_opt_set_int(m_swr_ctx, "ocl", channel_layout, 0); | |
239 | - av_opt_set_int(m_swr_ctx, "och", av_get_channel_layout_nb_channels(channel_layout), 0); | |
240 | + void SetOutputChannelLayout(AVChannelLayout *channel_layout) { | |
241 | + av_opt_set_int(m_swr_ctx, "out_channel_layout", channel_layout->u.mask, 0); | |
242 | } | |
243 | ||
244 | void SetOutputSampleFormat(AVSampleFormat sample_format) { | |
245 | - av_opt_set_int(m_swr_ctx, "osf", sample_format, 0); | |
246 | + av_opt_set_sample_fmt(m_swr_ctx, "out_sample_fmt", sample_format, 0); | |
247 | } | |
248 | ||
249 | void SetOutputSampleRate(int sample_rate) { | |
250 | - av_opt_set_int(m_swr_ctx, "osr", sample_rate, 0); | |
251 | + av_opt_set_int(m_swr_ctx, "out_sample_rate", sample_rate, 0); | |
252 | } | |
253 | ||
254 | int Init() { | |
255 | diff --git a/src/audio/ffmpeg_audio_reader.h b/src/audio/ffmpeg_audio_reader.h | |
256 | index 5550164..1c6b346 100644 | |
257 | --- a/src/audio/ffmpeg_audio_reader.h | |
258 | +++ b/src/audio/ffmpeg_audio_reader.h | |
259 | @@ -62,7 +62,7 @@ class FFmpegAudioReader { | |
260 | bool Read(const int16_t **data, size_t *size); | |
261 | ||
262 | bool IsOpen() const { return m_opened; } | |
263 | - bool IsFinished() const { return m_finished && !m_got_frame; } | |
264 | + bool IsFinished() const { return !m_has_more_packets && !m_has_more_frames; } | |
265 | ||
266 | std::string GetError() const { return m_error; } | |
267 | int GetErrorCode() const { return m_error_code; } | |
268 | @@ -74,20 +74,19 @@ class FFmpegAudioReader { | |
269 | uint8_t *m_convert_buffer[1] = { nullptr }; | |
270 | int m_convert_buffer_nb_samples = 0; | |
271 | ||
272 | - AVInputFormat *m_input_fmt = nullptr; | |
273 | + const AVInputFormat *m_input_fmt = nullptr; | |
274 | AVDictionary *m_input_opts = nullptr; | |
275 | ||
276 | AVFormatContext *m_format_ctx = nullptr; | |
277 | AVCodecContext *m_codec_ctx = nullptr; | |
278 | - AVFrame *m_frame = nullptr; | |
279 | int m_stream_index = -1; | |
280 | std::string m_error; | |
281 | int m_error_code = 0; | |
282 | - bool m_finished = false; | |
283 | bool m_opened = false; | |
284 | - int m_got_frame = 0; | |
285 | - AVPacket m_packet; | |
286 | - AVPacket m_packet0; | |
287 | + bool m_has_more_packets = true; | |
288 | + bool m_has_more_frames = true; | |
289 | + AVPacket *m_packet = nullptr; | |
290 | + AVFrame *m_frame = nullptr; | |
291 | ||
292 | int m_output_sample_rate = 0; | |
293 | int m_output_channels = 0; | |
294 | @@ -98,19 +97,12 @@ class FFmpegAudioReader { | |
295 | ||
296 | inline FFmpegAudioReader::FFmpegAudioReader() { | |
297 | av_log_set_level(AV_LOG_QUIET); | |
298 | - | |
299 | - av_init_packet(&m_packet); | |
300 | - m_packet.data = nullptr; | |
301 | - m_packet.size = 0; | |
302 | - | |
303 | - m_packet0 = m_packet; | |
304 | } | |
305 | ||
306 | inline FFmpegAudioReader::~FFmpegAudioReader() { | |
307 | Close(); | |
308 | av_dict_free(&m_input_opts); | |
309 | av_freep(&m_convert_buffer[0]); | |
310 | - av_packet_unref(&m_packet0); | |
311 | } | |
312 | ||
313 | inline bool FFmpegAudioReader::SetInputFormat(const char *name) { | |
314 | @@ -135,11 +127,10 @@ inline bool FFmpegAudioReader::Open(const std::string &file_name) { | |
315 | ||
316 | Close(); | |
317 | ||
318 | - av_init_packet(&m_packet); | |
319 | - m_packet.data = nullptr; | |
320 | - m_packet.size = 0; | |
321 | - | |
322 | - m_packet0 = m_packet; | |
323 | + m_packet = av_packet_alloc(); | |
324 | + if (!m_packet) { | |
325 | + return false; | |
326 | + } | |
327 | ||
328 | ret = avformat_open_input(&m_format_ctx, file_name.c_str(), m_input_fmt, &m_input_opts); | |
329 | if (ret < 0) { | |
330 | @@ -153,26 +144,31 @@ inline bool FFmpegAudioReader::Open(const std::string &file_name) { | |
331 | return false; | |
332 | } | |
333 | ||
334 | - AVCodec *codec; | |
335 | + const AVCodec *codec; | |
336 | ret = av_find_best_stream(m_format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0); | |
337 | if (ret < 0) { | |
338 | SetError("Could not find any audio stream in the file", ret); | |
339 | return false; | |
340 | } | |
341 | m_stream_index = ret; | |
342 | + auto stream = m_format_ctx->streams[m_stream_index]; | |
343 | ||
344 | - m_codec_ctx = m_format_ctx->streams[m_stream_index]->codec; | |
345 | + m_codec_ctx = avcodec_alloc_context3(codec); | |
346 | m_codec_ctx->request_sample_fmt = AV_SAMPLE_FMT_S16; | |
347 | ||
348 | + ret = avcodec_parameters_to_context(m_codec_ctx, stream->codecpar); | |
349 | + if (ret < 0) { | |
350 | + SetError("Could not copy the stream parameters", ret); | |
351 | + return false; | |
352 | + } | |
353 | + | |
354 | ret = avcodec_open2(m_codec_ctx, codec, nullptr); | |
355 | if (ret < 0) { | |
356 | SetError("Could not open the codec", ret); | |
357 | return false; | |
358 | } | |
359 | ||
360 | - if (!m_codec_ctx->channel_layout) { | |
361 | - m_codec_ctx->channel_layout = av_get_default_channel_layout(m_codec_ctx->channels); | |
362 | - } | |
363 | + av_dump_format(m_format_ctx, 0, "foo", 0); | |
364 | ||
365 | m_frame = av_frame_alloc(); | |
366 | if (!m_frame) { | |
367 | @@ -183,19 +179,23 @@ inline bool FFmpegAudioReader::Open(const std::string &file_name) { | |
368 | m_output_sample_rate = m_codec_ctx->sample_rate; | |
369 | } | |
370 | ||
371 | - if (!m_output_channels) { | |
372 | - m_output_channels = m_codec_ctx->channels; | |
373 | + AVChannelLayout output_channel_layout; | |
374 | + if (m_output_channels) { | |
375 | + av_channel_layout_default(&output_channel_layout, m_output_channels); | |
376 | + } else { | |
377 | + m_output_channels = m_codec_ctx->ch_layout.nb_channels; | |
378 | + av_channel_layout_default(&output_channel_layout, m_output_channels); | |
379 | } | |
380 | ||
381 | - if (m_codec_ctx->sample_fmt != AV_SAMPLE_FMT_S16 || m_codec_ctx->channels != m_output_channels || m_codec_ctx->sample_rate != m_output_sample_rate) { | |
382 | + if (m_codec_ctx->sample_fmt != AV_SAMPLE_FMT_S16 || m_codec_ctx->ch_layout.nb_channels != m_output_channels || m_codec_ctx->sample_rate != m_output_sample_rate) { | |
383 | m_converter.reset(new FFmpegAudioProcessor()); | |
384 | m_converter->SetCompatibleMode(); | |
385 | m_converter->SetInputSampleFormat(m_codec_ctx->sample_fmt); | |
386 | m_converter->SetInputSampleRate(m_codec_ctx->sample_rate); | |
387 | - m_converter->SetInputChannelLayout(m_codec_ctx->channel_layout); | |
388 | + m_converter->SetInputChannelLayout(&(m_codec_ctx->ch_layout)); | |
389 | m_converter->SetOutputSampleFormat(AV_SAMPLE_FMT_S16); | |
390 | m_converter->SetOutputSampleRate(m_output_sample_rate); | |
391 | - m_converter->SetOutputChannelLayout(av_get_default_channel_layout(m_output_channels)); | |
392 | + m_converter->SetOutputChannelLayout(&output_channel_layout); | |
393 | auto ret = m_converter->Init(); | |
394 | if (ret != 0) { | |
395 | SetError("Could not create an audio converter instance", ret); | |
396 | @@ -203,10 +203,11 @@ inline bool FFmpegAudioReader::Open(const std::string &file_name) { | |
397 | } | |
398 | } | |
399 | ||
400 | + av_channel_layout_uninit(&output_channel_layout); | |
401 | + | |
402 | m_opened = true; | |
403 | - m_finished = false; | |
404 | - m_got_frame = 0; | |
405 | - m_nb_packets = 0; | |
406 | + m_has_more_packets = true; | |
407 | + m_has_more_frames = true; | |
408 | m_decode_error = 0; | |
409 | ||
410 | return true; | |
411 | @@ -214,6 +215,7 @@ inline bool FFmpegAudioReader::Open(const std::string &file_name) { | |
412 | ||
413 | inline void FFmpegAudioReader::Close() { | |
414 | av_frame_free(&m_frame); | |
415 | + av_packet_free(&m_packet); | |
416 | ||
417 | m_stream_index = -1; | |
418 | ||
419 | @@ -252,91 +254,98 @@ inline bool FFmpegAudioReader::Read(const int16_t **data, size_t *size) { | |
420 | return false; | |
421 | } | |
422 | ||
423 | + *data = nullptr; | |
424 | + *size = 0; | |
425 | + | |
426 | int ret; | |
427 | + bool needs_packet = false; | |
428 | while (true) { | |
429 | - while (m_packet.size <= 0) { | |
430 | - av_packet_unref(&m_packet0); | |
431 | - av_init_packet(&m_packet); | |
432 | - m_packet.data = nullptr; | |
433 | - m_packet.size = 0; | |
434 | - ret = av_read_frame(m_format_ctx, &m_packet); | |
435 | + while (needs_packet && m_packet->size == 0) { | |
436 | + ret = av_read_frame(m_format_ctx, m_packet); | |
437 | if (ret < 0) { | |
438 | if (ret == AVERROR_EOF) { | |
439 | - m_finished = true; | |
440 | + needs_packet = false; | |
441 | + m_has_more_packets = false; | |
442 | break; | |
443 | - } else { | |
444 | + } | |
445 | + SetError("Error reading from the audio source", ret); | |
446 | + return false; | |
447 | + } | |
448 | + if (m_packet->stream_index == m_stream_index) { | |
449 | + needs_packet = false; | |
450 | + } else { | |
451 | + av_packet_unref(m_packet); | |
452 | + } | |
453 | + } | |
454 | + | |
455 | + if (m_packet->size != 0) { | |
456 | + ret = avcodec_send_packet(m_codec_ctx, m_packet); | |
457 | + if (ret < 0) { | |
458 | + if (ret != AVERROR(EAGAIN)) { | |
459 | SetError("Error reading from the audio source", ret); | |
460 | return false; | |
461 | } | |
462 | - } | |
463 | - m_packet0 = m_packet; | |
464 | - if (m_packet.stream_index != m_stream_index) { | |
465 | - m_packet.data = nullptr; | |
466 | - m_packet.size = 0; | |
467 | } else { | |
468 | - m_nb_packets++; | |
469 | + av_packet_unref(m_packet); | |
470 | } | |
471 | } | |
472 | ||
473 | - ret = avcodec_decode_audio4(m_codec_ctx, m_frame, &m_got_frame, &m_packet); | |
474 | + ret = avcodec_receive_frame(m_codec_ctx, m_frame); | |
475 | if (ret < 0) { | |
476 | - if (m_decode_error) { | |
477 | - SetError("Error decoding audio frame", m_decode_error); | |
478 | - return false; | |
479 | + if (ret == AVERROR_EOF) { | |
480 | + m_has_more_frames = false; | |
481 | + } else if (ret == AVERROR(EAGAIN)) { | |
482 | + if (m_has_more_packets) { | |
483 | + needs_packet = true; | |
484 | + continue; | |
485 | + } else { | |
486 | + m_has_more_frames = false; | |
487 | + } | |
488 | } | |
489 | - m_decode_error = ret; | |
490 | - m_packet.data = nullptr; | |
491 | - m_packet.size = 0; | |
492 | - continue; | |
493 | + SetError("Error decoding the audio source", ret); | |
494 | + return false; | |
495 | } | |
496 | ||
497 | - break; | |
498 | - } | |
499 | - | |
500 | - m_decode_error = 0; | |
501 | - | |
502 | - const int decoded = std::min(ret, m_packet.size); | |
503 | - m_packet.data += decoded; | |
504 | - m_packet.size -= decoded; | |
505 | - | |
506 | - if (m_got_frame) { | |
507 | - if (m_converter) { | |
508 | - if (m_frame->nb_samples > m_convert_buffer_nb_samples) { | |
509 | - int linsize; | |
510 | - av_freep(&m_convert_buffer[0]); | |
511 | - m_convert_buffer_nb_samples = std::max(1024 * 8, m_frame->nb_samples); | |
512 | - ret = av_samples_alloc(m_convert_buffer, &linsize, m_codec_ctx->channels, m_convert_buffer_nb_samples, AV_SAMPLE_FMT_S16, 1); | |
513 | - if (ret < 0) { | |
514 | - SetError("Couldn't allocate audio converter buffer", ret); | |
515 | + if (m_frame->nb_samples > 0) { | |
516 | + if (m_converter) { | |
517 | + if (m_frame->nb_samples > m_convert_buffer_nb_samples) { | |
518 | + int linsize; | |
519 | + av_freep(&m_convert_buffer[0]); | |
520 | + m_convert_buffer_nb_samples = std::max(1024 * 8, m_frame->nb_samples); | |
521 | + ret = av_samples_alloc(m_convert_buffer, &linsize, m_codec_ctx->ch_layout.nb_channels, m_convert_buffer_nb_samples, AV_SAMPLE_FMT_S16, 1); | |
522 | + if (ret < 0) { | |
523 | + SetError("Couldn't allocate audio converter buffer", ret); | |
524 | + return false; | |
525 | + } | |
526 | + } | |
527 | + auto nb_samples = m_converter->Convert(m_convert_buffer, m_convert_buffer_nb_samples, (const uint8_t **) m_frame->data, m_frame->nb_samples); | |
528 | + if (nb_samples < 0) { | |
529 | + SetError("Couldn't convert audio", ret); | |
530 | return false; | |
531 | } | |
532 | - } | |
533 | - auto nb_samples = m_converter->Convert(m_convert_buffer, m_convert_buffer_nb_samples, (const uint8_t **) m_frame->data, m_frame->nb_samples); | |
534 | - if (nb_samples < 0) { | |
535 | - SetError("Couldn't convert audio", ret); | |
536 | - return false; | |
537 | - } | |
538 | - *data = (const int16_t *) m_convert_buffer[0]; | |
539 | - *size = nb_samples; | |
540 | - } else { | |
541 | - *data = (const int16_t *) m_frame->data[0]; | |
542 | - *size = m_frame->nb_samples; | |
543 | - } | |
544 | - } else { | |
545 | - if (m_finished && m_converter) { | |
546 | - auto nb_samples = m_converter->Flush(m_convert_buffer, m_convert_buffer_nb_samples); | |
547 | - if (nb_samples < 0) { | |
548 | - SetError("Couldn't convert audio", ret); | |
549 | - return false; | |
550 | - } else if (nb_samples > 0) { | |
551 | - m_got_frame = 1; | |
552 | *data = (const int16_t *) m_convert_buffer[0]; | |
553 | *size = nb_samples; | |
554 | + } else { | |
555 | + *data = (const int16_t *) m_frame->data[0]; | |
556 | + *size = m_frame->nb_samples; | |
557 | + } | |
558 | + } else { | |
559 | + if (m_converter) { | |
560 | + if (IsFinished()) { | |
561 | + auto nb_samples = m_converter->Flush(m_convert_buffer, m_convert_buffer_nb_samples); | |
562 | + if (nb_samples < 0) { | |
563 | + SetError("Couldn't convert audio", ret); | |
564 | + return false; | |
565 | + } else if (nb_samples > 0) { | |
566 | + *data = (const int16_t *) m_convert_buffer[0]; | |
567 | + *size = nb_samples; | |
568 | + } | |
569 | + } | |
570 | } | |
571 | } | |
572 | - } | |
573 | ||
574 | - return true; | |
575 | + return true; | |
576 | + } | |
577 | } | |
578 | ||
579 | inline void FFmpegAudioReader::SetError(const char *message, int errnum) { | |
580 | diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt | |
581 | index a2b517b..123e643 100644 | |
582 | --- a/tests/CMakeLists.txt | |
583 | +++ b/tests/CMakeLists.txt | |
584 | @@ -38,6 +38,12 @@ set(SRCS | |
585 | ||
586 | if(BUILD_TOOLS) | |
587 | set(SRCS ${SRCS} ../src/audio/ffmpeg_audio_reader_test.cpp) | |
588 | + include_directories( | |
589 | + ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS} | |
590 | + ${FFMPEG_LIBAVCODEC_INCLUDE_DIRS} | |
591 | + ${FFMPEG_LIBAVUTIL_INCLUDE_DIRS} | |
592 | + ${AUDIO_PROCESSOR_INCLUDE_DIRS} | |
593 | + ) | |
594 | link_libraries(fpcalc_libs) | |
595 | endif() | |
596 |