Opened 6 years ago

Last modified 6 years ago

#7281 new defect

fMP4 Single File Generation is excruciatingly slow

Reported by: Ronak Patel Owned by:
Priority: normal Component: avformat
Version: git-master Keywords: hls
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:

Using a 20 hour audio mp4 file, try to make an fMP4 file (either HLS or DASH/HLS mode), using -codec copy to ensure there's no encoding being done. ffmpeg will take several hours to fragment the file.

Compare this to Apple's HLS Tools: https://developer.apple.com/streaming/ which is able to fragment in roughly 1 minute.

How to reproduce:

% ffmpeg -i "$FILE.mp4" -codec copy -hls_time 0.975238095238095 -hls_segment_type fmp4 -hls_flags single_file+append_list+split_by_time -hls_playlist_type vod "$FILE.m3u8"

ffmpeg version

ffmpeg version git-2018-06-23-b86c575 Copyright (c) 2000-2018 the FFmpeg developers
  built with Apple LLVM version 9.1.0 (clang-902.0.39.2)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/HEAD-b86c575 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-gpl --enable-libfdk-aac --enable-libmp3lame --enable-libopus --enable-librubberband --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxvid --enable-opencl --enable-videotoolbox --disable-lzma --enable-nonfree
  libavutil      56. 18.102 / 56. 18.102
  libavcodec     58. 20.103 / 58. 20.103
  libavformat    58. 17.101 / 58. 17.101
  libavdevice    58.  4.101 / 58.  4.101
  libavfilter     7. 25.100 /  7. 25.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  2.100 /  5.  2.100
  libswresample   3.  2.100 /  3.  2.100
  libpostproc    55.  2.100 / 55.  2.100
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...

Change History (11)

comment:1 by Carl Eugen Hoyos, 6 years ago

Keywords: fMP4 removed
Priority: importantnormal

This is currently at least missing the command line you tested together with the complete, uncut console output but I believe using time will make this ticket easier to understand.

Didn’t you already analyse the issue?

comment:2 by Ronak Patel, 6 years ago

I analyzed the issue, but I'm filing this ticket so I can get help from the community to fix this issue. The fix for this issue looks involved with many use cases to test for once we fix the problem.

Just to summarize, I'm including the research I've done on this issue so far:

Hey Carl,

So I dug into this more today and I have root caused what's exactly happening here.

The problematic code is this: https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/hlsenc.c#L1368
This is where the filename is set and the next line actually opens the file.

The logic for this hls_window method is the following:

  1. Make a new temporary file.
  2. Write out a new HLS manifest header.
  3. Loop through all available segments and write out all of the entries for them.
  4. Close the temporary file when finished.
  5. Rename the temporary file to the target file name.
  6. Rinse and repeat for every single fragment.

Therefore, if you can imagine a 153 hour audio file, we write out a totally new HLS manifest 550800 times (153 * 60 * 60 assuming a 1s fragment duration) that gets progressively larger as each fragment is generated.

This is a classic O(N2) algorithm implementation, instead of:

  1. Creating the destination file up front & write the manifest header.
  2. Append the new segment to the file.
  3. If this is the last segment, write out EXT-X-ENDLIST.

There's no looping involved, nor the need to make temporary files.

FYI that I've noticed the same sort of pattern being applied to MPEG DASH: https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/dashenc.c#L786

To implement something like this, looks like we'd have to significantly re-engineer the code. Do you have any pointers on how to go about doing this? Or, would you be able to help do this?

Thanks for all your help,

Ronak

Last edited 6 years ago by Carl Eugen Hoyos (previous) (diff)

comment:3 by Ronak Patel, 6 years ago

I've made the changes I've suggested and they work fine for the VOD and EVENT use cases. I haven't been able to test my changes with encryption, or true live HTTP Streams. Is there an easy way to set up for this test?

comment:4 by Carl Eugen Hoyos, 6 years ago

Have you already sent your patch - made with git format-patch - as an attachment to the development mailing list for review?

comment:5 by Ronak Patel, 6 years ago

Not yet, I'd like to make sure that my fix is actually working in every use case, before I put it up for review. Also, I've noticed that the segmentation is not consistent through the file when I choose mpegts containers. I would like to have this fixed, since it means my fix won't work perfectly with mpegts based streams.

Version 0, edited 6 years ago by Ronak Patel (next)

in reply to:  5 comment:6 by Carl Eugen Hoyos, 6 years ago

Replying to ronak2121:

Not yet, I'd like to make sure that my fix is actually working in every use case, before I put it up for review.

This is often a (very) bad strategy.

comment:7 by Ronak Patel, 6 years ago

I've just sent my first patch to ffmpeg for this issue. I'll send a second patch to fix issues in dashenc.c.

comment:8 by Carl Eugen Hoyos, 6 years ago

Was this fixed today?
Please remember to mention the ticket in the commit message.

comment:9 by Ronak Patel, 6 years ago

I'm going to submit another patch that fixes this same problem for dashenc.c. I should have the patch up today or tomorrow at the latest.

comment:10 by Lastique, 6 years ago

The rename part in the current behavior is essential because it makes manifest updates atomic. This is important for live streams.

comment:11 by Ronak Patel, 6 years ago

Then you should only do it for live streams. You are adding unnecessary overhead for VOD streams that don’t care about this.

Note: See TracTickets for help on using tickets.