diff --git a/.github/actions/prepare_macos_tooling/action.yml b/.github/actions/prepare_macos_tooling/action.yml index c57487979..a51f1791a 100644 --- a/.github/actions/prepare_macos_tooling/action.yml +++ b/.github/actions/prepare_macos_tooling/action.yml @@ -78,7 +78,7 @@ runs: # Install to separate staging paths for all architectures in # preparation for fusing universal libraries in a follow-up step. cd "$RUNNER_TEMP" - git clone --depth 1 --branch "n4.4.1" https://github.com/FFmpeg/FFmpeg + git clone --depth 1 --branch "n7.1" https://github.com/FFmpeg/FFmpeg cd FFmpeg # Common FFmpeg configure options diff --git a/src/libtrx/engine/audio_sample.c b/src/libtrx/engine/audio_sample.c index 0f5f75eb3..0d3a4afb8 100644 --- a/src/libtrx/engine/audio_sample.c +++ b/src/libtrx/engine/audio_sample.c @@ -171,12 +171,11 @@ static bool M_Convert(const int32_t sample_id) }; struct { - int32_t src_format; - int32_t src_channels; - int32_t src_sample_rate; - int32_t dst_format; - int32_t dst_channels; - int32_t dst_sample_rate; + struct { + int32_t format; + AVChannelLayout ch_layout; + int32_t sample_rate; + } src, dst; SwrContext *ctx; } swr = {}; @@ -279,17 +278,18 @@ static bool M_Convert(const int32_t sample_id) goto cleanup; } - if (!swr.ctx) { - swr.src_sample_rate = av.codec_ctx->sample_rate; - swr.src_channels = av.codec_ctx->channels; - swr.src_format = av.codec_ctx->sample_fmt; - swr.dst_sample_rate = AUDIO_WORKING_RATE; - swr.dst_channels = 1; - swr.dst_format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT); - swr.ctx = swr_alloc_set_opts( - swr.ctx, swr.dst_channels, swr.dst_format, swr.dst_sample_rate, - swr.src_channels, swr.src_format, swr.src_sample_rate, 0, 0); - if (!swr.ctx) { + if (swr.ctx == nullptr) { + swr.src.sample_rate = av.codec_ctx->sample_rate; + swr.src.ch_layout = av.codec_ctx->ch_layout; + swr.src.format = av.codec_ctx->sample_fmt; + swr.dst.sample_rate = AUDIO_WORKING_RATE; + av_channel_layout_default(&swr.dst.ch_layout, 1); + swr.dst.format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT); + swr_alloc_set_opts2( + &swr.ctx, &swr.dst.ch_layout, swr.dst.format, + swr.dst.sample_rate, &swr.src.ch_layout, swr.src.format, + swr.src.sample_rate, 0, 0); + if (swr.ctx == nullptr) { av_packet_unref(av.packet); error_code = AVERROR(ENOMEM); goto cleanup; @@ -319,15 +319,15 @@ static bool M_Convert(const int32_t sample_id) const int32_t out_samples = swr_get_out_samples(swr.ctx, av.frame->nb_samples); av_samples_alloc( - &out_buffer, nullptr, swr.dst_channels, out_samples, - swr.dst_format, 1); + &out_buffer, nullptr, swr.dst.ch_layout.nb_channels, + out_samples, swr.dst.format, 1); int32_t resampled_size = swr_convert( swr.ctx, &out_buffer, out_samples, (const uint8_t **)av.frame->data, av.frame->nb_samples); while (resampled_size > 0) { int32_t out_buffer_size = av_samples_get_buffer_size( - nullptr, swr.dst_channels, resampled_size, swr.dst_format, - 1); + nullptr, swr.dst.ch_layout.nb_channels, resampled_size, + swr.dst.format, 1); if (out_buffer_size > 0) { working_buffer = Memory_Realloc( @@ -351,10 +351,10 @@ static bool M_Convert(const int32_t sample_id) av_packet_unref(av.packet); } - int32_t sample_format_bytes = av_get_bytes_per_sample(swr.dst_format); - sample->num_samples = - working_buffer_size / sample_format_bytes / swr.dst_channels; - sample->channels = swr.src_channels; + int32_t sample_format_bytes = av_get_bytes_per_sample(swr.dst.format); + sample->num_samples = working_buffer_size / sample_format_bytes + / swr.dst.ch_layout.nb_channels; + sample->channels = swr.src.ch_layout.nb_channels; sample->sample_data = working_buffer; result = true; @@ -396,8 +396,7 @@ cleanup: } if (av.codec_ctx) { - avcodec_close(av.codec_ctx); - av_freep(&av.codec_ctx); + avcodec_free_context(&av.codec_ctx); } if (av.format_ctx) { diff --git a/src/libtrx/engine/audio_stream.c b/src/libtrx/engine/audio_stream.c index 7cfc5412b..bca11ca75 100644 --- a/src/libtrx/engine/audio_stream.c +++ b/src/libtrx/engine/audio_stream.c @@ -52,12 +52,11 @@ typedef struct { } av; struct { - int32_t src_format; - int32_t src_channels; - int32_t src_sample_rate; - int32_t dst_format; - int32_t dst_channels; - int32_t dst_sample_rate; + struct { + int32_t format; + AVChannelLayout ch_layout; + int32_t sample_rate; + } src, dst; SwrContext *ctx; } swr; @@ -147,17 +146,18 @@ static bool M_EnqueueFrame(AUDIO_STREAM_SOUND *stream) int32_t error_code; if (!stream->swr.ctx) { - stream->swr.src_sample_rate = stream->av.codec_ctx->sample_rate; - stream->swr.src_channels = stream->av.codec_ctx->channels; - stream->swr.src_format = stream->av.codec_ctx->sample_fmt; - stream->swr.dst_sample_rate = AUDIO_WORKING_RATE; - stream->swr.dst_channels = AUDIO_WORKING_CHANNELS; - stream->swr.dst_format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT); - stream->swr.ctx = swr_alloc_set_opts( - stream->swr.ctx, Audio_GetAVChannelLayout(stream->swr.dst_channels), - stream->swr.dst_format, stream->swr.dst_sample_rate, - Audio_GetAVChannelLayout(stream->swr.src_channels), - stream->swr.src_format, stream->swr.src_sample_rate, 0, 0); + stream->swr.src.sample_rate = stream->av.codec_ctx->sample_rate; + stream->swr.src.ch_layout = stream->av.codec_ctx->ch_layout; + stream->swr.src.format = stream->av.codec_ctx->sample_fmt; + stream->swr.dst.sample_rate = AUDIO_WORKING_RATE; + av_channel_layout_default( + &stream->swr.dst.ch_layout, AUDIO_WORKING_CHANNELS); + stream->swr.dst.format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT); + swr_alloc_set_opts2( + &stream->swr.ctx, &stream->swr.dst.ch_layout, + stream->swr.dst.format, stream->swr.dst.sample_rate, + &stream->swr.src.ch_layout, stream->swr.src.format, + stream->swr.src.sample_rate, 0, 0); if (!stream->swr.ctx) { av_packet_unref(stream->av.packet); error_code = AVERROR(ENOMEM); @@ -189,8 +189,8 @@ static bool M_EnqueueFrame(AUDIO_STREAM_SOUND *stream) const int32_t out_samples = swr_get_out_samples(stream->swr.ctx, stream->av.frame->nb_samples); av_samples_alloc( - &out_buffer, nullptr, stream->swr.dst_channels, out_samples, - stream->swr.dst_format, 1); + &out_buffer, nullptr, stream->swr.dst.ch_layout.nb_channels, + out_samples, stream->swr.dst.format, 1); int32_t resampled_size = swr_convert( stream->swr.ctx, &out_buffer, out_samples, (const uint8_t **)stream->av.frame->data, @@ -199,8 +199,8 @@ static bool M_EnqueueFrame(AUDIO_STREAM_SOUND *stream) size_t out_pos = 0; while (resampled_size > 0) { const size_t out_buffer_size = av_samples_get_buffer_size( - nullptr, stream->swr.dst_channels, resampled_size, - stream->swr.dst_format, 1); + nullptr, stream->swr.dst.ch_layout.nb_channels, resampled_size, + stream->swr.dst.format, 1); if (out_pos + out_buffer_size > m_DecodeBufferCapacity) { m_DecodeBufferCapacity = out_pos + out_buffer_size; @@ -322,8 +322,8 @@ static bool M_InitialiseFromPath(int32_t sound_id, const char *file_path) M_DecodeFrame(stream); - int32_t sdl_sample_rate = stream->av.codec_ctx->sample_rate; - int32_t sdl_channels = stream->av.codec_ctx->channels; + const int32_t sdl_sample_rate = stream->av.codec_ctx->sample_rate; + const int32_t sdl_channels = stream->av.codec_ctx->ch_layout.nb_channels; stream->is_read_done = false; stream->is_used = true; @@ -474,14 +474,12 @@ bool Audio_Stream_Close(int32_t sound_id) AUDIO_STREAM_SOUND *stream = &m_Streams[sound_id]; if (stream->av.codec_ctx) { - avcodec_close(stream->av.codec_ctx); - // XXX: potential libav bug - avcodec_close should free this info if (stream->av.codec_ctx->extradata != nullptr) { av_freep(&stream->av.codec_ctx->extradata); } - av_free(stream->av.codec_ctx); + avcodec_free_context(&stream->av.codec_ctx); stream->av.codec_ctx = nullptr; } @@ -613,13 +611,15 @@ void Audio_Stream_Mix(float *dst_buffer, size_t len) const float *src_ptr = &m_MixBuffer[0]; float *dst_ptr = dst_buffer; - if (stream->av.codec_ctx->channels == AUDIO_WORKING_CHANNELS) { + const int32_t channels = + stream->av.codec_ctx->ch_layout.nb_channels; + if (channels == AUDIO_WORKING_CHANNELS) { for (int32_t s = 0; s < samples_gotten; s++) { for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) { *dst_ptr++ += *src_ptr++ * stream->volume; } } - } else if (stream->av.codec_ctx->channels == 1) { + } else if (channels == 1) { for (int32_t s = 0; s < samples_gotten; s++) { for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) { *dst_ptr++ += *src_ptr * stream->volume; @@ -630,11 +630,10 @@ void Audio_Stream_Mix(float *dst_buffer, size_t len) for (int32_t s = 0; s < samples_gotten; s++) { // downmix to mono float src_sample = 0.0f; - for (int32_t i = 0; i < stream->av.codec_ctx->channels; - i++) { + for (int32_t i = 0; i < channels; i++) { src_sample += *src_ptr++; } - src_sample /= (float)stream->av.codec_ctx->channels; + src_sample /= (float)channels; for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) { *dst_ptr++ += src_sample * stream->volume; } diff --git a/src/libtrx/engine/image.c b/src/libtrx/engine/image.c index 1d5ccc54c..9449a1a8c 100644 --- a/src/libtrx/engine/image.c +++ b/src/libtrx/engine/image.c @@ -77,6 +77,9 @@ static bool M_Init(const char *const path, IMAGE_READER_CONTEXT *const ctx) AVStream *video_stream = nullptr; for (unsigned int i = 0; i < ctx->format_ctx->nb_streams; i++) { AVStream *current_stream = ctx->format_ctx->streams[i]; + if (current_stream->codecpar == nullptr) { + continue; + } if (current_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream = current_stream; break; @@ -165,9 +168,7 @@ static void M_Free(IMAGE_READER_CONTEXT *const ctx) } if (ctx->codec_ctx != nullptr) { - avcodec_close(ctx->codec_ctx); - av_free(ctx->codec_ctx); - ctx->codec_ctx = nullptr; + avcodec_free_context(&ctx->codec_ctx); } if (ctx->format_ctx != nullptr) { @@ -490,9 +491,7 @@ cleanup: } if (codec) { - avcodec_close(codec_ctx); - av_free(codec_ctx); - codec_ctx = nullptr; + avcodec_free_context(&codec_ctx); } if (frame) { diff --git a/src/libtrx/engine/video.c b/src/libtrx/engine/video.c index adc93fe61..b4d2fb535 100644 --- a/src/libtrx/engine/video.c +++ b/src/libtrx/engine/video.c @@ -90,7 +90,7 @@ typedef struct { } M_PACKET_LIST; typedef struct { - AVFifoBuffer *pkt_list; + AVFifo *pkt_list; int nb_packets; int size; int64_t duration; @@ -103,7 +103,7 @@ typedef struct { typedef struct { int freq; int channels; - int64_t channel_layout; + AVChannelLayout ch_layout; enum AVSampleFormat fmt; int frame_size; int bytes_per_sec; @@ -131,6 +131,10 @@ typedef struct { AVRational sar; } M_FRAME; +typedef struct { + int64_t pkt_pos; +} M_FRAME_DATA; + typedef struct { M_FRAME queue[FRAME_QUEUE_SIZE]; int rindex; @@ -223,6 +227,7 @@ typedef struct { int target_surface_height; double frame_timer; + double frame_last_returned_time; int video_stream; AVStream *video_st; M_PACKET_QUEUE videoq; @@ -277,16 +282,13 @@ static int M_PacketQueuePutPrivate(M_PACKET_QUEUE *q, AVPacket *pkt) return -1; } - if (av_fifo_space(q->pkt_list) < (signed)sizeof(pkt1)) { - if (av_fifo_grow(q->pkt_list, sizeof(pkt1)) < 0) { - return -1; - } - } - pkt1.pkt = pkt; pkt1.serial = q->serial; - av_fifo_generic_write(q->pkt_list, &pkt1, sizeof(pkt1), nullptr); + int32_t ret = av_fifo_write(q->pkt_list, &pkt1, 1); + if (ret < 0) { + return ret; + } q->nb_packets++; q->size += pkt1.pkt->size + sizeof(pkt1); q->duration += pkt1.pkt->duration; @@ -327,8 +329,9 @@ static int M_PacketQueuePutNullPacket( static int M_PacketQueueInit(M_PACKET_QUEUE *q) { memset(q, 0, sizeof(M_PACKET_QUEUE)); - q->pkt_list = av_fifo_alloc(sizeof(M_PACKET_LIST)); - if (!q->pkt_list) { + q->pkt_list = + av_fifo_alloc2(1, sizeof(M_PACKET_LIST), AV_FIFO_FLAG_AUTO_GROW); + if (q->pkt_list == nullptr) { return AVERROR(ENOMEM); } @@ -353,8 +356,7 @@ static void M_PacketQueueFlush(M_PACKET_QUEUE *q) M_PACKET_LIST pkt1; SDL_LockMutex(q->mutex); - while (av_fifo_size(q->pkt_list) >= (signed)sizeof(pkt1)) { - av_fifo_generic_read(q->pkt_list, &pkt1, sizeof(pkt1), nullptr); + while (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) { av_packet_free(&pkt1.pkt); } q->nb_packets = 0; @@ -367,7 +369,7 @@ static void M_PacketQueueFlush(M_PACKET_QUEUE *q) static void M_PacketQueueDestroy(M_PACKET_QUEUE *q) { M_PacketQueueFlush(q); - av_fifo_freep(&q->pkt_list); + av_fifo_freep2(&q->pkt_list); SDL_DestroyMutex(q->mutex); SDL_DestroyCond(q->cond); } @@ -402,8 +404,7 @@ static int M_PacketQueueGet( break; } - if (av_fifo_size(q->pkt_list) >= (signed)sizeof(pkt1)) { - av_fifo_generic_read(q->pkt_list, &pkt1, sizeof(pkt1), nullptr); + if (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) { q->nb_packets--; q->size -= pkt1.pkt->size + sizeof(pkt1); q->duration -= pkt1.pkt->duration; @@ -518,6 +519,15 @@ static int M_DecoderDecodeFrame(M_DECODER *d, AVFrame *frame) av_packet_unref(d->pkt); } + if (d->pkt->buf && !d->pkt->opaque_ref) { + d->pkt->opaque_ref = av_buffer_allocz(sizeof(M_FRAME_DATA)); + if (!d->pkt->opaque_ref) { + return AVERROR(ENOMEM); + } + M_FRAME_DATA *fd = (M_FRAME_DATA *)d->pkt->opaque_ref->data; + fd->pkt_pos = d->pkt->pos; + } + if (avcodec_send_packet(d->avctx, d->pkt) == AVERROR(EAGAIN)) { LOG_ERROR( "Receive_frame and send_packet both returned EAGAIN, " @@ -1109,37 +1119,52 @@ static int M_AudioThread(void *arg) M_STATE *is = arg; AVFrame *frame = av_frame_alloc(); M_FRAME *af; + int last_serial = -1; int got_frame = 0; AVRational tb; int ret = 0; - if (!frame) { + if (frame == nullptr) { return AVERROR(ENOMEM); } do { - if ((got_frame = M_DecoderDecodeFrame(&is->auddec, frame)) < 0) { + got_frame = M_DecoderDecodeFrame(&is->auddec, frame); + if (got_frame < 0) { goto the_end; } if (got_frame) { tb = (AVRational) { 1, frame->sample_rate }; - if (!(af = M_FrameQueuePeekWritable(&is->sampq))) { + M_FRAME_DATA *fd = frame->opaque_ref + ? (M_FRAME_DATA *)frame->opaque_ref->data + : nullptr; + af = M_FrameQueuePeekWritable(&is->sampq); + if (af == nullptr) { goto the_end; } af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); - af->pos = frame->pkt_pos; + af->pos = fd ? fd->pkt_pos : -1; af->serial = is->auddec.pkt_serial; af->duration = av_q2d((AVRational) { frame->nb_samples, frame->sample_rate }); av_frame_move_ref(af->frame, frame); M_FrameQueuePush(&is->sampq); + + if (is->audioq.serial != is->auddec.pkt_serial) { + break; + } + + if (ret == AVERROR_EOF) { + is->auddec.finished = is->auddec.pkt_serial; + } } } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF); + the_end: av_frame_free(&frame); return ret; @@ -1180,17 +1205,23 @@ static int M_VideoThread(void *arg) continue; } + is->frame_last_returned_time = av_gettime_relative() / 1000000.0; + + M_FRAME_DATA *fd = frame->opaque_ref + ? (M_FRAME_DATA *)frame->opaque_ref->data + : nullptr; + duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational) { frame_rate.den, frame_rate.num }) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); ret = M_QueuePicture( - is, frame, pts, duration, frame->pkt_pos, is->viddec.pkt_serial); + is, frame, pts, duration, fd ? fd->pkt_pos : -1, + is->viddec.pkt_serial); av_frame_unref(frame); - - if (ret < 0) { - goto the_end; + if (is->videoq.serial != is->viddec.pkt_serial) { + break; } } the_end: @@ -1240,6 +1271,7 @@ static int M_SynchronizeAudio(M_STATE *is, int nb_samples) static int M_AudioDecodeFrame(M_STATE *is) { + int data_size, resampled_data_size; av_unused double audio_clock0; int wanted_nb_samples; @@ -1250,6 +1282,15 @@ static int M_AudioDecodeFrame(M_STATE *is) } do { +#if defined(_WIN32) + while (M_FrameQueueNBRemaining(&is->sampq) == 0) { + if ((av_gettime_relative() - m_AudioCallbackTime) > 1000000LL + * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2) { + return -1; + } + av_usleep(1000); + } +#endif if (!(af = M_FrameQueuePeekReadable(&is->sampq))) { return -1; } @@ -1257,39 +1298,39 @@ static int M_AudioDecodeFrame(M_STATE *is) } while (af->serial != is->audioq.serial); data_size = av_samples_get_buffer_size( - nullptr, af->frame->channels, af->frame->nb_samples, af->frame->format, - 1); + nullptr, af->frame->ch_layout.nb_channels, af->frame->nb_samples, + af->frame->format, 1); - int64_t dec_channel_layout = - (af->frame->channel_layout - && af->frame->channels - == av_get_channel_layout_nb_channels(af->frame->channel_layout)) - ? (signed)af->frame->channel_layout - : av_get_default_channel_layout(af->frame->channels); wanted_nb_samples = M_SynchronizeAudio(is, af->frame->nb_samples); if (af->frame->format != is->audio_src.fmt - || dec_channel_layout != is->audio_src.channel_layout + || av_channel_layout_compare( + &af->frame->ch_layout, &is->audio_src.ch_layout) || af->frame->sample_rate != is->audio_src.freq || (wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) { + int ret; swr_free(&is->swr_ctx); - is->swr_ctx = swr_alloc_set_opts( - nullptr, is->audio_tgt.channel_layout, is->audio_tgt.fmt, - is->audio_tgt.freq, dec_channel_layout, af->frame->format, + ret = swr_alloc_set_opts2( + &is->swr_ctx, &is->audio_tgt.ch_layout, is->audio_tgt.fmt, + is->audio_tgt.freq, &af->frame->ch_layout, af->frame->format, af->frame->sample_rate, 0, nullptr); - if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) { + if (ret < 0 || swr_init(is->swr_ctx) < 0) { LOG_ERROR( "Cannot create sample rate converter for conversion of %d Hz " "%s %d channels to %d Hz %s %d channels!", af->frame->sample_rate, - av_get_sample_fmt_name(af->frame->format), af->frame->channels, - is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), - is->audio_tgt.channels); + av_get_sample_fmt_name(af->frame->format), + af->frame->ch_layout.nb_channels, is->audio_tgt.freq, + av_get_sample_fmt_name(is->audio_tgt.fmt), + is->audio_tgt.ch_layout.nb_channels); swr_free(&is->swr_ctx); return -1; } - is->audio_src.channel_layout = dec_channel_layout; - is->audio_src.channels = af->frame->channels; + if (av_channel_layout_copy( + &is->audio_src.ch_layout, &af->frame->ch_layout) + < 0) { + return -1; + } is->audio_src.freq = af->frame->sample_rate; is->audio_src.fmt = af->frame->format; } @@ -1301,7 +1342,8 @@ static int M_AudioDecodeFrame(M_STATE *is) / af->frame->sample_rate + 256; int out_size = av_samples_get_buffer_size( - nullptr, is->audio_tgt.channels, out_count, is->audio_tgt.fmt, 0); + nullptr, is->audio_tgt.ch_layout.nb_channels, out_count, + is->audio_tgt.fmt, 0); int len2; if (out_size < 0) { LOG_ERROR("av_samples_get_buffer_size() failed"); @@ -1330,12 +1372,13 @@ static int M_AudioDecodeFrame(M_STATE *is) return -1; } if (len2 == out_count) { + LOG_ERROR("audio buffer is probably too small"); if (swr_init(is->swr_ctx) < 0) { swr_free(&is->swr_ctx); } } is->audio_buf = is->audio_buf1; - resampled_data_size = len2 * is->audio_tgt.channels + resampled_data_size = len2 * is->audio_tgt.ch_layout.nb_channels * av_get_bytes_per_sample(is->audio_tgt.fmt); } else { is->audio_buf = af->frame->data[0]; @@ -1404,29 +1447,27 @@ static void M_SDLAudioCallback(void *opaque, Uint8 *stream, int len) } static int M_AudioOpen( - M_STATE *is, int64_t wanted_channel_layout, int wanted_nb_channels, - int wanted_sample_rate, M_AUDIO_PARAMS *audio_hw_params) + M_STATE *is, AVChannelLayout *wanted_channel_layout, int wanted_sample_rate, + M_AUDIO_PARAMS *audio_hw_params) { SDL_AudioSpec wanted_spec, spec; + const char *env; static const int next_nb_channels[] = { 0, 0, 1, 6, 2, 6, 4, 6 }; static const int next_sample_rates[] = { 0, 44100, 48000, 96000, 192000 }; int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1; + int wanted_nb_channels = wanted_channel_layout->nb_channels; - const char *const env = SDL_getenv("SDL_AUDIO_CHANNELS"); + env = SDL_getenv("SDL_AUDIO_CHANNELS"); if (env) { wanted_nb_channels = atoi(env); - wanted_channel_layout = - av_get_default_channel_layout(wanted_nb_channels); + av_channel_layout_uninit(wanted_channel_layout); + av_channel_layout_default(wanted_channel_layout, wanted_nb_channels); } - if (!wanted_channel_layout - || wanted_nb_channels - != av_get_channel_layout_nb_channels(wanted_channel_layout)) { - wanted_channel_layout = - av_get_default_channel_layout(wanted_nb_channels); - wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX; + if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) { + av_channel_layout_uninit(wanted_channel_layout); + av_channel_layout_default(wanted_channel_layout, wanted_nb_channels); } - wanted_nb_channels = - av_get_channel_layout_nb_channels(wanted_channel_layout); + wanted_nb_channels = wanted_channel_layout->nb_channels; wanted_spec.channels = wanted_nb_channels; wanted_spec.freq = wanted_sample_rate; if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) { @@ -1448,6 +1489,9 @@ static int M_AudioOpen( nullptr, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) { + LOG_WARNING( + "SDL_OpenAudio (%d channels, %d Hz): %s", wanted_spec.channels, + wanted_spec.freq, SDL_GetError()); wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)]; if (!wanted_spec.channels) { wanted_spec.freq = next_sample_rates[next_sample_rate_idx--]; @@ -1457,16 +1501,16 @@ static int M_AudioOpen( return -1; } } - wanted_channel_layout = - av_get_default_channel_layout(wanted_spec.channels); + av_channel_layout_default(wanted_channel_layout, wanted_spec.channels); } if (spec.format != AUDIO_S16SYS) { LOG_ERROR("SDL advised audio format %d is not supported!", spec.format); return -1; } if (spec.channels != wanted_spec.channels) { - wanted_channel_layout = av_get_default_channel_layout(spec.channels); - if (!wanted_channel_layout) { + av_channel_layout_uninit(wanted_channel_layout); + av_channel_layout_default(wanted_channel_layout, spec.channels); + if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) { LOG_ERROR( "SDL advised channel count %d is not supported!", spec.channels); @@ -1476,12 +1520,15 @@ static int M_AudioOpen( audio_hw_params->fmt = AV_SAMPLE_FMT_S16; audio_hw_params->freq = spec.freq; - audio_hw_params->channel_layout = wanted_channel_layout; - audio_hw_params->channels = spec.channels; + if (av_channel_layout_copy( + &audio_hw_params->ch_layout, wanted_channel_layout) + < 0) + return -1; audio_hw_params->frame_size = av_samples_get_buffer_size( - nullptr, audio_hw_params->channels, 1, audio_hw_params->fmt, 1); + nullptr, audio_hw_params->ch_layout.nb_channels, 1, + audio_hw_params->fmt, 1); audio_hw_params->bytes_per_sec = av_samples_get_buffer_size( - nullptr, audio_hw_params->channels, audio_hw_params->freq, + nullptr, audio_hw_params->ch_layout.nb_channels, audio_hw_params->freq, audio_hw_params->fmt, 1); if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) { @@ -1501,7 +1548,7 @@ static int M_StreamComponentOpen(M_STATE *is, int stream_index) const AVDictionaryEntry *t = nullptr; int sample_rate; int nb_channels; - int64_t channel_layout; + AVChannelLayout ch_layout; int ret = 0; if (stream_index < 0 || stream_index >= (signed)ic->nb_streams) { @@ -1542,11 +1589,9 @@ static int M_StreamComponentOpen(M_STATE *is, int stream_index) switch (avctx->codec_type) { case AVMEDIA_TYPE_AUDIO: sample_rate = avctx->sample_rate; - nb_channels = avctx->channels; - channel_layout = avctx->channel_layout; + ch_layout = avctx->ch_layout; - if ((ret = M_AudioOpen( - is, channel_layout, nb_channels, sample_rate, &is->audio_tgt)) + if ((ret = M_AudioOpen(is, &ch_layout, sample_rate, &is->audio_tgt)) < 0) { goto fail; } @@ -1568,9 +1613,7 @@ static int M_StreamComponentOpen(M_STATE *is, int stream_index) < 0) { goto fail; } - if ((is->ic->iformat->flags - & (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK)) - && !is->ic->iformat->read_seek) { + if (is->ic->iformat->flags & AVFMT_NOTIMESTAMPS) { is->auddec.start_pts = is->audio_st->start_time; is->auddec.start_pts_tb = is->audio_st->time_base; } @@ -1606,8 +1649,9 @@ static int M_StreamComponentOpen(M_STATE *is, int stream_index) fail: avcodec_free_context(&avctx); - out: + av_channel_layout_uninit(&ch_layout); + return ret; } diff --git a/tools/tr1/docker/game-linux/Dockerfile b/tools/tr1/docker/game-linux/Dockerfile index 0a709aab0..b41f7a83c 100644 --- a/tools/tr1/docker/game-linux/Dockerfile +++ b/tools/tr1/docker/game-linux/Dockerfile @@ -53,7 +53,7 @@ RUN apt-get install -y \ zlib1g-dev RUN git clone \ --depth 1 \ - --branch "n4.4.1" \ + --branch "n7.1" \ https://github.com/FFmpeg/FFmpeg COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt RUN cd FFmpeg \ diff --git a/tools/tr1/docker/game-win/Dockerfile b/tools/tr1/docker/game-win/Dockerfile index 7497ea439..8174e701d 100644 --- a/tools/tr1/docker/game-win/Dockerfile +++ b/tools/tr1/docker/game-win/Dockerfile @@ -54,7 +54,7 @@ RUN apt-get install -y \ nasm RUN git clone \ --depth 1 \ - --branch "n4.4.1" \ + --branch "n7.1" \ https://github.com/FFmpeg/FFmpeg COPY --from=zlib /ext/ /usr/i686-w64-mingw32/ COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt @@ -65,6 +65,8 @@ RUN cd FFmpeg \ --cross-prefix=i686-w64-mingw32- \ --prefix=/ext/ \ --cc=i686-w64-mingw32-gcc \ + --cxx=i686-w64-mingw32-g++ \ + --host-cc=i686-w64-mingw32-gcc \ --strip=i686-w64-mingw32-strip \ --pkg-config=i686-w64-mingw32-pkg-config \ --enable-static \ diff --git a/tools/tr2/docker/game-linux/Dockerfile b/tools/tr2/docker/game-linux/Dockerfile index 61b58faaf..b7e30464f 100644 --- a/tools/tr2/docker/game-linux/Dockerfile +++ b/tools/tr2/docker/game-linux/Dockerfile @@ -53,7 +53,7 @@ RUN apt-get install -y \ zlib1g-dev RUN git clone \ --depth 1 \ - --branch "n4.4.1" \ + --branch "n7.1" \ https://github.com/FFmpeg/FFmpeg COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt RUN cd FFmpeg \ diff --git a/tools/tr2/docker/game-win/Dockerfile b/tools/tr2/docker/game-win/Dockerfile index 60cf3e391..be01f1309 100644 --- a/tools/tr2/docker/game-win/Dockerfile +++ b/tools/tr2/docker/game-win/Dockerfile @@ -56,7 +56,7 @@ RUN apt-get install -y \ nasm RUN git clone \ --depth 1 \ - --branch "n4.4.1" \ + --branch "n7.1" \ https://github.com/FFmpeg/FFmpeg COPY --from=zlib /ext/ /usr/i686-w64-mingw32/ COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt @@ -67,6 +67,8 @@ RUN cd FFmpeg \ --cross-prefix=i686-w64-mingw32- \ --prefix=/ext/ \ --cc=i686-w64-mingw32-gcc \ + --cxx=i686-w64-mingw32-g++ \ + --host-cc=i686-w64-mingw32-gcc \ --strip=i686-w64-mingw32-strip \ --pkg-config=i686-w64-mingw32-pkg-config \ --enable-static \