#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 , 11 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 , 11 years ago
Cc: | added |
---|
comment:3 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | open → closed |
comment:4 by , 11 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 , 11 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 , 11 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 , 11 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 , 11 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 , 11 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.
hangs here