1

What I want to happen: the equivalent of this: split -n 4 output.mp4, which generates 4 files. Only the first file is "valid mp4" that you can play. The other 3 files rely on the previous file.

A similar request can be seen here: https://lists.ffmpeg.org/pipermail/ffmpeg-user/2013-May/015090.html

Why I want this to happen: running FFMPEG in the browser, which means 1) file size limit, 2) I don't have the Linux command split to help me out, just FFMPEG. If I can get FFMPEG to output files of X MB each, I can iteratively delete files as soon as I've read them.

EDIT: as a commenter asked, yes it is possible to run several ffmpeg commands if necessary.

The right solution is not using segments. The following example command generates several 4 valid mp4 files. That's not exactly what I want. ffmpeg -i ../flv.flv -segment_time 5 -f segment -t 20 %d.mp4

This other solution also does not work (it's the same output as previous incorrect solution):

ffmpeg -i ../flv.flv -ss 00:00:00 -t 5 1.mp4

ffmpeg -i ../flv.flv -ss 00:00:05 -t 5 2.mp4

Friendly Genius
  • 305
  • 3
  • 12

2 Answers2

1

Alright I've solved my problem, although my question was not worded as precisely as I should've.

The root problem I was trying to solve is fragmenting the conversion of some random file type (say flv) to multiple mp4 files on the fly, such that the browser can call sourceBuffer.appendBuffer() on each file.

The correct answer, as it turns out, was indeed to use segment. The reason why the segment command in my question was incorrect was that it didn't pass the correct movflags for segmenting.

I had failed with this command: ffmpeg -i ../flv.flv -movflags frag_keyframe+empty_moov+default_base_moof -segment_time 5 -f segment -t 20 %d.mp4

The correct command is this: ffmpeg -i ../flv.flv -g 1 -segment_format_options movflags=+frag_keyframe+empty_moov+default_base_moof -segment_time 5 -f segment -t 20 %d.mp4

What is the key difference? The -segment_format_options flag. I guess the failed command totally ignored the -movflags option. Must pass in the movflags to -segment_format_options

One additional note: The -g 1 is actually important if you want to appendBuffer as sourceBuffer.mode = 'segment' instead of as 'sequence'. The reason you'd want 'segment' instead of 'sequence' is so that you can append buffers out of order (say a buffer at 30 minute mark straight away). This is useful for a feature such as seeking.

My takeaway from this struggle is that FFmpeg is one heck of a beast. Just knowing the ins and outs of FFmpeg would be very impressive and possibly very valuable. I should write a blog post about this one day! I'll post a link to the write up later.

Friendly Genius
  • 305
  • 3
  • 12
  • 1
    1) With segment, all files are valid MP4s and independent, Your Q indicates you only wanted the first file to be valid; it also omits mention of movflags in your segmenting attempt. 2) g 1 is very inefficient - files will be much larger for same quality. For quick enough seek, KF at half-second intervals is usually acceptable. – Gyan Nov 15 '20 at 07:42
  • re 1) ya, I admit my question should've stated my original problem better re 2) what is a better alternative to `-g 1` then? – Friendly Genius Nov 15 '20 at 08:41
  • Use `-force_key_frames expr:gte(t,n_forced*0.5)` for keyframes every 0.5 seconds. You may have to escape some of those characters depending on shell. – Gyan Nov 15 '20 at 09:13
  • I just tested and that worked like a charm! Thank you and I'm sorry for the rabbit hole we both went down earlier. Are you looking for some Stackoverflow points? You can write a different answer including your force_key_frames and I'll accept it. Make it sound good. – Friendly Genius Nov 15 '20 at 11:37
  • force_key_frames has already been documented elsewhere, like https://stackoverflow.com/q/43563208/ . My answer, as written, addresses your question, as currently stated, and this use-case is fairly unique, so more useful than making it another answer about GOP size. – Gyan Nov 15 '20 at 12:40
0

Using ffmpeg to split files is unusual but it can be done.

Basic template is

ffmpeg -f data -start START -end END -i subfile:/path/to/file -map 0 -c copy -f data segX.mp4

START and END are byte offsets. The byte at offset START will be the first byte in the output. The byte at offset END will be the first byte not in the output, so output ends with END-1. For next command, start offset is END and end offset is END+X where X is segment size.

Check for file size of output. When it's zero, you know the entire file has been split.

Gyan
  • 85,394
  • 9
  • 169
  • 201
  • Not that unusual. Here is another guy trying to do the same thing I'm doing: https://lists.ffmpeg.org/pipermail/ffmpeg-user/2013-May/015090.html – Friendly Genius Nov 14 '20 at 19:37
  • Does your solution only work for mp4 as input? What about while converting from an flv to mp4 file? – Friendly Genius Nov 14 '20 at 19:44
  • All the command does is split the input which is treated as raw data so input format doesn't matter. There's no conversion. – Gyan Nov 15 '20 at 04:00
  • ya that's what I thought when I saw `-f data`. This solution doesn't quite work for my use case. – Friendly Genius Nov 15 '20 at 04:33
  • What's the issue? It emulates `split` – Gyan Nov 15 '20 at 04:35
  • it doesn't split the output of converting a file like flv. – Friendly Genius Nov 15 '20 at 04:47
  • What does that mean? The `split` command is content-agnostic. All it does is partition input bytes into separate files. That's what this does. – Gyan Nov 15 '20 at 05:00
  • that doesn't make sense because the input is flv while the output is mp4. – Friendly Genius Nov 15 '20 at 05:55
  • If your input is FLV, then remux it first: `ffmpeg -i in.flv -c copy -movflags +faststart out.mp4` and then run the split commands on the output. – Gyan Nov 15 '20 at 06:37
  • unable to in my case. Example: FLV is 1 GB file. Conversion would take too long. I'd like to start playing the fragmented mp4 file immediately. It's fine, I've solved it another way...I'll post an answer – Friendly Genius Nov 15 '20 at 06:44