#3531 closed defect (fixed)
ffmpeg hangs converting a possibly broken avi file
| Reported by: | hxuanyu | Owned by: | |
|---|---|---|---|
| Priority: | important | Component: | undetermined |
| Version: | git-master | Keywords: | avi deadlock regression |
| Cc: | donmoir@comcast.net | Blocked By: | |
| Blocking: | Reproduced by developer: | yes | |
| Analyzed by developer: | no |
Description
Hi,
Here is an avi file, for which latest ffplay couldn't play at all (not even one frame). Nor can ffprobe show any information.
MediaInfo can show info of this file.
WMP plays a few frames then reports it can't play this type of file.
VLC doesn't play any frames but is responsive.
Quicktime crashes.
Ffprobe and ffplay just hang once command is executed.
Change History (9)
comment:1 by , 12 years ago
| Keywords: | avi deadlock regression added |
|---|---|
| Priority: | normal → important |
| Reproduced by developer: | set |
| Status: | new → open |
| Summary: | ffplay can't play any video frame → ffmpeg hangs converting a possibly broken avi file |
| Version: | unspecified → git-master |
comment:2 by , 12 years ago
| Cc: | added |
|---|
comment:3 by , 12 years ago
| Resolution: | → fixed |
|---|---|
| Status: | open → closed |
comment:4 by , 12 years ago
Could someone double check to see if this is actually fixed. For me, it seems to be hung up in read_braindead_odml_indx (avidec.c) which keeps building indexes recursively until it dies.
Comment out where read_braindead_odml_indx is called and it works.
comment:5 by , 12 years ago
Hangs up when trying to build index for me.
static int avi_read_header(AVFormatContext *s)
{
...
case MKTAG('i', 'n', 'd', 'x'):
i = avio_tell(pb);
if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) &&
avi->use_odml &&
read_braindead_odml_indx(s, 0) < 0 &&
(s->error_recognition & AV_EF_EXPLODE))
goto fail;
avio_seek(pb, i + size, SEEK_SET);
break;
...
}
This allows it to at least play. Seeking not so good :)
case MKTAG('i', 'n', 'd', 'x'):
i = avio_tell(pb);
/*
if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) &&
avi->use_odml &&
read_braindead_odml_indx(s, 0) < 0 &&
(s->error_recognition & AV_EF_EXPLODE))
goto fail;
*/
avio_seek(pb, i + size, SEEK_SET);
break;
I am not trying to convert, just playback.
comment:6 by , 12 years ago
The index is big, it needs time to be read
on ssd its less than 10sec it might be more on a slow hdd
comment:7 by , 12 years ago
It seems to settle somewhere around 11,200,000 entries. I stopped it at that anyway. If you take the size of the file which is 186,042,456 bytes divided by 11,200,000 then thats about an entry for every 16 bytes.
While it's doing this, it's eating the CPU big time plus memory overhead. It's just not going to work for most people. The only way out is to trap interrupt_callback and just fail, but wish there was some other solution.
I am testing this on my slower machine and there I can't let it complete since this computer will overheat and shutdown. Have not tested it on fast machine but whatever the case I can't let this happen.
comment:8 by , 12 years ago
I changed read_braindead_odml_indx so it only adds an index entry if it's a keyframe. You end up with only 2 index entries. This allowed to open in about 1 to 3 seconds on my slower machine. Could not open on this machine before without it dying due to overheating. When adding index entries in read_braindead_odml_indx, it adds keyframe or non-keyframe entries and it's the non-keyframe entries that are a problem since there are many millions of them. Seems memory is thrashing to disk etc., as it attempts to build the index since it becomes a large consumer of memory and CPU.
With the above change it worked normally but I don't know what other ramifications it might have.
comment:9 by , 12 years ago
I ended up changing the following. I tested several avi files and it seems to be ok. With the change, lake.avi will open in about 2 seconds with about 350 index entries. Need someone to verify. Also, it could be last_pos should only be set if an index is added. Does new ticket need to be opened?
static int read_braindead_odml_indx(AVFormatContext *s, int frame_num)
{
AVIContext *avi = s->priv_data;
AVIOContext *pb = s->pb;
int longs_pre_entry = avio_rl16(pb);
int index_sub_type = avio_r8(pb);
int index_type = avio_r8(pb);
int entries_in_use = avio_rl32(pb);
int chunk_id = avio_rl32(pb);
int64_t base = avio_rl64(pb);
int stream_id = ((chunk_id & 0xFF) - '0') * 10 +
((chunk_id >> 8 & 0xFF) - '0');
AVStream *st;
AVIStream *ast;
int i;
int64_t last_pos = -1;
int64_t filesize = avi->fsize;
av_dlog(s,
"longs_pre_entry:%d index_type:%d entries_in_use:%d "
"chunk_id:%X base:%16"PRIX64"\n",
longs_pre_entry,
index_type,
entries_in_use,
chunk_id,
base);
if (stream_id >= s->nb_streams || stream_id < 0)
return AVERROR_INVALIDDATA;
st = s->streams[stream_id];
ast = st->priv_data;
if (index_sub_type)
return AVERROR_INVALIDDATA;
avio_rl32(pb);
if (index_type && longs_pre_entry != 2)
return AVERROR_INVALIDDATA;
if (index_type > 1)
return AVERROR_INVALIDDATA;
if (filesize > 0 && base >= filesize) {
av_log(s, AV_LOG_ERROR, "ODML index invalid\n");
if (base >> 32 == (base & 0xFFFFFFFF) &&
(base & 0xFFFFFFFF) < filesize &&
filesize <= 0xFFFFFFFF)
base &= 0xFFFFFFFF;
else
return AVERROR_INVALIDDATA;
}
for (i = 0; i < entries_in_use; i++) {
if (index_type) {
int64_t pos = avio_rl32(pb) + base - 8;
int len = avio_rl32(pb);
int key = len >= 0;
len &= 0x7FFFFFFF;
#ifdef DEBUG_SEEK
av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len);
#endif
if (url_feof(pb))
return AVERROR_INVALIDDATA;
if (last_pos == pos || pos == base - 8)
avi->non_interleaved = 1;
- if (last_pos != pos && (len || !ast->sample_size))
+ if (len && last_pos != pos)
av_add_index_entry(st, pos, ast->cum_len, len, 0,
key ? AVINDEX_KEYFRAME : 0);
ast->cum_len += get_duration(ast, len);
last_pos = pos;
} else {
int64_t offset, pos;
int duration;
offset = avio_rl64(pb);
avio_rl32(pb); /* size */
duration = avio_rl32(pb);
if (url_feof(pb))
return AVERROR_INVALIDDATA;
pos = avio_tell(pb);
if (avi->odml_depth > MAX_ODML_DEPTH) {
av_log(s, AV_LOG_ERROR, "Too deeply nested ODML indexes\n");
return AVERROR_INVALIDDATA;
}
if (avio_seek(pb, offset + 8, SEEK_SET) < 0)
return -1;
avi->odml_depth++;
read_braindead_odml_indx(s, frame_num);
avi->odml_depth--;
frame_num += duration;
if (avio_seek(pb, pos, SEEK_SET) < 0) {
av_log(s, AV_LOG_ERROR, "Failed to restore position after reading index\n");
return -1;
}
}
}
avi->index_loaded = 2;
return 0;
}



(Works fine here with ffplay.)
Regression since 574dcb5b - possibly related to tickets #1796 and #3208.
(gdb) r -i Lake.avi -qscale 2 out.avi Starting program: ffmpeg_g -i Lake.avi -qscale 2 out.avi [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". ffmpeg version N-62122-g16509d3 Copyright (c) 2000-2014 the FFmpeg developers built on Apr 4 2014 09:59:31 with gcc 4.7 (SUSE Linux) configuration: --enable-gpl libavutil 52. 73.100 / 52. 73.100 libavcodec 55. 56.107 / 55. 56.107 libavformat 55. 36.101 / 55. 36.101 libavdevice 55. 11.100 / 55. 11.100 libavfilter 4. 3.100 / 4. 3.100 libswscale 2. 6.100 / 2. 6.100 libswresample 0. 18.100 / 0. 18.100 libpostproc 52. 3.100 / 52. 3.100 Input #0, avi, from 'Lake.avi': Duration: 00:00:11.51, start: 0.000000, bitrate: 129297 kb/s Stream #0:0: Video: h264 (High) (H264 / 0x34363248), yuv420p, 720x480 [SAR 1:1 DAR 3:2], 29.97 tbr, 1000k tbn, 2000k tbc Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, s16p, 128 kb/s Please use -q:a or -q:v, -qscale is ambiguous Output #0, avi, to 'out.avi': Metadata: ISFT : Lavf55.36.101 Stream #0:0: Video: mpeg4 (FMP4 / 0x34504D46), yuv420p, 720x480 [SAR 1:1 DAR 3:2], q=2-31, 200 kb/s, 29.97 tbn, 29.97 tbc Stream #0:1: Audio: ac3 ([0] [0][0] / 0x2000), 44100 Hz, stereo, fltp, 192 kb/s Stream mapping: Stream #0:0 -> #0:0 (h264 -> mpeg4) Stream #0:1 -> #0:1 (mp3 -> ac3) Press [q] to stop, [?] for helphangs here
Program received signal SIGINT, Interrupt. ff_index_search_timestamp (flags=0, wanted_timestamp=<optimized out>, nb_entries=11511001, entries=0x7fffd477d010) at libavformat/utils.c:1822 1822 while (m >= 0 && m < nb_entries && (gdb) bt #0 ff_index_search_timestamp (flags=0, wanted_timestamp=<optimized out>, nb_entries=11511001, entries=0x7fffd477d010) at libavformat/utils.c:1822 #1 av_index_search_timestamp (st=st@entry=0x1924140, wanted_timestamp=<optimized out>, flags=flags@entry=0) at libavformat/utils.c:1833 #2 0x000000000050fa50 in avi_read_packet (s=0x1923900, pkt=<optimized out>) at libavformat/avidec.c:1371 #3 0x00000000005e7666 in ff_read_packet (s=s@entry=0x1923900, pkt=pkt@entry=0x7fffffffd630) at libavformat/utils.c:767 #4 0x00000000005e9c30 in read_frame_internal (s=0x1923900, pkt=0x7fffffffda10) at libavformat/utils.c:1436 #5 0x00000000005eab06 in av_read_frame (s=0x1923900, pkt=pkt@entry=0x7fffffffda10) at libavformat/utils.c:1557 #6 0x0000000000480d85 in get_input_packet (pkt=0x7fffffffda10, f=0x1b1ff20) at ffmpeg.c:3184 #7 process_input (file_index=0) at ffmpeg.c:3221 #8 0x0000000000468db0 in transcode_step () at ffmpeg.c:3507 #9 transcode () at ffmpeg.c:3559 #10 main (argc=<optimized out>, argv=<optimized out>) at ffmpeg.c:3739 (gdb) disass $pc-32,$pc+32 Dump of assembler code from 0x5eae80 to 0x5eaec0: 0x00000000005eae80 <av_index_search_timestamp+160>: lea (%r9,%rdx,8),%rdx 0x00000000005eae84 <av_index_search_timestamp+164>: jmp 0x5eae9d <av_index_search_timestamp+189> 0x00000000005eae86 <av_index_search_timestamp+166>: nopw %cs:0x0(%rax,%rax,1) 0x00000000005eae90 <av_index_search_timestamp+176>: movzbl 0x10(%rdx),%ecx 0x00000000005eae94 <av_index_search_timestamp+180>: add $0x18,%rdx 0x00000000005eae98 <av_index_search_timestamp+184>: and $0x1,%ecx 0x00000000005eae9b <av_index_search_timestamp+187>: jne 0x5eaf00 <av_index_search_timestamp+288> 0x00000000005eae9d <av_index_search_timestamp+189>: add $0x1,%eax => 0x00000000005eaea0 <av_index_search_timestamp+192>: cmp %eax,%r10d 0x00000000005eaea3 <av_index_search_timestamp+195>: jg 0x5eae90 <av_index_search_timestamp+176> 0x00000000005eaea5 <av_index_search_timestamp+197>: nopl (%rax) 0x00000000005eaea8 <av_index_search_timestamp+200>: cmp %eax,%r10d 0x00000000005eaeab <av_index_search_timestamp+203>: mov $0xffffffff,%edx 0x00000000005eaeb0 <av_index_search_timestamp+208>: cmove %edx,%eax 0x00000000005eaeb3 <av_index_search_timestamp+211>: repz retq 0x00000000005eaeb5 <av_index_search_timestamp+213>: nopl (%rax) 0x00000000005eaeb8 <av_index_search_timestamp+216>: add %r10d,%r8d 0x00000000005eaebb <av_index_search_timestamp+219>: jmpq 0x5eae18 <av_index_search_timestamp+56> End of assembler dump. (gdb) info register rax 0x3f7876 4159606 rbx 0x19249c0 26364352 rcx 0x0 0 rdx 0x7fffda6b1b20 140736857840416 rsi 0xf554e8 16078056 rdi 0x1eaa9d 2009757 rbp 0x0 0x0 rsp 0x7fffffffd428 0x7fffffffd428 r8 0xa38df 669919 r9 0x7fffd477d010 140736758009872 r10 0xafa4d9 11511001 r11 0x0 0 r12 0x1924130 26362160 r13 0x1924e80 26365568 r14 0x1924130 26362160 r15 0x7fffffffd630 140737488344624 rip 0x5eaea0 0x5eaea0 <av_index_search_timestamp+192> eflags 0x202 [ IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0