xine-lib/xine-lib-ffmpeg-7.patch

1099 lines
40 KiB
Diff

Cumulative patches from upstream:
https://sourceforge.net/p/xine/xine-lib-1.2/ci/73b833e7fe35
https://sourceforge.net/p/xine/xine-lib-1.2/ci/1e7b18400886
https://sourceforge.net/p/xine/xine-lib-1.2/ci/0a786d63bbdb
https://sourceforge.net/p/xine/xine-lib-1.2/ci/6f1000084f60
https://sourceforge.net/p/xine/xine-lib-1.2/ci/771f4ae27e58
diff --git a/src/combined/ffmpeg/demux_avformat.c b/src/combined/ffmpeg/demux_avformat.c
index 30b6a2d..a3c2cae 100644
--- a/src/combined/ffmpeg/demux_avformat.c
+++ b/src/combined/ffmpeg/demux_avformat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2022 the xine project
+ * Copyright (C) 2013-2023 the xine project
* Copyright (C) 2013-2020 Petri Hintukainen <phintuka@users.sourceforge.net>
*
* This file is part of xine, a free video player.
@@ -423,8 +423,13 @@ static int find_avformat_streams(avformat_demux_plugin_t *this) {
}
#ifdef XFF_CODECPAR
+# if XFF_AUDIO_CHANNEL_LAYOUT < 2
if (st->codecpar && st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
st->codecpar->sample_rate != 0 && st->codecpar->channels != 0)
+# else
+ if (st->codecpar && st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
+ st->codecpar->sample_rate != 0 && st->codecpar->ch_layout.nb_channels != 0)
+# endif
#else
if (st->codec && st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
st->codec->sample_rate != 0 && st->codec->channels != 0)
@@ -501,7 +506,11 @@ static void send_headers_audio(avformat_demux_plugin_t *this) {
buf->size = extradata_size + sizeof(xine_waveformatex);
buf->decoder_info[1] = ctx->sample_rate;
buf->decoder_info[2] = ctx->bits_per_coded_sample;
+#if XFF_AUDIO_CHANNEL_LAYOUT < 2
buf->decoder_info[3] = ctx->channels;
+#else
+ buf->decoder_info[3] = ctx->ch_layout.nb_channels;
+#endif
buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_STDHEADER | BUF_FLAG_FRAME_END;
this->stream->audio_fifo->put (this->stream->audio_fifo, buf);
diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c
index b542b85..cec1ce6 100644
--- a/src/combined/ffmpeg/ff_audio_decoder.c
+++ b/src/combined/ffmpeg/ff_audio_decoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001-2022 the xine project
+ * Copyright (C) 2001-2024 the xine project
*
* This file is part of xine, a free video player.
*
@@ -67,6 +67,7 @@ typedef struct {
xine_t *xine;
float gain;
+ int bitexact;
} ff_audio_class_t;
typedef struct ff_audio_decoder_s {
@@ -188,14 +189,25 @@ static int ff_aac_mode_parse (ff_audio_decoder_t *this, uint8_t *buf, int size,
xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
"ffmpeg_audio_dec: found AAC ADTS syncword after %d bytes\n", i);
if (this->buftype == BUF_AUDIO_AAC_LATM) {
+ uint8_t *ed = NULL;
+ int es = 0;
xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
"ffmpeg_audio_dec: stream says LATM but is ADTS -> switching decoders\n");
- if (this->decoder_ok) {
- pthread_mutex_lock (&ffmpeg_lock);
- avcodec_close (this->context);
- pthread_mutex_unlock (&ffmpeg_lock);
- this->decoder_ok = 0;
+ pthread_mutex_lock (&ffmpeg_lock);
+ if (this->context) {
+ ed = this->context->extradata;
+ es = this->context->extradata_size;
+ this->context->extradata = NULL;
+ this->context->extradata_size = 0;
+ XFF_FREE_CONTEXT (this->context);
}
+ this->decoder_ok = 0;
+ this->context = XFF_ALLOC_CONTEXT ();
+ if (this->context) {
+ this->context->extradata = ed;
+ this->context->extradata_size = es;
+ }
+ pthread_mutex_unlock (&ffmpeg_lock);
this->codec = NULL;
ff_audio_open_codec (this, BUF_AUDIO_AAC);
}
@@ -303,7 +315,11 @@ static void ff_audio_init_codec(ff_audio_decoder_t *this, unsigned int codec_typ
this->context->bits_per_sample = this->ff_bits;
this->context->sample_rate = this->ff_sample_rate;
+#if XFF_AUDIO_CHANNEL_LAYOUT < 2
this->context->channels = this->ff_channels;
+#else
+ this->context->ch_layout.nb_channels = this->ff_channels;
+#endif
this->context->codec_id = this->codec->id;
this->context->codec_type = this->codec->type;
this->context->codec_tag = _x_stream_info_get(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC);
@@ -345,6 +361,11 @@ static int ff_audio_open_codec(ff_audio_decoder_t *this, unsigned int codec_type
return -1;
}
+ if (this->class->bitexact)
+ this->context->flags |= CODEC_FLAG_BITEXACT;
+ else
+ this->context->flags &= ~CODEC_FLAG_BITEXACT;
+
pthread_mutex_lock (&ffmpeg_lock);
if (XFF_AVCODEC_OPEN (this->context, this->codec) < 0) {
pthread_mutex_unlock (&ffmpeg_lock);
@@ -527,16 +548,75 @@ static void ff_audio_output_close(ff_audio_decoder_t *this)
this->ao_mode = 0;
}
+static unsigned int ff_list_channels (uint8_t *list, uint64_t map) {
+ unsigned int n, bit;
+
+ for (n = bit = 0; map; map >>= 1, bit++) {
+ uint32_t b = map & 1;
+
+ list[n] = bit;
+ n += b;
+ }
+ return n;
+}
+
static void ff_map_channels (ff_audio_decoder_t *this) {
uint64_t ff_map;
+ uint8_t ff_list[64];
+ unsigned int ff_num;
+ const char *type = "native";
int caps = this->stream->audio_out->get_capabilities (this->stream->audio_out);
+#if XFF_AUDIO_CHANNEL_LAYOUT < 2
+
/* safety kludge for very old libavcodec */
-#ifdef AV_CH_FRONT_LEFT
+# ifdef AV_CH_FRONT_LEFT
ff_map = this->context->channel_layout;
if (!ff_map) /* wma2 bug */
-#endif
+# endif
ff_map = ((uint64_t)1 << this->context->channels) - 1;
+ ff_num = ff_list_channels (ff_list, ff_map);
+
+#else /* XFF_AUDIO_CHANNEL_LAYOUT == 2 */
+
+ ff_num = this->context->ch_layout.nb_channels;
+ if (ff_num > (int)(sizeof (ff_list) / sizeof (ff_list[0])))
+ ff_num = sizeof (ff_list) / sizeof (ff_list[0]);
+ switch (this->context->ch_layout.order) {
+ const AVChannelCustom *cmap;
+ unsigned int i;
+
+ case AV_CHANNEL_ORDER_UNSPEC:
+ type = "unknown";
+ goto _fallback;
+
+ case AV_CHANNEL_ORDER_NATIVE:
+ ff_map = this->context->ch_layout.u.mask;
+ if (!ff_map) /* wma2 bug */
+ ff_map = ((uint64_t)1 << ff_num) - 1;
+ ff_num = ff_list_channels (ff_list, ff_map);
+ break;
+
+ case AV_CHANNEL_ORDER_CUSTOM:
+ type = "custom";
+ if (!(cmap = this->context->ch_layout.u.map))
+ goto _fallback;
+ ff_map = 0;
+ for (i = 0; i < ff_num; i++) {
+ ff_list[i] = cmap[i].id;
+ ff_map |= (uint64_t)1 << ff_list[i];
+ }
+ break;
+
+ default:
+ type = "unsupported";
+ /* fall through */
+ _fallback:
+ ff_map = ((uint64_t)1 << ff_num) - 1;
+ ff_num = ff_list_channels (ff_list, ff_map);
+ }
+
+#endif
if ((caps != this->ao_caps) || (ff_map != this->ff_map)) {
unsigned int i, j;
@@ -562,7 +642,7 @@ static void ff_map_channels (ff_audio_decoder_t *this) {
this->ao_caps = caps;
this->ff_map = ff_map;
- this->ff_channels = this->context->channels;
+ this->ff_channels = ff_num;
/* silence out */
for (i = 0; i < MAX_CHANNELS; i++)
@@ -576,20 +656,23 @@ static void ff_map_channels (ff_audio_decoder_t *this) {
this->left[0] = this->right[0] = 0;
tries = wishlist + 0 * num_modes;
} else if (this->ff_channels == 2) { /* stereo */
+ /* FIXME: libxine does not yet support audio selection _after_ decoding.
+ * For now, treat the most common "dual mono" case as stereo. */
name_map[0] = 0;
name_map[1] = 1;
this->left[0] = 0;
this->right[0] = 1;
tries = wishlist + 1 * num_modes;
} else {
- for (i = j = 0; i < sizeof (base_map) / sizeof (base_map[0]); i++) {
- if ((ff_map >> i) & 1) {
- int8_t target = base_map[i];
- if ((target >= 0) && (this->map[target] < 0))
- this->map[target] = j;
- name_map[j] = i; /* for debug output below */
- j++;
- }
+ for (i = 0; i < ff_num; i++) {
+ int8_t target;
+ uint32_t num = ff_list[i];
+ if (num >= sizeof (base_map) / sizeof (base_map[0]))
+ continue;
+ target = base_map[num];
+ if ((target >= 0) && (this->map[target] < 0))
+ this->map[target] = i;
+ name_map[i] = num; /* for debug output below */
}
this->left[0] = this->map[0] < 0 ? 0 : this->map[0];
this->map[0] = -1;
@@ -641,8 +724,8 @@ static void ff_map_channels (ff_audio_decoder_t *this) {
"rear center",
"side left", "side right"
};
- int8_t buf[200];
- int p = sprintf (buf, "ff_audio_dec: channel layout: ");
+ int8_t buf[256];
+ int p = sprintf (buf, "ff_audio_dec: %s channel layout: ", type);
int8_t *indx = this->left;
for (i = 0; i < 2; i++) {
buf[p++] = '[';
@@ -730,7 +813,7 @@ static void ff_audio_unparse (ff_audio_decoder_t *this) {
#define CLIP_16(v) ((v + 0x8000) & ~0xffff ? (v >> 31) ^ 0x7fff : v)
static int ff_audio_decode (ff_audio_decoder_t *this) {
- int16_t *decode_buffer = (int16_t *)this->send.buf;
+ int16_t *decode_buffer = (int16_t *)ASSUME_ALIGNED_2 (this->send.buf, 2);
int consumed, got_frame = 0;
#if XFF_AUDIO >= 4
float gain = this->class->gain;
@@ -805,13 +888,13 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
const stype *p1, *p2, *p3, *p4;\
int i, sstep;\
int8_t *x = idx;\
- int16_t *dptr = (int16_t *)decode_buffer + dindx;\
+ int16_t *dptr = decode_buffer + dindx;\
if (planar) {\
- p1 = (stype *)this->av_frame->extended_data[x[0]];\
+ p1 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[0]], sizeof (stype));\
if (!p1) break;\
sstep = 1;\
} else {\
- p1 = (stype *)this->av_frame->extended_data[0];\
+ p1 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype));\
if (!p1) break;\
p1 += x[0];\
sstep = this->ff_channels;\
@@ -827,10 +910,10 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
break;\
}\
if (planar) {\
- p2 = (stype *)this->av_frame->extended_data[x[1]];\
+ p2 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[1]], sizeof (stype));\
if (!p2) break;\
} else\
- p2 = (stype *)this->av_frame->extended_data[0] + x[1];\
+ p2 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype)) + x[1];\
if (num == 2) {\
for (i = 0; i < samples; i++) {\
int32_t v = MIX_FIX(*p2);\
@@ -845,10 +928,10 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
break;\
}\
if (planar) {\
- p3 = (stype *)this->av_frame->extended_data[x[2]];\
+ p3 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[2]], sizeof (stype));\
if (!p3) break;\
} else\
- p3 = (stype *)this->av_frame->extended_data[0] + x[2];\
+ p3 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype)) + x[2];\
if (num == 3) {\
for (i = 0; i < samples; i++) {\
int32_t v = MIX_FIX(*p2);\
@@ -865,10 +948,10 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
break;\
}\
if (planar) {\
- p4 = (stype *)this->av_frame->extended_data[x[3]];\
+ p4 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[3]], sizeof (stype));\
if (!p4) break;\
} else\
- p4 = (stype *)this->av_frame->extended_data[0] + x[3];\
+ p4 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype)) + x[3];\
for (i = 0; i < samples; i++) {\
int32_t v = MIX_FIX(*p2);\
p2 += sstep;\
@@ -937,13 +1020,13 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
int i, sstep;\
float gain3;\
int8_t *x = idx;\
- int16_t *dptr = (int16_t *)decode_buffer + dindx;\
+ int16_t *dptr = decode_buffer + dindx;\
if (planar) {\
- p1 = (stype *)this->av_frame->extended_data[x[0]];\
+ p1 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[0]], sizeof (stype));\
if (!p1) break;\
sstep = 1;\
} else {\
- p1 = (stype *)this->av_frame->extended_data[0];\
+ p1 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype));\
if (!p1) break;\
p1 += x[0];\
sstep = this->ff_channels;\
@@ -959,10 +1042,10 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
}\
gain3 = gain * 0.7071;\
if (planar) {\
- p2 = (stype *)this->av_frame->extended_data[x[1]];\
+ p2 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[1]], sizeof (stype));\
if (!p2) break;\
} else\
- p2 = (stype *)this->av_frame->extended_data[0] + x[1];\
+ p2 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype)) + x[1];\
if (num == 2) {\
for (i = 0; i < samples; i++) {\
int32_t v = (*p1) * gain + (*p2) * gain3;\
@@ -974,10 +1057,10 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
break;\
}\
if (planar) {\
- p3 = (stype *)this->av_frame->extended_data[x[2]];\
+ p3 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[2]], sizeof (stype));\
if (!p3) break;\
} else\
- p3 = (stype *)this->av_frame->extended_data[0] + x[2];\
+ p3 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype)) + x[2];\
if (num == 3) {\
for (i = 0; i < samples; i++) {\
int32_t v = (*p1) * gain + (*p2 + *p3) * gain3;\
@@ -990,10 +1073,10 @@ static int ff_audio_decode (ff_audio_decoder_t *this) {
break;\
}\
if (planar) {\
- p4 = (stype *)this->av_frame->extended_data[x[3]];\
+ p4 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[x[3]], sizeof (stype));\
if (!p4) break;\
} else\
- p4 = (stype *)this->av_frame->extended_data[0] + x[3];\
+ p4 = (stype *)ASSUME_ALIGNED_2 (this->av_frame->extended_data[0], sizeof (stype)) + x[3];\
for (i = 0; i < samples; i++) {\
int32_t v = (*p1) * gain + (*p2 + *p3 + *p4) * gain3;\
p1 += sstep;\
@@ -1174,8 +1257,8 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf)
/* the above codecs output float samples, not 16-bit integers */
int samples = this->send.len / sizeof(float);
float gain = this->class->gain;
- float *p = (float *)this->decode_buffer;
- int16_t *q = (int16_t *)this->decode_buffer;
+ float *p = (float *)ASSUME_ALIGNED_2 (this->decode_buffer, 4);
+ int16_t *q = (int16_t *)ASSUME_ALIGNED_2 (this->decode_buffer, 2);
int i;
for (i = samples; i; i--) {
int v = *p++ * gain;
@@ -1189,7 +1272,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf)
int samples = this->send.len / (this->ff_channels * 2);
int channels = this->ao_channels;
int ff_channels = this->ff_channels;
- int16_t *p = (int16_t *)this->decode_buffer;
+ int16_t *p = (int16_t *)ASSUME_ALIGNED_2 (this->decode_buffer, 2);
int16_t *q = p;
int shift = this->downmix_shift, i, j;
/* downmix mono output to stereo first */
@@ -1234,7 +1317,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf)
}
/* final mono downmix */
if (channels > this->ao_channels) {
- p = (int16_t *)this->decode_buffer;
+ p = (int16_t *)ASSUME_ALIGNED_2 (this->decode_buffer, 2);
q = p;
for (i = samples; i; i--) {
int v = *p++;
@@ -1310,11 +1393,27 @@ static void ff_audio_reset (audio_decoder_t *this_gen) {
XFF_FREE_FRAME (this->av_frame);
}
#endif
+#if 1
+ avcodec_flush_buffers (this->context);
+#else
pthread_mutex_lock (&ffmpeg_lock);
- avcodec_close (this->context);
- if (XFF_AVCODEC_OPEN (this->context, this->codec) < 0)
+ {
+ uint8_t *ed = this->context->extradata;
+ int es = this->context->extradata_size;
+ this->context->extradata = NULL;
+ this->context->extradata_size = 0;
+ XFF_FREE_CONTEXT (this->context);
this->decoder_ok = 0;
+ this->context = XFF_ALLOC_CONTEXT ();
+ if (this->context) {
+ this->context->extradata = ed;
+ this->context->extradata_size = es;
+ }
+ }
+ if (XFF_AVCODEC_OPEN (this->context, this->codec) >= 0)
+ this->decoder_ok = 1;
pthread_mutex_unlock (&ffmpeg_lock);
+#endif
}
ff_audio_reset_parser(this);
@@ -1352,20 +1451,20 @@ static void ff_audio_dispose (audio_decoder_t *this_gen) {
XFF_FREE_FRAME (this->av_frame);
}
#endif
- pthread_mutex_lock (&ffmpeg_lock);
- avcodec_close (this->context);
- pthread_mutex_unlock (&ffmpeg_lock);
}
+ pthread_mutex_lock (&ffmpeg_lock);
+ if (this->context) {
+ _x_freep (&this->context->extradata);
+ this->context->extradata_size = 0;
+ XFF_FREE_CONTEXT (this->context);
+ }
+ pthread_mutex_unlock (&ffmpeg_lock);
ff_audio_output_close(this);
xine_free_aligned (this->buf);
xine_free_aligned (this->decode_buffer);
- _x_freep (&this->context->extradata);
- this->context->extradata_size = 0;
- XFF_FREE_CONTEXT (this->context);
-
XFF_PACKET_UNREF (this->avpkt);
xine_pts_queue_delete (&this->pts_queue);
@@ -1447,6 +1546,12 @@ static void dispose_audio_class (audio_decoder_class_t *this_gen) {
free (this);
}
+static void ff_bitexact_cb (void *user_data, xine_cfg_entry_t *entry) {
+ ff_audio_class_t *class = (ff_audio_class_t *)user_data;
+
+ class->bitexact = entry->num_value;
+}
+
void *init_audio_plugin (xine_t *xine, const void *data) {
ff_audio_class_t *this ;
@@ -1474,5 +1579,12 @@ void *init_audio_plugin (xine_t *xine, const void *data) {
10, ff_gain_cb, this)
/ (float)20);
+ this->bitexact = xine->config->register_bool (xine->config,
+ "audio.processing.ffmpeg_bitexact", 0,
+ _("Let FFmpeg use precise but slower math"),
+ _("Get slightly better sound, at the expense of speed.\n"
+ "Takes effect with next stream."),
+ 10, ff_bitexact_cb, this);
+
return this;
}
diff --git a/src/combined/ffmpeg/ff_video_decoder.c b/src/combined/ffmpeg/ff_video_decoder.c
index 54efc05..5a10225 100644
--- a/src/combined/ffmpeg/ff_video_decoder.c
+++ b/src/combined/ffmpeg/ff_video_decoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001-2022 the xine project
+ * Copyright (C) 2001-2024 the xine project
*
* This file is part of xine, a free video player.
*
@@ -89,6 +89,11 @@
# define ENABLE_EMMS
#endif
+/*
+#undef XFF_AVCODEC_SLICE_TABLE
+#define XFF_AVCODEC_SLICE_TABLE 1
+*/
+
#define VIDEOBUFSIZE (128*1024)
#define SLICE_BUFFER_SIZE (1194*1024)
@@ -128,6 +133,7 @@ struct ff_video_decoder_s {
int64_t pts;
int64_t last_pts;
+ int64_t tagged_pts;
int video_step;
int reported_video_step;
uint8_t pts_tag_pass;
@@ -147,11 +153,11 @@ struct ff_video_decoder_s {
int bufsize;
int size;
int skipframes;
-
+#if XFF_AVCODEC_SLICE_TABLE == 1
int *slice_offset_table;
int slice_offset_size;
int slice_offset_pos;
-
+#endif
AVFrame *av_frame;
AVFrame *av_frame2;
AVCodecContext *context;
@@ -237,6 +243,13 @@ struct ff_video_decoder_s {
#if XFF_VIDEO > 1
XFF_PACKET_DECL (avpkt);
#endif
+
+#if XFF_AVCODEC_SLICE_TABLE == 2
+ uint8_t *temp_buf;
+ uint32_t temp_size;
+ int slice_num;
+ uint8_t slice_table[1 + 256 * 8];
+#endif
};
/* import color matrix names */
@@ -551,7 +564,9 @@ static int get_buffer_vaapi_vld (AVCodecContext *context, AVFrame *av_frame)
# ifdef XFF_FRAME_AGE
av_frame->age = 1;
# endif
+#ifdef XFF_AVCODEC_REORDERED_OPAQUE
av_frame->reordered_opaque = context->reordered_opaque;
+#endif
ffsf = ffsf_new (this);
if (!ffsf)
@@ -862,7 +877,9 @@ static int get_buffer (AVCodecContext *context, AVFrame *av_frame)
# endif
/* take over pts for this frame to have it reordered */
+#ifdef XFF_AVCODEC_REORDERED_OPAQUE
av_frame->reordered_opaque = context->reordered_opaque;
+#endif
return 0;
}
@@ -1142,9 +1159,13 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
if (this->codec->id == CODEC_ID_VC1 &&
(!this->bih.biWidth || !this->bih.biHeight)) {
/* VC1 codec must be re-opened with correct width and height. */
- avcodec_close(this->context);
-
- if (XFF_AVCODEC_OPEN (this->context, this->codec) < 0) {
+ if (this->context) {
+ _x_freep (&this->context->extradata);
+ this->context->extradata_size = 0;
+ XFF_FREE_CONTEXT (this->context);
+ }
+ this->context = XFF_ALLOC_CONTEXT ();
+ if (!(this->context && XFF_AVCODEC_OPEN (this->context, this->codec) >= 0)) {
pthread_mutex_unlock(&ffmpeg_lock);
xprintf (this->stream->xine, XINE_VERBOSITY_LOG,
_("ffmpeg_video_dec: couldn't open decoder (pass 2)\n"));
@@ -1211,6 +1232,11 @@ static void init_video_codec (ff_video_decoder_t *this, unsigned int codec_type)
/* dont want initial AV_NOPTS_VALUE here */
this->context->reordered_opaque = 0;
#endif
+
+#ifdef XFF_AVCODEC_FRAME_PTS
+ this->context->time_base.num = 1;
+ this->context->time_base.den = 90000 << 8;
+#endif
}
#ifdef ENABLE_VAAPI
@@ -1398,7 +1424,7 @@ static void ff_setup_rgb2yuy2 (ff_video_decoder_t *this, int pix_fmt) {
#if defined(AV_PIX_FMT_YUV420P9) || defined(AV_PIX_FMT_YUV420P10)
static void ff_get_deep_color (uint8_t *src, int sstride, uint8_t *dest, int dstride,
int width, int height, uint8_t *tab) {
- uint16_t *p = (uint16_t *) src;
+ uint16_t *p = (uint16_t *)ASSUME_ALIGNED_2 (src, 2);
uint8_t *q = dest;
int spad = sstride / 2 - width;
int dpad = dstride - width;
@@ -1769,10 +1795,9 @@ static void ff_handle_header_buffer (ff_video_decoder_t *this, buf_element_t *bu
this->size += buf->size;
if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
- int codec_type;
+ uint32_t codec_type = buf->type & 0xFFFF0000;
lprintf ("header complete\n");
- codec_type = buf->type & 0xFFFF0000;
if (buf->decoder_flags & BUF_FLAG_STDHEADER) {
@@ -1804,22 +1829,24 @@ static void ff_handle_header_buffer (ff_video_decoder_t *this, buf_element_t *bu
#ifdef XFF_AVCODEC_SUB_ID
this->context->sub_id = _X_BE_32(&this->buf[30]);
#endif
- this->context->extradata_size = this->size - 26;
- if (this->context->extradata_size < 8) {
- this->context->extradata_size= 8;
- this->context->extradata = calloc(1, this->context->extradata_size +
- AV_INPUT_BUFFER_PADDING_SIZE);
- ((uint32_t *)this->context->extradata)[0] = 0;
- if (codec_type == BUF_VIDEO_RV10)
- ((uint32_t *)this->context->extradata)[1] = 0x10000000;
- else
- ((uint32_t *)this->context->extradata)[1] = 0x10003001;
+ if (this->size < 8 + 26) {
+ uint32_t *b = calloc (1, 8 + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (b) {
+ this->context->extradata_size = 8;
+ this->context->extradata = (uint8_t *)b;
+ b[0] = 0;
+ if (codec_type == BUF_VIDEO_RV10)
+ b[1] = 0x10000000;
+ else
+ b[1] = 0x10003001;
+ }
} else {
- this->context->extradata = malloc(this->context->extradata_size +
- AV_INPUT_BUFFER_PADDING_SIZE);
- memcpy(this->context->extradata, this->buf + 26,
- this->context->extradata_size);
- memset(this->context->extradata + this->context->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ this->context->extradata = malloc (this->size - 26 + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (this->context->extradata) {
+ this->context->extradata_size = this->size - 26;
+ memcpy (this->context->extradata, this->buf + 26, this->context->extradata_size);
+ memset (this->context->extradata + this->context->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ }
}
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
@@ -1896,33 +1923,44 @@ static void ff_handle_special_buffer (ff_video_decoder_t *this, buf_element_t *b
#endif
}
else if (buf->decoder_info[1] == BUF_SPECIAL_RV_CHUNK_TABLE) {
- /* o dear. Multiple decoding threads use individual contexts.
- av_decode_video2 () does only copy the _pointer_ to the offsets,
- not the offsets themselves. So we must not overwrite anything
- that another thread has not yet read. */
- int i, l, total;
-
- lprintf("BUF_SPECIAL_RV_CHUNK_TABLE\n");
- l = buf->decoder_info[2] + 1;
-
- total = l * this->class->thread_count;
- if (total < SLICE_OFFSET_SIZE)
- total = SLICE_OFFSET_SIZE;
- if (total > this->slice_offset_size) {
- this->slice_offset_table = realloc (this->slice_offset_table, total * sizeof (int));
- this->slice_offset_size = total;
- }
+ {
+#if XFF_AVCODEC_SLICE_TABLE == 1
+ /* o dear. Multiple decoding threads use individual contexts.
+ * av_decode_video2 () does only copy the _pointer_ to the offsets,
+ * not the offsets themselves. So we must not overwrite anything
+ * that another thread has not yet read. */
+ int i, l, total;
+
+ lprintf("BUF_SPECIAL_RV_CHUNK_TABLE\n");
+ l = buf->decoder_info[2] + 1;
+
+ total = l * this->class->thread_count;
+ if (total < SLICE_OFFSET_SIZE)
+ total = SLICE_OFFSET_SIZE;
+ if (total > this->slice_offset_size) {
+ this->slice_offset_table = realloc (this->slice_offset_table, total * sizeof (int));
+ this->slice_offset_size = total;
+ }
- if (this->slice_offset_pos + l > this->slice_offset_size)
- this->slice_offset_pos = 0;
- this->context->slice_offset = this->slice_offset_table + this->slice_offset_pos;
- this->context->slice_count = l;
+ if (this->slice_offset_pos + l > this->slice_offset_size)
+ this->slice_offset_pos = 0;
+ this->context->slice_offset = this->slice_offset_table + this->slice_offset_pos;
+ this->context->slice_count = l;
- lprintf ("slice_count=%d\n", l);
- for (i = 0; i < l; i++) {
- this->slice_offset_table[this->slice_offset_pos++] =
- ((uint32_t *)buf->decoder_info_ptr[2])[(2 * i) + 1];
- lprintf("slice_offset[%d]=%d\n", i, this->context->slice_offset[i]);
+ lprintf ("slice_count=%d\n", l);
+ for (i = 0; i < l; i++) {
+ this->slice_offset_table[this->slice_offset_pos++] =
+ ((uint32_t *)buf->decoder_info_ptr[2])[(2 * i) + 1];
+ lprintf("slice_offset[%d]=%d\n", i, this->context->slice_offset[i]);
+ }
+#elif XFF_AVCODEC_SLICE_TABLE == 2
+ /* (count-1):1, 1:4, (offs[0]):4, 1:4, (offs[1]:4, ... just in front of the frame bitstream.
+ * reverse engineered from ffmpeg/libavcodec/rv34.c. they seem to expect no
+ * external use of rv decoders, and did not document this. */
+ this->slice_table[0] = buf->decoder_info[2];
+ this->slice_num = this->slice_table[0] + 1;
+ memcpy (this->slice_table + 1, buf->decoder_info_ptr[2], 8 * this->slice_num);
+#endif
}
}
}
@@ -1957,7 +1995,26 @@ static int64_t ff_tag_pts (ff_video_decoder_t *this, int64_t pts) {
return (pts * 256) | this->pts_tag_pass;
}
-static int64_t ff_untag_pts (ff_video_decoder_t *this, int64_t pts) {
+static int64_t ff_untag_pts (ff_video_decoder_t *this, AVFrame *av_frame) {
+ int64_t pts;
+#if defined(XFF_AVCODEC_FRAME_PTS)
+ pts = (av_frame->pts != AV_NOPTS_VALUE) ? av_frame->pts : 0;
+# if defined(XFF_AVCODEC_REORDERED_OPAQUE)
+ /* paranoia !!! */
+ if (pts != av_frame->reordered_opaque) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ LOG_MODULE ": WARNING: frame pts %" PRId64 " != reordered_opaque %" PRId64 ".\n",
+ pts, av_frame->reordered_opaque);
+ pts = av_frame->reordered_opaque;
+ }
+ av_frame->reordered_opaque = 0;
+# endif
+#elif defined(XFF_AVCODEC_REORDERED_OPAQUE)
+ pts = av_frame->reordered_opaque;
+ av_frame->reordered_opaque = 0;
+#else
+ pts = this->tagged_pts;
+#endif
if ((uint8_t)(pts & 0xff) == this->pts_tag_pass) {
/* restore sign. */
return pts >> 8;
@@ -1969,6 +2026,7 @@ static int64_t ff_untag_pts (ff_video_decoder_t *this, int64_t pts) {
static int decode_video_wrapper (ff_video_decoder_t *this,
AVFrame *av_frame, int *err, void *buf, size_t buf_size) {
+ uint32_t tsize = 0;
int len;
#if ENABLE_VAAPI
@@ -1978,11 +2036,36 @@ static int decode_video_wrapper (ff_video_decoder_t *this,
}
#endif /* ENABLE_VAAPI */
+#if XFF_AVCODEC_SLICE_TABLE == 2
+ if ((this->slice_num > 0) && buf) {
+ uint32_t nsize;
+ tsize = 1 + this->slice_num * 8;
+ nsize = tsize + buf_size + AV_INPUT_BUFFER_PADDING_SIZE;
+ if (this->temp_size < nsize) {
+ nsize = nsize * 3 / 2;
+ free (this->temp_buf);
+ this->temp_buf = malloc (nsize);
+ if (!this->temp_buf)
+ nsize = 0;
+ this->temp_size = nsize;
+ nsize = tsize + buf_size + AV_INPUT_BUFFER_PADDING_SIZE;
+ }
+ if (this->temp_size >= nsize) {
+ memcpy (this->temp_buf, this->slice_table, tsize);
+ memcpy (this->temp_buf + tsize, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ buf = this->temp_buf;
+ }
+ this->slice_num = 0;
+ }
+#endif
+
#if XFF_VIDEO > 1
this->avpkt->data = buf;
- this->avpkt->size = buf_size;
+ this->avpkt->size = buf_size + tsize;
this->avpkt->flags = AV_PKT_FLAG_KEY;
-
+# ifdef XFF_AVCODEC_FRAME_PTS
+ this->avpkt->pts = this->tagged_pts;
+# endif
# if XFF_PALETTE == 2 || XFF_PALETTE == 3
if (buf && this->palette_changed) {
uint8_t *sd = av_packet_new_side_data (this->avpkt, AV_PKT_DATA_PALETTE, 256 * 4);
@@ -2092,9 +2175,14 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu
#endif
/* apply valid pts to first frame _starting_ thereafter only */
- if (this->pts && !this->context->reordered_opaque) {
- this->context->reordered_opaque =
- this->av_frame->reordered_opaque = ff_tag_pts (this, this->pts);
+ if (this->pts && !this->tagged_pts) {
+ this->tagged_pts = ff_tag_pts (this, this->pts);
+#ifdef XFF_AVCODEC_REORDERED_OPAQUE
+ this->context->reordered_opaque = this->av_frame->reordered_opaque = this->tagged_pts;
+#endif
+#ifdef XFF_AVCODEC_FRAME_PTS
+ this->av_frame->pts = this->tagged_pts;
+#endif
this->pts = 0;
}
@@ -2205,9 +2293,11 @@ static void ff_handle_mpeg12_buffer (ff_video_decoder_t *this, buf_element_t *bu
img->top_field_first = this->av_frame->top_field_first;
/* get back reordered pts */
- img->pts = ff_untag_pts (this, this->av_frame->reordered_opaque);
- this->av_frame->reordered_opaque = 0;
+ img->pts = ff_untag_pts (this, this->av_frame);
+ this->tagged_pts = 0;
+#ifdef XFF_AVCODEC_REORDERED_OPAQUE
this->context->reordered_opaque = 0;
+#endif
if (this->av_frame->repeat_pict)
img->duration = this->video_step * 3 / 2;
@@ -2328,9 +2418,14 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
}
if (this->size == 0) {
+ this->tagged_pts = ff_tag_pts (this, this->pts);
/* take over pts when we are about to buffer a frame */
- this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts);
- this->context->reordered_opaque = ff_tag_pts(this, this->pts);
+#ifdef XFF_AVCODEC_REORDERED_OPAQUE
+ this->av_frame->reordered_opaque = this->context->reordered_opaque = this->tagged_pts;
+#endif
+#ifdef XFF_AVCODEC_FRAME_PTS
+ this->av_frame->pts = this->tagged_pts;
+#endif
this->pts = 0;
}
@@ -2403,7 +2498,10 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
need_unref = 1;
#endif
/* reset consumed pts value */
- this->context->reordered_opaque = ff_tag_pts(this, 0);
+ this->tagged_pts = ff_tag_pts (this, 0);
+#ifdef XFF_AVCODEC_REORDERED_OPAQUE
+ this->context->reordered_opaque = this->tagged_pts;
+#endif
if (err) {
@@ -2434,13 +2532,16 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
this->size -= len;
if (this->size > 0) {
- ff_check_bufsize(this, this->size);
memmove (this->buf, &chunk_buf[offset], this->size);
chunk_buf = this->buf;
-
/* take over pts for next access unit */
- this->av_frame->reordered_opaque = ff_tag_pts(this, this->pts);
- this->context->reordered_opaque = ff_tag_pts(this, this->pts);
+ this->tagged_pts = ff_tag_pts (this, this->pts);
+#ifdef XFF_AVCODEC_REORDERED_OPAQUE
+ this->av_frame->reordered_opaque = this->context->reordered_opaque = this->tagged_pts;
+#endif
+#ifdef XFF_AVCODEC_FRAME_PTS
+ this->av_frame->pts = this->tagged_pts;
+#endif
this->pts = 0;
}
}
@@ -2557,11 +2658,10 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
ff_convert_frame(this, img, this->av_frame);
}
- img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque);
- this->av_frame->reordered_opaque = 0;
+ img->pts = ff_untag_pts(this, this->av_frame);
- /* workaround for weird 120fps streams */
- if( video_step_to_use == 750 ) {
+ /* workaround for weird 120fps streams, as well as some rv20 with frame duration 3pts. */
+ if (video_step_to_use <= 750) {
/* fallback to the VIDEO_PTS_MODE */
video_step_to_use = 0;
}
@@ -2598,8 +2698,7 @@ static void ff_handle_buffer (ff_video_decoder_t *this, buf_element_t *buf) {
this->output_format,
VO_BOTH_FIELDS|this->frame_flags);
/* set PTS to allow early syncing */
- img->pts = ff_untag_pts(this, this->av_frame->reordered_opaque);
- this->av_frame->reordered_opaque = 0;
+ img->pts = ff_untag_pts(this, this->av_frame);
img->duration = video_step_to_use;
@@ -2781,9 +2880,9 @@ static void ff_flush_internal (ff_video_decoder_t *this, int display) {
ff_convert_frame (this, img, this->av_frame2);
}
- img->pts = ff_untag_pts (this, this->av_frame2->reordered_opaque);
+ img->pts = ff_untag_pts (this, this->av_frame2);
- if (video_step_to_use == 750)
+ if (video_step_to_use <= 750)
video_step_to_use = 0;
img->duration = this->av_frame2->repeat_pict ? video_step_to_use * 3 / 2 : video_step_to_use;
img->progressive_frame = !this->av_frame2->interlaced_frame;
@@ -2887,6 +2986,9 @@ static void ff_reset (video_decoder_t *this_gen) {
mpeg_parser_reset(this->mpeg_parser);
/* this->pts_tag_pass = 0; */
+#if XFF_AVCODEC_SLICE_TABLE == 2
+ this->slice_num = 0;
+#endif
}
static void ff_dispose (video_decoder_t *this_gen) {
@@ -2899,10 +3001,15 @@ static void ff_dispose (video_decoder_t *this_gen) {
rgb2yuy2_free (this->rgb2yuy2);
if (this->decoder_ok) {
+ uint8_t *ed;
pthread_mutex_lock(&ffmpeg_lock);
- avcodec_close (this->context);
+ ed = this->context->extradata;
+ this->context->extradata = NULL;
+ this->context->extradata_size = 0;
+ XFF_FREE_CONTEXT (this->context);
pthread_mutex_unlock(&ffmpeg_lock);
+ _x_freep (&ed);
#ifdef ENABLE_DIRECT_RENDERING
ff_free_dr1_frames (this, 1);
@@ -2910,17 +3017,18 @@ static void ff_dispose (video_decoder_t *this_gen) {
this->stream->video_out->close(this->stream->video_out, this->stream);
this->decoder_ok = 0;
- }
-
- if (this->slice_offset_table)
- free (this->slice_offset_table);
-
- if (this->context) {
+ } else if (this->context) {
_x_freep (&this->context->extradata);
this->context->extradata_size = 0;
XFF_FREE_CONTEXT (this->context);
}
+#if XFF_AVCODEC_SLICE_TABLE == 1
+ free (this->slice_offset_table);
+#elif XFF_AVCODEC_SLICE_TABLE == 2
+ free (this->temp_buf);
+#endif
+
#if XFF_VIDEO > 1
XFF_PACKET_UNREF (this->avpkt);
#endif
@@ -3007,21 +3115,25 @@ static video_decoder_t *ff_video_open_plugin (video_decoder_class_t *class_gen,
this->decoder_ok = 0;
this->aspect_ratio = 0;
this->pts_tag_pass = 0;
-#ifdef HAVE_POSTPROC
+# ifdef HAVE_POSTPROC
this->pp_quality = 0;
this->our_context = NULL;
this->our_mode = NULL;
-#endif
+# endif
this->mpeg_parser = NULL;
this->set_stream_info = 0;
this->rgb2yuy2 = NULL;
-#ifdef ENABLE_VAAPI
+# ifdef ENABLE_VAAPI
this->accel = NULL;
this->accel_img = NULL;
-#endif
-#if XFF_VIDEO == 3
+# endif
+# if XFF_VIDEO == 3
this->flush_packet_sent = 0;
-#endif
+# endif
+# if XFF_AVCODEC_SLICE_TABLE == 2
+ this->temp_size = 0;
+ this->temp_buf = NULL;
+# endif
#endif
this->video_decoder.decode_data = ff_decode_data;
diff --git a/src/combined/ffmpeg/ffmpeg_compat.h b/src/combined/ffmpeg/ffmpeg_compat.h
index 803ace2..01096a7 100644
--- a/src/combined/ffmpeg/ffmpeg_compat.h
+++ b/src/combined/ffmpeg/ffmpeg_compat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2022 the xine project
+ * Copyright (C) 2000-2024 the xine project
*
* This file is part of xine, a unix video player.
*
@@ -54,9 +54,16 @@
#endif
/* reordered_opaque appeared in libavcodec 51.68.0 */
-#define XFF_AVCODEC_REORDERED_OPAQUE
-#if LIBAVCODEC_VERSION_INT < XFF_INT_VERSION(51,68,0)
-# undef XFF_AVCODEC_REORDERED_OPAQUE
+#if LIBAVCODEC_VERSION_INT >= XFF_INT_VERSION(51,68,0) && LIBAVCODEC_VERSION_INT < XFF_INT_VERSION(60,0,0)
+# define XFF_AVCODEC_REORDERED_OPAQUE
+#else
+# undef XFF_AVCODEC_REORDERED_OPAQUE
+#endif
+
+#if LIBAVCODEC_VERSION_INT >= XFF_INT_VERSION(58,33,100)
+# define XFF_AVCODEC_FRAME_PTS
+#else
+# undef XFF_AVCODEC_FRAME_PTS
#endif
/* colorspace and color_range were added before 52.29.0 */
@@ -132,6 +139,14 @@
# define XFF_PALETTE 3
#endif
+#if LIBAVCODEC_VERSION_INT < XFF_INT_VERSION(59,42,100)
+/* AVCodecContext.slice_{offset,count} */
+# define XFF_AVCODEC_SLICE_TABLE 1
+#else
+/* inline offset table before the frame. */
+# define XFF_AVCODEC_SLICE_TABLE 2
+#endif
+
#if LIBAVCODEC_VERSION_INT < XFF_INT_VERSION(59,0,100) /** << revise this */
# define XFF_VAAPI 1 /** << libavcodec/vaapi.h */
#else
@@ -210,9 +225,11 @@
#endif
#if LIBAVCODEC_VERSION_INT < XFF_INT_VERSION(55,63,100)
-# define XFF_FREE_CONTEXT(pp) do {av_free(pp); pp = NULL;} while (0)
+# define XFF_FREE_CONTEXT(pp) do {if (pp) avcodec_close (pp); av_free (pp); pp = NULL;} while (0)
+#elif LIBAVCODEC_VERSION_INT < XFF_INT_VERSION(58,33,100)
+# define XFF_FREE_CONTEXT(pp) do {if (pp) avcodec_close (pp); avcodec_free_context (&(pp));} while (0)
#else
-# define XFF_FREE_CONTEXT(pp) avcodec_free_context(&(pp))
+# define XFF_FREE_CONTEXT(pp) avcodec_free_context (&(pp))
#endif
#if LIBAVCODEC_VERSION_INT < XFF_INT_VERSION(54,59,100)
@@ -303,4 +320,3 @@
#endif /* defined(LIBAVCODEC_VERSION_INT) */
#endif /* XINE_AVCODEC_COMPAT_H */
-
diff --git a/src/dxr3/ffmpeg_encoder.c b/src/dxr3/ffmpeg_encoder.c
index 42dee3a..f45d60d 100644
--- a/src/dxr3/ffmpeg_encoder.c
+++ b/src/dxr3/ffmpeg_encoder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000-2022 the xine project
+ * Copyright (C) 2000-2024 the xine project
*
* This file is part of xine, a unix video player.
*
@@ -127,10 +127,8 @@ static int lavc_on_update_format(dxr3_driver_t *drv, dxr3_frame_t *frame)
unsigned char use_quantizer;
if (this->context) {
- avcodec_close(this->context);
- free(this->context);
+ XFF_FREE_CONTEXT (this->context);
free(this->picture);
- this->context = NULL;
this->picture = NULL;
}
@@ -344,10 +342,8 @@ static int lavc_on_unneeded(dxr3_driver_t *drv)
#if XFF_ENCVIDEO > 1
XFF_PACKET_UNREF (this->pkt);
#endif
- avcodec_close(this->context);
XFF_FREE_CONTEXT (this->context);
free(this->picture);
- this->context = NULL;
this->picture = NULL;
}
return 1;