build: upgrade ffmpeg to 7.1

This commit is contained in:
Marcin Kurczewski 2025-02-10 23:18:50 +01:00
parent 301fe93315
commit 63ce670d22
9 changed files with 188 additions and 143 deletions

View file

@ -78,7 +78,7 @@ runs:
# Install to separate staging paths for all architectures in # Install to separate staging paths for all architectures in
# preparation for fusing universal libraries in a follow-up step. # preparation for fusing universal libraries in a follow-up step.
cd "$RUNNER_TEMP" 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 cd FFmpeg
# Common FFmpeg configure options # Common FFmpeg configure options

View file

@ -171,12 +171,11 @@ static bool M_Convert(const int32_t sample_id)
}; };
struct { struct {
int32_t src_format; struct {
int32_t src_channels; int32_t format;
int32_t src_sample_rate; AVChannelLayout ch_layout;
int32_t dst_format; int32_t sample_rate;
int32_t dst_channels; } src, dst;
int32_t dst_sample_rate;
SwrContext *ctx; SwrContext *ctx;
} swr = {}; } swr = {};
@ -279,17 +278,18 @@ static bool M_Convert(const int32_t sample_id)
goto cleanup; goto cleanup;
} }
if (!swr.ctx) { if (swr.ctx == nullptr) {
swr.src_sample_rate = av.codec_ctx->sample_rate; swr.src.sample_rate = av.codec_ctx->sample_rate;
swr.src_channels = av.codec_ctx->channels; swr.src.ch_layout = av.codec_ctx->ch_layout;
swr.src_format = av.codec_ctx->sample_fmt; swr.src.format = av.codec_ctx->sample_fmt;
swr.dst_sample_rate = AUDIO_WORKING_RATE; swr.dst.sample_rate = AUDIO_WORKING_RATE;
swr.dst_channels = 1; av_channel_layout_default(&swr.dst.ch_layout, 1);
swr.dst_format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT); swr.dst.format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT);
swr.ctx = swr_alloc_set_opts( swr_alloc_set_opts2(
swr.ctx, swr.dst_channels, swr.dst_format, swr.dst_sample_rate, &swr.ctx, &swr.dst.ch_layout, swr.dst.format,
swr.src_channels, swr.src_format, swr.src_sample_rate, 0, 0); swr.dst.sample_rate, &swr.src.ch_layout, swr.src.format,
if (!swr.ctx) { swr.src.sample_rate, 0, 0);
if (swr.ctx == nullptr) {
av_packet_unref(av.packet); av_packet_unref(av.packet);
error_code = AVERROR(ENOMEM); error_code = AVERROR(ENOMEM);
goto cleanup; goto cleanup;
@ -319,15 +319,15 @@ static bool M_Convert(const int32_t sample_id)
const int32_t out_samples = const int32_t out_samples =
swr_get_out_samples(swr.ctx, av.frame->nb_samples); swr_get_out_samples(swr.ctx, av.frame->nb_samples);
av_samples_alloc( av_samples_alloc(
&out_buffer, nullptr, swr.dst_channels, out_samples, &out_buffer, nullptr, swr.dst.ch_layout.nb_channels,
swr.dst_format, 1); out_samples, swr.dst.format, 1);
int32_t resampled_size = swr_convert( int32_t resampled_size = swr_convert(
swr.ctx, &out_buffer, out_samples, swr.ctx, &out_buffer, out_samples,
(const uint8_t **)av.frame->data, av.frame->nb_samples); (const uint8_t **)av.frame->data, av.frame->nb_samples);
while (resampled_size > 0) { while (resampled_size > 0) {
int32_t out_buffer_size = av_samples_get_buffer_size( int32_t out_buffer_size = av_samples_get_buffer_size(
nullptr, swr.dst_channels, resampled_size, swr.dst_format, nullptr, swr.dst.ch_layout.nb_channels, resampled_size,
1); swr.dst.format, 1);
if (out_buffer_size > 0) { if (out_buffer_size > 0) {
working_buffer = Memory_Realloc( working_buffer = Memory_Realloc(
@ -351,10 +351,10 @@ static bool M_Convert(const int32_t sample_id)
av_packet_unref(av.packet); av_packet_unref(av.packet);
} }
int32_t sample_format_bytes = av_get_bytes_per_sample(swr.dst_format); int32_t sample_format_bytes = av_get_bytes_per_sample(swr.dst.format);
sample->num_samples = sample->num_samples = working_buffer_size / sample_format_bytes
working_buffer_size / sample_format_bytes / swr.dst_channels; / swr.dst.ch_layout.nb_channels;
sample->channels = swr.src_channels; sample->channels = swr.src.ch_layout.nb_channels;
sample->sample_data = working_buffer; sample->sample_data = working_buffer;
result = true; result = true;
@ -396,8 +396,7 @@ cleanup:
} }
if (av.codec_ctx) { if (av.codec_ctx) {
avcodec_close(av.codec_ctx); avcodec_free_context(&av.codec_ctx);
av_freep(&av.codec_ctx);
} }
if (av.format_ctx) { if (av.format_ctx) {

View file

@ -52,12 +52,11 @@ typedef struct {
} av; } av;
struct { struct {
int32_t src_format; struct {
int32_t src_channels; int32_t format;
int32_t src_sample_rate; AVChannelLayout ch_layout;
int32_t dst_format; int32_t sample_rate;
int32_t dst_channels; } src, dst;
int32_t dst_sample_rate;
SwrContext *ctx; SwrContext *ctx;
} swr; } swr;
@ -147,17 +146,18 @@ static bool M_EnqueueFrame(AUDIO_STREAM_SOUND *stream)
int32_t error_code; int32_t error_code;
if (!stream->swr.ctx) { if (!stream->swr.ctx) {
stream->swr.src_sample_rate = stream->av.codec_ctx->sample_rate; stream->swr.src.sample_rate = stream->av.codec_ctx->sample_rate;
stream->swr.src_channels = stream->av.codec_ctx->channels; stream->swr.src.ch_layout = stream->av.codec_ctx->ch_layout;
stream->swr.src_format = stream->av.codec_ctx->sample_fmt; stream->swr.src.format = stream->av.codec_ctx->sample_fmt;
stream->swr.dst_sample_rate = AUDIO_WORKING_RATE; stream->swr.dst.sample_rate = AUDIO_WORKING_RATE;
stream->swr.dst_channels = AUDIO_WORKING_CHANNELS; av_channel_layout_default(
stream->swr.dst_format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT); &stream->swr.dst.ch_layout, AUDIO_WORKING_CHANNELS);
stream->swr.ctx = swr_alloc_set_opts( stream->swr.dst.format = Audio_GetAVAudioFormat(AUDIO_WORKING_FORMAT);
stream->swr.ctx, Audio_GetAVChannelLayout(stream->swr.dst_channels), swr_alloc_set_opts2(
stream->swr.dst_format, stream->swr.dst_sample_rate, &stream->swr.ctx, &stream->swr.dst.ch_layout,
Audio_GetAVChannelLayout(stream->swr.src_channels), stream->swr.dst.format, stream->swr.dst.sample_rate,
stream->swr.src_format, stream->swr.src_sample_rate, 0, 0); &stream->swr.src.ch_layout, stream->swr.src.format,
stream->swr.src.sample_rate, 0, 0);
if (!stream->swr.ctx) { if (!stream->swr.ctx) {
av_packet_unref(stream->av.packet); av_packet_unref(stream->av.packet);
error_code = AVERROR(ENOMEM); error_code = AVERROR(ENOMEM);
@ -189,8 +189,8 @@ static bool M_EnqueueFrame(AUDIO_STREAM_SOUND *stream)
const int32_t out_samples = const int32_t out_samples =
swr_get_out_samples(stream->swr.ctx, stream->av.frame->nb_samples); swr_get_out_samples(stream->swr.ctx, stream->av.frame->nb_samples);
av_samples_alloc( av_samples_alloc(
&out_buffer, nullptr, stream->swr.dst_channels, out_samples, &out_buffer, nullptr, stream->swr.dst.ch_layout.nb_channels,
stream->swr.dst_format, 1); out_samples, stream->swr.dst.format, 1);
int32_t resampled_size = swr_convert( int32_t resampled_size = swr_convert(
stream->swr.ctx, &out_buffer, out_samples, stream->swr.ctx, &out_buffer, out_samples,
(const uint8_t **)stream->av.frame->data, (const uint8_t **)stream->av.frame->data,
@ -199,8 +199,8 @@ static bool M_EnqueueFrame(AUDIO_STREAM_SOUND *stream)
size_t out_pos = 0; size_t out_pos = 0;
while (resampled_size > 0) { while (resampled_size > 0) {
const size_t out_buffer_size = av_samples_get_buffer_size( const size_t out_buffer_size = av_samples_get_buffer_size(
nullptr, stream->swr.dst_channels, resampled_size, nullptr, stream->swr.dst.ch_layout.nb_channels, resampled_size,
stream->swr.dst_format, 1); stream->swr.dst.format, 1);
if (out_pos + out_buffer_size > m_DecodeBufferCapacity) { if (out_pos + out_buffer_size > m_DecodeBufferCapacity) {
m_DecodeBufferCapacity = out_pos + out_buffer_size; 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); M_DecodeFrame(stream);
int32_t sdl_sample_rate = stream->av.codec_ctx->sample_rate; const int32_t sdl_sample_rate = stream->av.codec_ctx->sample_rate;
int32_t sdl_channels = stream->av.codec_ctx->channels; const int32_t sdl_channels = stream->av.codec_ctx->ch_layout.nb_channels;
stream->is_read_done = false; stream->is_read_done = false;
stream->is_used = true; stream->is_used = true;
@ -474,14 +474,12 @@ bool Audio_Stream_Close(int32_t sound_id)
AUDIO_STREAM_SOUND *stream = &m_Streams[sound_id]; AUDIO_STREAM_SOUND *stream = &m_Streams[sound_id];
if (stream->av.codec_ctx) { if (stream->av.codec_ctx) {
avcodec_close(stream->av.codec_ctx);
// XXX: potential libav bug - avcodec_close should free this info // XXX: potential libav bug - avcodec_close should free this info
if (stream->av.codec_ctx->extradata != nullptr) { if (stream->av.codec_ctx->extradata != nullptr) {
av_freep(&stream->av.codec_ctx->extradata); 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; 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]; const float *src_ptr = &m_MixBuffer[0];
float *dst_ptr = dst_buffer; 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 s = 0; s < samples_gotten; s++) {
for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) { for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) {
*dst_ptr++ += *src_ptr++ * stream->volume; *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 s = 0; s < samples_gotten; s++) {
for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) { for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) {
*dst_ptr++ += *src_ptr * stream->volume; *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++) { for (int32_t s = 0; s < samples_gotten; s++) {
// downmix to mono // downmix to mono
float src_sample = 0.0f; float src_sample = 0.0f;
for (int32_t i = 0; i < stream->av.codec_ctx->channels; for (int32_t i = 0; i < channels; i++) {
i++) {
src_sample += *src_ptr++; 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++) { for (int32_t c = 0; c < AUDIO_WORKING_CHANNELS; c++) {
*dst_ptr++ += src_sample * stream->volume; *dst_ptr++ += src_sample * stream->volume;
} }

View file

@ -77,6 +77,9 @@ static bool M_Init(const char *const path, IMAGE_READER_CONTEXT *const ctx)
AVStream *video_stream = nullptr; AVStream *video_stream = nullptr;
for (unsigned int i = 0; i < ctx->format_ctx->nb_streams; i++) { for (unsigned int i = 0; i < ctx->format_ctx->nb_streams; i++) {
AVStream *current_stream = ctx->format_ctx->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) { if (current_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream = current_stream; video_stream = current_stream;
break; break;
@ -165,9 +168,7 @@ static void M_Free(IMAGE_READER_CONTEXT *const ctx)
} }
if (ctx->codec_ctx != nullptr) { if (ctx->codec_ctx != nullptr) {
avcodec_close(ctx->codec_ctx); avcodec_free_context(&ctx->codec_ctx);
av_free(ctx->codec_ctx);
ctx->codec_ctx = nullptr;
} }
if (ctx->format_ctx != nullptr) { if (ctx->format_ctx != nullptr) {
@ -490,9 +491,7 @@ cleanup:
} }
if (codec) { if (codec) {
avcodec_close(codec_ctx); avcodec_free_context(&codec_ctx);
av_free(codec_ctx);
codec_ctx = nullptr;
} }
if (frame) { if (frame) {

View file

@ -90,7 +90,7 @@ typedef struct {
} M_PACKET_LIST; } M_PACKET_LIST;
typedef struct { typedef struct {
AVFifoBuffer *pkt_list; AVFifo *pkt_list;
int nb_packets; int nb_packets;
int size; int size;
int64_t duration; int64_t duration;
@ -103,7 +103,7 @@ typedef struct {
typedef struct { typedef struct {
int freq; int freq;
int channels; int channels;
int64_t channel_layout; AVChannelLayout ch_layout;
enum AVSampleFormat fmt; enum AVSampleFormat fmt;
int frame_size; int frame_size;
int bytes_per_sec; int bytes_per_sec;
@ -131,6 +131,10 @@ typedef struct {
AVRational sar; AVRational sar;
} M_FRAME; } M_FRAME;
typedef struct {
int64_t pkt_pos;
} M_FRAME_DATA;
typedef struct { typedef struct {
M_FRAME queue[FRAME_QUEUE_SIZE]; M_FRAME queue[FRAME_QUEUE_SIZE];
int rindex; int rindex;
@ -223,6 +227,7 @@ typedef struct {
int target_surface_height; int target_surface_height;
double frame_timer; double frame_timer;
double frame_last_returned_time;
int video_stream; int video_stream;
AVStream *video_st; AVStream *video_st;
M_PACKET_QUEUE videoq; M_PACKET_QUEUE videoq;
@ -277,16 +282,13 @@ static int M_PacketQueuePutPrivate(M_PACKET_QUEUE *q, AVPacket *pkt)
return -1; 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.pkt = pkt;
pkt1.serial = q->serial; 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->nb_packets++;
q->size += pkt1.pkt->size + sizeof(pkt1); q->size += pkt1.pkt->size + sizeof(pkt1);
q->duration += pkt1.pkt->duration; q->duration += pkt1.pkt->duration;
@ -327,8 +329,9 @@ static int M_PacketQueuePutNullPacket(
static int M_PacketQueueInit(M_PACKET_QUEUE *q) static int M_PacketQueueInit(M_PACKET_QUEUE *q)
{ {
memset(q, 0, sizeof(M_PACKET_QUEUE)); memset(q, 0, sizeof(M_PACKET_QUEUE));
q->pkt_list = av_fifo_alloc(sizeof(M_PACKET_LIST)); q->pkt_list =
if (!q->pkt_list) { av_fifo_alloc2(1, sizeof(M_PACKET_LIST), AV_FIFO_FLAG_AUTO_GROW);
if (q->pkt_list == nullptr) {
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
@ -353,8 +356,7 @@ static void M_PacketQueueFlush(M_PACKET_QUEUE *q)
M_PACKET_LIST pkt1; M_PACKET_LIST pkt1;
SDL_LockMutex(q->mutex); SDL_LockMutex(q->mutex);
while (av_fifo_size(q->pkt_list) >= (signed)sizeof(pkt1)) { while (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) {
av_fifo_generic_read(q->pkt_list, &pkt1, sizeof(pkt1), nullptr);
av_packet_free(&pkt1.pkt); av_packet_free(&pkt1.pkt);
} }
q->nb_packets = 0; q->nb_packets = 0;
@ -367,7 +369,7 @@ static void M_PacketQueueFlush(M_PACKET_QUEUE *q)
static void M_PacketQueueDestroy(M_PACKET_QUEUE *q) static void M_PacketQueueDestroy(M_PACKET_QUEUE *q)
{ {
M_PacketQueueFlush(q); M_PacketQueueFlush(q);
av_fifo_freep(&q->pkt_list); av_fifo_freep2(&q->pkt_list);
SDL_DestroyMutex(q->mutex); SDL_DestroyMutex(q->mutex);
SDL_DestroyCond(q->cond); SDL_DestroyCond(q->cond);
} }
@ -402,8 +404,7 @@ static int M_PacketQueueGet(
break; break;
} }
if (av_fifo_size(q->pkt_list) >= (signed)sizeof(pkt1)) { if (av_fifo_read(q->pkt_list, &pkt1, 1) >= 0) {
av_fifo_generic_read(q->pkt_list, &pkt1, sizeof(pkt1), nullptr);
q->nb_packets--; q->nb_packets--;
q->size -= pkt1.pkt->size + sizeof(pkt1); q->size -= pkt1.pkt->size + sizeof(pkt1);
q->duration -= pkt1.pkt->duration; q->duration -= pkt1.pkt->duration;
@ -518,6 +519,15 @@ static int M_DecoderDecodeFrame(M_DECODER *d, AVFrame *frame)
av_packet_unref(d->pkt); 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)) { if (avcodec_send_packet(d->avctx, d->pkt) == AVERROR(EAGAIN)) {
LOG_ERROR( LOG_ERROR(
"Receive_frame and send_packet both returned EAGAIN, " "Receive_frame and send_packet both returned EAGAIN, "
@ -1109,37 +1119,52 @@ static int M_AudioThread(void *arg)
M_STATE *is = arg; M_STATE *is = arg;
AVFrame *frame = av_frame_alloc(); AVFrame *frame = av_frame_alloc();
M_FRAME *af; M_FRAME *af;
int last_serial = -1;
int got_frame = 0; int got_frame = 0;
AVRational tb; AVRational tb;
int ret = 0; int ret = 0;
if (!frame) { if (frame == nullptr) {
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
do { do {
if ((got_frame = M_DecoderDecodeFrame(&is->auddec, frame)) < 0) { got_frame = M_DecoderDecodeFrame(&is->auddec, frame);
if (got_frame < 0) {
goto the_end; goto the_end;
} }
if (got_frame) { if (got_frame) {
tb = (AVRational) { 1, frame->sample_rate }; 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; goto the_end;
} }
af->pts = af->pts =
(frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); (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->serial = is->auddec.pkt_serial;
af->duration = af->duration =
av_q2d((AVRational) { frame->nb_samples, frame->sample_rate }); av_q2d((AVRational) { frame->nb_samples, frame->sample_rate });
av_frame_move_ref(af->frame, frame); av_frame_move_ref(af->frame, frame);
M_FrameQueuePush(&is->sampq); 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); } while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF);
the_end: the_end:
av_frame_free(&frame); av_frame_free(&frame);
return ret; return ret;
@ -1180,17 +1205,23 @@ static int M_VideoThread(void *arg)
continue; 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 = duration =
(frame_rate.num && frame_rate.den (frame_rate.num && frame_rate.den
? av_q2d((AVRational) { frame_rate.den, frame_rate.num }) ? av_q2d((AVRational) { frame_rate.den, frame_rate.num })
: 0); : 0);
pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb);
ret = M_QueuePicture( 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); av_frame_unref(frame);
if (is->videoq.serial != is->viddec.pkt_serial) {
if (ret < 0) { break;
goto the_end;
} }
} }
the_end: the_end:
@ -1240,6 +1271,7 @@ static int M_SynchronizeAudio(M_STATE *is, int nb_samples)
static int M_AudioDecodeFrame(M_STATE *is) static int M_AudioDecodeFrame(M_STATE *is)
{ {
int data_size, resampled_data_size; int data_size, resampled_data_size;
av_unused double audio_clock0; av_unused double audio_clock0;
int wanted_nb_samples; int wanted_nb_samples;
@ -1250,6 +1282,15 @@ static int M_AudioDecodeFrame(M_STATE *is)
} }
do { 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))) { if (!(af = M_FrameQueuePeekReadable(&is->sampq))) {
return -1; return -1;
} }
@ -1257,39 +1298,39 @@ static int M_AudioDecodeFrame(M_STATE *is)
} while (af->serial != is->audioq.serial); } while (af->serial != is->audioq.serial);
data_size = av_samples_get_buffer_size( data_size = av_samples_get_buffer_size(
nullptr, af->frame->channels, af->frame->nb_samples, af->frame->format, nullptr, af->frame->ch_layout.nb_channels, af->frame->nb_samples,
1); 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); wanted_nb_samples = M_SynchronizeAudio(is, af->frame->nb_samples);
if (af->frame->format != is->audio_src.fmt 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 || af->frame->sample_rate != is->audio_src.freq
|| (wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) { || (wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) {
int ret;
swr_free(&is->swr_ctx); swr_free(&is->swr_ctx);
is->swr_ctx = swr_alloc_set_opts( ret = swr_alloc_set_opts2(
nullptr, is->audio_tgt.channel_layout, is->audio_tgt.fmt, &is->swr_ctx, &is->audio_tgt.ch_layout, is->audio_tgt.fmt,
is->audio_tgt.freq, dec_channel_layout, af->frame->format, is->audio_tgt.freq, &af->frame->ch_layout, af->frame->format,
af->frame->sample_rate, 0, nullptr); 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( LOG_ERROR(
"Cannot create sample rate converter for conversion of %d Hz " "Cannot create sample rate converter for conversion of %d Hz "
"%s %d channels to %d Hz %s %d channels!", "%s %d channels to %d Hz %s %d channels!",
af->frame->sample_rate, af->frame->sample_rate,
av_get_sample_fmt_name(af->frame->format), af->frame->channels, av_get_sample_fmt_name(af->frame->format),
is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), af->frame->ch_layout.nb_channels, is->audio_tgt.freq,
is->audio_tgt.channels); av_get_sample_fmt_name(is->audio_tgt.fmt),
is->audio_tgt.ch_layout.nb_channels);
swr_free(&is->swr_ctx); swr_free(&is->swr_ctx);
return -1; return -1;
} }
is->audio_src.channel_layout = dec_channel_layout; if (av_channel_layout_copy(
is->audio_src.channels = af->frame->channels; &is->audio_src.ch_layout, &af->frame->ch_layout)
< 0) {
return -1;
}
is->audio_src.freq = af->frame->sample_rate; is->audio_src.freq = af->frame->sample_rate;
is->audio_src.fmt = af->frame->format; is->audio_src.fmt = af->frame->format;
} }
@ -1301,7 +1342,8 @@ static int M_AudioDecodeFrame(M_STATE *is)
/ af->frame->sample_rate / af->frame->sample_rate
+ 256; + 256;
int out_size = av_samples_get_buffer_size( 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; int len2;
if (out_size < 0) { if (out_size < 0) {
LOG_ERROR("av_samples_get_buffer_size() failed"); LOG_ERROR("av_samples_get_buffer_size() failed");
@ -1330,12 +1372,13 @@ static int M_AudioDecodeFrame(M_STATE *is)
return -1; return -1;
} }
if (len2 == out_count) { if (len2 == out_count) {
LOG_ERROR("audio buffer is probably too small");
if (swr_init(is->swr_ctx) < 0) { if (swr_init(is->swr_ctx) < 0) {
swr_free(&is->swr_ctx); swr_free(&is->swr_ctx);
} }
} }
is->audio_buf = is->audio_buf1; 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); * av_get_bytes_per_sample(is->audio_tgt.fmt);
} else { } else {
is->audio_buf = af->frame->data[0]; 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( static int M_AudioOpen(
M_STATE *is, int64_t wanted_channel_layout, int wanted_nb_channels, M_STATE *is, AVChannelLayout *wanted_channel_layout, int wanted_sample_rate,
int wanted_sample_rate, M_AUDIO_PARAMS *audio_hw_params) M_AUDIO_PARAMS *audio_hw_params)
{ {
SDL_AudioSpec wanted_spec, spec; 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_nb_channels[] = { 0, 0, 1, 6, 2, 6, 4, 6 };
static const int next_sample_rates[] = { 0, 44100, 48000, 96000, 192000 }; static const int next_sample_rates[] = { 0, 44100, 48000, 96000, 192000 };
int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1; 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) { if (env) {
wanted_nb_channels = atoi(env); wanted_nb_channels = atoi(env);
wanted_channel_layout = av_channel_layout_uninit(wanted_channel_layout);
av_get_default_channel_layout(wanted_nb_channels); av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);
} }
if (!wanted_channel_layout if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {
|| wanted_nb_channels av_channel_layout_uninit(wanted_channel_layout);
!= av_get_channel_layout_nb_channels(wanted_channel_layout)) { av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);
wanted_channel_layout =
av_get_default_channel_layout(wanted_nb_channels);
wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
} }
wanted_nb_channels = wanted_nb_channels = wanted_channel_layout->nb_channels;
av_get_channel_layout_nb_channels(wanted_channel_layout);
wanted_spec.channels = wanted_nb_channels; wanted_spec.channels = wanted_nb_channels;
wanted_spec.freq = wanted_sample_rate; wanted_spec.freq = wanted_sample_rate;
if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) { if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
@ -1448,6 +1489,9 @@ static int M_AudioOpen(
nullptr, 0, &wanted_spec, &spec, nullptr, 0, &wanted_spec, &spec,
SDL_AUDIO_ALLOW_FREQUENCY_CHANGE SDL_AUDIO_ALLOW_FREQUENCY_CHANGE
| SDL_AUDIO_ALLOW_CHANNELS_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)]; wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
if (!wanted_spec.channels) { if (!wanted_spec.channels) {
wanted_spec.freq = next_sample_rates[next_sample_rate_idx--]; wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
@ -1457,16 +1501,16 @@ static int M_AudioOpen(
return -1; return -1;
} }
} }
wanted_channel_layout = av_channel_layout_default(wanted_channel_layout, wanted_spec.channels);
av_get_default_channel_layout(wanted_spec.channels);
} }
if (spec.format != AUDIO_S16SYS) { if (spec.format != AUDIO_S16SYS) {
LOG_ERROR("SDL advised audio format %d is not supported!", spec.format); LOG_ERROR("SDL advised audio format %d is not supported!", spec.format);
return -1; return -1;
} }
if (spec.channels != wanted_spec.channels) { if (spec.channels != wanted_spec.channels) {
wanted_channel_layout = av_get_default_channel_layout(spec.channels); av_channel_layout_uninit(wanted_channel_layout);
if (!wanted_channel_layout) { av_channel_layout_default(wanted_channel_layout, spec.channels);
if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {
LOG_ERROR( LOG_ERROR(
"SDL advised channel count %d is not supported!", "SDL advised channel count %d is not supported!",
spec.channels); spec.channels);
@ -1476,12 +1520,15 @@ static int M_AudioOpen(
audio_hw_params->fmt = AV_SAMPLE_FMT_S16; audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
audio_hw_params->freq = spec.freq; audio_hw_params->freq = spec.freq;
audio_hw_params->channel_layout = wanted_channel_layout; if (av_channel_layout_copy(
audio_hw_params->channels = spec.channels; &audio_hw_params->ch_layout, wanted_channel_layout)
< 0)
return -1;
audio_hw_params->frame_size = av_samples_get_buffer_size( 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( 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); audio_hw_params->fmt, 1);
if (audio_hw_params->bytes_per_sec <= 0 if (audio_hw_params->bytes_per_sec <= 0
|| audio_hw_params->frame_size <= 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; const AVDictionaryEntry *t = nullptr;
int sample_rate; int sample_rate;
int nb_channels; int nb_channels;
int64_t channel_layout; AVChannelLayout ch_layout;
int ret = 0; int ret = 0;
if (stream_index < 0 || stream_index >= (signed)ic->nb_streams) { 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) { switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO: case AVMEDIA_TYPE_AUDIO:
sample_rate = avctx->sample_rate; sample_rate = avctx->sample_rate;
nb_channels = avctx->channels; ch_layout = avctx->ch_layout;
channel_layout = avctx->channel_layout;
if ((ret = M_AudioOpen( if ((ret = M_AudioOpen(is, &ch_layout, sample_rate, &is->audio_tgt))
is, channel_layout, nb_channels, sample_rate, &is->audio_tgt))
< 0) { < 0) {
goto fail; goto fail;
} }
@ -1568,9 +1613,7 @@ static int M_StreamComponentOpen(M_STATE *is, int stream_index)
< 0) { < 0) {
goto fail; goto fail;
} }
if ((is->ic->iformat->flags if (is->ic->iformat->flags & AVFMT_NOTIMESTAMPS) {
& (AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK))
&& !is->ic->iformat->read_seek) {
is->auddec.start_pts = is->audio_st->start_time; is->auddec.start_pts = is->audio_st->start_time;
is->auddec.start_pts_tb = is->audio_st->time_base; 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: fail:
avcodec_free_context(&avctx); avcodec_free_context(&avctx);
out: out:
av_channel_layout_uninit(&ch_layout);
return ret; return ret;
} }

View file

@ -53,7 +53,7 @@ RUN apt-get install -y \
zlib1g-dev zlib1g-dev
RUN git clone \ RUN git clone \
--depth 1 \ --depth 1 \
--branch "n4.4.1" \ --branch "n7.1" \
https://github.com/FFmpeg/FFmpeg https://github.com/FFmpeg/FFmpeg
COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt
RUN cd FFmpeg \ RUN cd FFmpeg \

View file

@ -54,7 +54,7 @@ RUN apt-get install -y \
nasm nasm
RUN git clone \ RUN git clone \
--depth 1 \ --depth 1 \
--branch "n4.4.1" \ --branch "n7.1" \
https://github.com/FFmpeg/FFmpeg https://github.com/FFmpeg/FFmpeg
COPY --from=zlib /ext/ /usr/i686-w64-mingw32/ COPY --from=zlib /ext/ /usr/i686-w64-mingw32/
COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt
@ -65,6 +65,8 @@ RUN cd FFmpeg \
--cross-prefix=i686-w64-mingw32- \ --cross-prefix=i686-w64-mingw32- \
--prefix=/ext/ \ --prefix=/ext/ \
--cc=i686-w64-mingw32-gcc \ --cc=i686-w64-mingw32-gcc \
--cxx=i686-w64-mingw32-g++ \
--host-cc=i686-w64-mingw32-gcc \
--strip=i686-w64-mingw32-strip \ --strip=i686-w64-mingw32-strip \
--pkg-config=i686-w64-mingw32-pkg-config \ --pkg-config=i686-w64-mingw32-pkg-config \
--enable-static \ --enable-static \

View file

@ -53,7 +53,7 @@ RUN apt-get install -y \
zlib1g-dev zlib1g-dev
RUN git clone \ RUN git clone \
--depth 1 \ --depth 1 \
--branch "n4.4.1" \ --branch "n7.1" \
https://github.com/FFmpeg/FFmpeg https://github.com/FFmpeg/FFmpeg
COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt
RUN cd FFmpeg \ RUN cd FFmpeg \

View file

@ -56,7 +56,7 @@ RUN apt-get install -y \
nasm nasm
RUN git clone \ RUN git clone \
--depth 1 \ --depth 1 \
--branch "n4.4.1" \ --branch "n7.1" \
https://github.com/FFmpeg/FFmpeg https://github.com/FFmpeg/FFmpeg
COPY --from=zlib /ext/ /usr/i686-w64-mingw32/ COPY --from=zlib /ext/ /usr/i686-w64-mingw32/
COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt COPY ./tools/ffmpeg_flags.txt /tmp/ffmpeg_flags.txt
@ -67,6 +67,8 @@ RUN cd FFmpeg \
--cross-prefix=i686-w64-mingw32- \ --cross-prefix=i686-w64-mingw32- \
--prefix=/ext/ \ --prefix=/ext/ \
--cc=i686-w64-mingw32-gcc \ --cc=i686-w64-mingw32-gcc \
--cxx=i686-w64-mingw32-g++ \
--host-cc=i686-w64-mingw32-gcc \
--strip=i686-w64-mingw32-strip \ --strip=i686-w64-mingw32-strip \
--pkg-config=i686-w64-mingw32-pkg-config \ --pkg-config=i686-w64-mingw32-pkg-config \
--enable-static \ --enable-static \