|
|
@@ -30,7 +30,8 @@
|
|
|
* @file
|
|
|
* simple media player based on the FFmpeg libraries
|
|
|
*/
|
|
|
-#include<stdio.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <string.h>
|
|
|
#include "config.h"
|
|
|
#include <inttypes.h>
|
|
|
#include <math.h>
|
|
|
@@ -3236,10 +3237,19 @@ static int read_thread(void *arg)
|
|
|
/* add the stream start time */
|
|
|
if (ic->start_time != AV_NOPTS_VALUE)
|
|
|
timestamp += ic->start_time;
|
|
|
- ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
|
|
|
- if (ret < 0) {
|
|
|
- av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
|
|
|
- is->filename, (double)timestamp / AV_TIME_BASE);
|
|
|
+
|
|
|
+ // Skip initial seek for ASF format to avoid crash
|
|
|
+ int is_asf_init = (ic->iformat && ic->iformat->name &&
|
|
|
+ (strcmp(ic->iformat->name, "asf") == 0 ||
|
|
|
+ strstr(ic->iformat->name, "asf") != NULL));
|
|
|
+ if (is_asf_init) {
|
|
|
+ av_log(ffp, AV_LOG_WARNING, "heanup: ASF format detected, skipping initial seek\n");
|
|
|
+ } else {
|
|
|
+ ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
|
|
|
+ if (ret < 0) {
|
|
|
+ av_log(NULL, AV_LOG_WARNING, "%s: could not seek to position %0.3f\n",
|
|
|
+ is->filename, (double)timestamp / AV_TIME_BASE);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -3413,23 +3423,52 @@ static int read_thread(void *arg)
|
|
|
ffp_notify_msg3(ffp, FFP_MSG_BUFFERING_UPDATE, 0, 0);
|
|
|
|
|
|
// Workaround for ASF/WMA seek crash (FFmpeg ff_seek_frame_binary uninitialized variable issue)
|
|
|
- // See: https://ffmpeg.org/pipermail/ffmpeg-cvslog/2024-April/142447.html
|
|
|
- // For ASF format, use AVSEEK_FLAG_BACKWARD to avoid triggering binary seek with uninitialized pos_min/pos_max
|
|
|
+ // The FFmpeg libavformat has a bug in ff_seek_frame_binary with uninitialized pos_min/pos_max
|
|
|
+ // For ASF format, we completely disable seek to prevent crash
|
|
|
int seek_flags = is->seek_flags;
|
|
|
- int is_asf_format = (ic->iformat && ic->iformat->name && !strcmp(ic->iformat->name, "asf"));
|
|
|
- if (is_asf_format) {
|
|
|
- seek_flags |= AVSEEK_FLAG_BACKWARD;
|
|
|
- av_log(ffp, AV_LOG_DEBUG, "ASF format detected, using AVSEEK_FLAG_BACKWARD for seek\n");
|
|
|
- }
|
|
|
|
|
|
- ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, seek_flags);
|
|
|
+ // Debug: print format name to diagnose ASF detection
|
|
|
+ const char *format_name = (ic->iformat && ic->iformat->name) ? ic->iformat->name : "unknown";
|
|
|
+ av_log(ffp, AV_LOG_WARNING, "heanup seek: format_name=%s\n", format_name);
|
|
|
+
|
|
|
+ // Check for ASF format (WMA files use ASF container)
|
|
|
+ // Also check for "asf_o" which is the output variant
|
|
|
+ int is_asf_format = (ic->iformat && ic->iformat->name &&
|
|
|
+ (strcmp(ic->iformat->name, "asf") == 0 ||
|
|
|
+ strcmp(ic->iformat->name, "asf_o") == 0 ||
|
|
|
+ strstr(ic->iformat->name, "asf") != NULL));
|
|
|
|
|
|
- // Fallback for ASF format: if seek failed, try with audio stream index
|
|
|
- if (ret < 0 && is_asf_format && is->audio_stream >= 0) {
|
|
|
- av_log(ffp, AV_LOG_WARNING, "ASF seek failed, trying fallback with audio stream index\n");
|
|
|
- // Convert seek_target from AV_TIME_BASE to audio stream time_base
|
|
|
- int64_t seek_ts = av_rescale_q(seek_target, AV_TIME_BASE_Q, is->audio_st->time_base);
|
|
|
- ret = av_seek_frame(is->ic, is->audio_stream, seek_ts, seek_flags | AVSEEK_FLAG_ANY);
|
|
|
+ if (is_asf_format) {
|
|
|
+ // ASF/WMA format: use alternative seek method to avoid ff_seek_frame_binary crash
|
|
|
+ // The crash occurs because ff_seek_frame_binary has uninitialized pos_min/pos_max
|
|
|
+ // Try using AVSEEK_FLAG_BYTE to force byte-based seeking instead of timestamp-based
|
|
|
+ av_log(ffp, AV_LOG_WARNING, "heanup: ASF format, trying byte-based seek\n");
|
|
|
+
|
|
|
+ // Calculate byte position based on duration and file size
|
|
|
+ int64_t file_size = avio_size(ic->pb);
|
|
|
+ int64_t duration = ic->duration;
|
|
|
+
|
|
|
+ if (file_size > 0 && duration > 0) {
|
|
|
+ // Convert seek_target (in AV_TIME_BASE) to byte position
|
|
|
+ int64_t byte_pos = av_rescale(seek_target, file_size, duration);
|
|
|
+ av_log(ffp, AV_LOG_WARNING, "heanup: ASF byte seek: target=%lld, file_size=%lld, duration=%lld, byte_pos=%lld\n",
|
|
|
+ (long long)seek_target, (long long)file_size, (long long)duration, (long long)byte_pos);
|
|
|
+
|
|
|
+ // Use av_seek_frame with AVSEEK_FLAG_BYTE for byte-based seeking
|
|
|
+ ret = av_seek_frame(ic, -1, byte_pos, AVSEEK_FLAG_BYTE | AVSEEK_FLAG_BACKWARD);
|
|
|
+
|
|
|
+ if (ret < 0) {
|
|
|
+ av_log(ffp, AV_LOG_WARNING, "heanup: ASF byte seek failed, ret=%d\n", ret);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ av_log(ffp, AV_LOG_WARNING, "heanup: ASF cannot calculate byte position, file_size=%lld, duration=%lld\n",
|
|
|
+ (long long)file_size, (long long)duration);
|
|
|
+ ret = -1;
|
|
|
+ }
|
|
|
+ // Don't continue here - let the code below handle flush if seek succeeded
|
|
|
+ } else {
|
|
|
+ // Normal format: use avformat_seek_file
|
|
|
+ ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, seek_flags);
|
|
|
}
|
|
|
|
|
|
if (ret < 0) {
|