Concatenate four MP4 video files using FFmpeg - ffmpeg

I'm trying to concatenate four MP4 video files using FFmpeg. (latest version) Those four mp4 videos differ from general mp4 videos and have specific codecs, I play them in Windows Media Player with the help of K-Lite Mega Codec Pack 13.1.0.
Codec information of one file (all four files have same codecs) by MediaInfo:
General
Complete name : Testing - 1.mp4
Format : MPEG-4
Format profile : Base Media
Codec ID : isom (mp41/avc1)
File size : 59.4 MiB
Duration : 3 min 47 s
Overall bit rate mode : Variable
Overall bit rate : 2 196 kb/s
Writing application : vlc 2.2.4 stream output
Comment : QuickTime 6.0 or greater
Video
ID : 2
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High#L3
Format settings, CABAC : Yes
Format settings, ReFrames : 3 frames
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 3 min 47 s
Bit rate mode : Constant
Bit rate : 2 000 kb/s
Width : 720 pixels
Height : 576 pixels
Display aspect ratio : 5:4
Frame rate mode : Constant
Frame rate : 25.000 FPS
Standard : PAL
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.193
Stream size : 54.1 MiB (91%)
Audio
ID : 1
Format : AAC
Format/Info : Advanced Audio Codec
Format profile : LC
Codec ID : 40
Duration : 3 min 47 s
Source duration : 3 min 46 s
Bit rate mode : Variable
Bit rate : 192 kb/s
Maximum bit rate : 294 kb/s
Channel(s) : 2 channels
Channel positions : Front: L R
Sampling rate : 48.0 kHz
Frame rate : 46.875 FPS (1024 spf)
Compression mode : Lossy
Stream size : 5.13 MiB (9%)
Source stream size : 5.13 MiB (9%)
MP4 video files to be concatenated are "Testing - 1.mp4", "Testing - 2.mp4", "Testing - 3.mp4" and "Testing - 4.mp4".
I needed to use FFmpeg's Concatenation method to join those four MP4 files together into one MP4 file.
First attempt (using Concat Demuxer):
FFmpeg -f concat -safe 0 -i "F:\New Text Document.txt" -c copy E:\Testing.mp4
File concatenated into one MP4 file with several errors and warnings from FFmpeg.
Non-monotonous DTS in output stream
SPS NALU is missing or invalid, The resulting stream may not play
When playing above concatenated file with Windows Media Player, it gives error
Network is too busy to play file at original quality
but the file actually in a local hard drive.
Seek option not working (even in VLC media player) and Windows Explorer showing incorrect duration like 3h 54min, it should be 15min 05s.
Second attempt (using Concat Demuxer):
FFmpeg -f concat -safe 0 -i "F:\New Text Document.txt" -vcodec copy -acodec copy -crf 0 E:\Testing.mp4
Then file concatenates successfully and plays without any errors in Windows Media Player and VLC media player. The only problem here is file is very big and about 1.2GB in size because Constant Rate Factor is set to 0 to stop WMP network related error.
Note: Before concatenating (four source files) are playing fine in both players without any errors, but they are medium in size also. As MediaInfo shows, "Testing - 1.mp4" is 59.4 MB, instead huge sizes.
When I join those using EasiestSoft Video/Audio Joiner 4.7, file produces no errors while playing (I mean everything works fine as expect, but I need a command line tool like FFmpeg to batch process multiple videos), but in version 5.0, it seems to produce this network related error (this may be a program bug, I think it re-encodes even I check don't re-encode checkbox).
What can I do with FFmpeg to make this concatenated MP4 file smaller (around total size of four source files) and to make this able to play in both players without any network related issues or incorrect duration issues.

Related

FFMPEG : Extract Audio with exact Timing despite corrupted intermediate audio chunks

I have a full automated tool chain which first concatenate video chunks and adjusts user events to it.
This first step uses 3rd party software, I am not able to fix the problem there.
Later in the process I extract the audio from the video. Sometimes there are corrupted audio chunks inbetween. FFMPEG ignores the corrupted parts on extraction. So I got a mutch shorter audio (the linked events rely on the exact length of the org A/V). It wouldnt be a big issue if it would only happen at the end, I know how to pad it there, but at random poistions, I didnt find an option at the documentation doing the job.
The only solution that worked was (pretty dirty I know) to convert the video to another video container with removed video stream and rename the file to MP3/AAC. It was working at windows/Android but all Mac-Browser didnt play it.
The -filter_complex -discard looks promising but I didnt find any good example for the correct syntax.
I have found an Adobe Tool doing the job correctly so I hope there is a way to do with ffmpeg, too.
General
Complete name : C:\tmp123\video.mp4
Format : MPEG-4
Format profile : Base Media
Codec ID : isom (isom/iso2/avc1/mp41)
File size : 57.8 MiB
Duration : 6 min 51 s
Overall bit rate : 1 177 kb/s
Writing application : Lavf58.26.100
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : Baseline#L4
Format settings, CABAC : No
Format settings, RefFrames : 2 frames
Format settings, GOP : M=1, N=30
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 6 min 51 s
Bit rate : 1 003 kb/s
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 30.303 FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.016
Stream size : 49.2 MiB (85%)
Audio
ID : 2
Format : AAC
Format/Info : Advanced Audio Codec
Format profile : LC
Codec ID : 40
Duration : 6 min 51 s
Bit rate mode : Constant
Bit rate : 168 kb/s
Channel(s) : 2 channels
Channel positions : Front: L R
Sampling rate : 44.1 kHz
Frame rate : 43.066 FPS (1024 SPF)
Compression mode : Lossy
Stream size : 8.22 MiB (14%)
Default : Yes
Alternate group : 1
Thanks to Gyan I was able to fix the missing time by:
ffmpeg -i x.mp4 -y -vn -af aresample=async=1:first_pts=0:min_hard_comp=0.01 -acodec libfdk_aac x.aac
But I had a lot of audio clipping. Gyan suggest to use "async=3072" instead, but it was not working for me. The clipping was still present. I played around with the other values and min_hard_comp did the job. After setting it to 0.2 instead of 0.01 the clipping was gone. The generated audio does not fit 100% now, but it was redused from >1:30min to 30ms for a 6:51min video:
ffmpeg -i video.mp4 -y -vn -af aresample=async=1:first_pts=0:min_hard_comp=0.2 audioout1.mp3
Thx Gyan!

HLS MP4 Independent Segments

Long story short: Why HLS can't just play normal MP4 files together one after one? Why need to segment media file into .ts segments?
Details:
We've segmented MP4 file into mini MP4 segments (not TS), each one about 30 seconds for testing. It never plays in any HLS player, just loading all segment files then nothing happens.
Example MP4 segment Info:
Format : MPEG-4
Format profile : Base Media
Codec ID : isom
File size : 1.44 MiB
Duration : 32s 950ms
Overall bit rate : 366 Kbps
Writing application : Lavf56.25.101
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High#L4.1
Format settings, CABAC : Yes
Format settings, ReFrames : 6 frames
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 32s 950ms
Bit rate : 230 Kbps
Width : 426 pixels
Height : 240 pixels
Display aspect ratio : 16:9
Original display aspect rat : 16:9
Frame rate mode : Constant
Frame rate : 23.976 fps
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.094
Stream size : 925 KiB (63%)
Writing library : x264 core 142 r2495 6a301b6
Audio
ID : 2
Format : AAC
Format/Info : Advanced Audio Codec
Format profile : LC
Codec ID : 40
Duration : 32s 896ms
Bit rate mode : Constant
Bit rate : 129 Kbps
Channel(s) : 2 channels
Channel(s)_Original : 6 channels
Channel positions : Front: L C R, Side: L R, LFE
Sampling rate : 48.0 KHz
Compression mode : Lossy
Stream size : 517 KiB (35%)
The Master M3U8:
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-STREAM-INF:RESOLUTION=426x240,BANDWIDTH=370000,CODECS="avc1.640015,mp4a.40.2"
240p.m3u8
#EXT-X-STREAM-INF:RESOLUTION=640x360,BANDWIDTH=580000,CODECS="avc1.640015,mp4a.40.2"
360p.m3u8
#EXT-X-STREAM-INF:RESOLUTION=896x504,BANDWIDTH=900000,CODECS="avc1.640015,mp4a.40.2"
480p.m3u8
#EXT-X-STREAM-INF:RESOLUTION=1280x720,BANDWIDTH=1500000,CODECS="avc1.640015,mp4a.40.2"
720p.m3u8
240p.m3u8
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:34
#EXTINF:33.033033,
240p000.mp4
#EXTINF:33.533534,
240p001.mp4
#EXTINF:24.941608,
240p002.mp4
#EXTINF:28.611945,
240p003.mp4
#EXT-X-ENDLIST
When tested with HLS.js, gives this error:
Parsing Error:no demux matching with content found,cannot recover,
last media error recovery failed ...
Bitmovin Player: loads all segments of all variants and never plays any of them. just stop.
Tested on Chrome & Firefox On Windows, Safari on Mac, Android and iPad Browsers. Never works on any of them. Are we doing anything wrong?!
While transport stream segments are self-initializing, this is usually/often not the case for fMP4 segments. Therefore, you will need to add the initialization segment to the manifest file, which is needed to initialize the decoder. This can be done using the #EXT-X-MAP:URI tag as shown in the image of this blog post and in the example below:
#EXTM3U
#EXT-X-TARGETDURATION:4
#EXT-X-VERSION:7
#EXT-X-MEDIA-SEQUENCE:1
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MAP:URI="init.mp4"
#EXTINF:4.0
segment_0.m4s
#EXTINF:4.0
segment_1.m4s
...
#EXT-X-ENDLIST
I'm not sure about HLS.js, but this should work at least for the Bitmovin Player. If not I'd recommend to use Bitmovin's support.
Apple also provides a test page with fMP4 HLS (requires native HLS support in the browser, such in Safari), and Bitmovin has a demo page with fMP4 HLS avialable.
Why HLS can't just play normal MP4 files together one after one? Why need to segment media file into .ts segments?
MP4 files have a whole container that you don't really want or need. Each segment could in theory contain its own number of audio and video tracks, each with its own formats, frame rates, sample rates, etc. You don't need all of that, and you also need to stick video segments together cleanly. Therefore, you need something to encode segments cleanly in the first place.
FFMPEG has supported to generate fragment MP4 for HLS now. Take a look at https://trac.ffmpeg.org/ticket/5699

How can I play raw PCM file that I dumped from a codec?

I'm debugging an audio codec and need to test if the data is coming out of a codec properly. I have my code dumping the raw pcm stream into a file and now I want to try to play it in VLC or another OS X compatible player. I've heard that this is possible with VLC from the command line.
Short of writing some code to output your own header followed by your PCM data which will of course work - you could use Audacity to import the file as RAW data where you then specify :
Encoding : signed 16 bit PCM
Byte order : little endian (typically unless you're on powerpc or such)
Channels : 1 mono
start offset : 0
sample rate 44100 Hz (typical)
once imported Audacity will let you play the clip ... not as slick as some command line but easy to do none the less
this also works
ffplay -autoexit -f s16le myrawaudio.pcm
above assumes your raw audio is using bit depth of 16 bits which is typical of CD quality audio

Progressive or Interlace detection in ffmpeg

I am trying to write a decoder using ffmpeg and I want to display some information about the video stream. I can detect if a frame is progressive or interlaced (tff, bff) only after decoding the frame. i.e,
avcodec_decode_video2(pCodecCtx, pFrame, &gotFrame, &packet);
.....(assume we have a frame)
.....
// print information
printf("prog=%d inter=%d", !pFrame->interlaced_frame, pFrame->interlaced_frame);
This works well.
But I want to know if there is a way of detecting this from the AVFormatContext, AVCodecCtx or AVCodec structs or some other functions. This would be very useful, if for example I want to abort decoding if the file is interlaced. I don't want to decode a frame to get this piece of information.
I am trying to support MPEG2, H.264/AVC and HEVC codecs (either elementary streams or in MP4 container).
Sorry if this is a trivial question! Thank you very much!
ffmpeg can run in "idet" (interlace detection) mode and gives a summary of frame types it finds in the file. I use:
$ ffmpeg -filter:v idet -frames:v 360 -an -f rawvideo -y /dev/null -i HitchhikersGuide.mp4
(ffmpeg with the idet filter, sample 360 frames, blocking audio, using rawvideo format, send output to /dev/null, with input file HitchhikersGuide.mp4)
which produces a report that contains (in part):
[Parsed_idet_0 # 0x7fd5f3c121c0] Repeated Fields: Neither: 360 Top: 0 Bottom: 0
[Parsed_idet_0 # 0x7fd5f3c121c0] Single frame detection: TFF: 30 BFF: 0 Progressive: 330 Undetermined: 0
[Parsed_idet_0 # 0x7fd5f3c121c0] Multi frame detection: TFF: 22 BFF: 0 Progressive: 338 Undetermined: 0
In this case, 92% of the sampled frames are progressive, and 8% are interlaced, so most services would call this an interlaced video. TFF and BFF are Top-Field-First and Bottom-Field-First, respectively, and both indicate an interlaced frame.
Note that it is possible to encode interlaced video as progressive and progressive video as interlaced, and this method will report on the encoding only. If you want to know if the video was originally interlaced or progressive, then you will need to visually inspect it and look for a "combing" effect where alternate lines don't quite line up with each other (especially when the camera is moving fast), and if you see combing, then the original video is interlaced.
You could use ffprobe, which comes with ffmpeg. I don't know how you would use that from a library, but the command-line version can show the field_order.
Example command, with a few additional fields:
ffprobe -v quiet -select_streams v stream=codec_name,height,width,pix_fmt,field_order -of csv=p=0 "$Your_File"
Example output with different files:
prores,1920,1080,yuva444p12le,progressive
h264,1920,1080,yuv420p,unknown # some progressive files show unknown
prores,720,576,yuv422p10le,tb # tb = interlaced TFF interleaved
mpeg2video,1920,1080,yuv422p,tt # tt = interlaced TFF
dvvideo,720,576,yuv420p,bt # bt = interlaced BFF interleaved
An alternative would be Mediainfo :
mediainfo --Inform='Video;%ScanType%,%ScanOrder%,%ScanType_StoreMethod%' "$Your_File"
Example output with different files:
Progressive,,
Interlaced,TFF,
Interlaced,TFF,InterleavedFields
Interlaced,BFF,InterleavedFields
Mediainfo's source is available here, and on Github.

how to choose ffmpeg video mp3 audio version id?

I am having issues on ffmpeg encoded video files audio tracks. My encoded video contains ID for audio track as extracted from mediainfo:
I use CODEC_ID_MP3 in guess_format "mov" container for quicktime
Audio
ID : 2
Format : MPEG Audio
Format version : Version 2
Format profile : Layer 3
Codec ID : .mp3
Duration : 2s 916ms
Bit rate mode : Constant
Bit rate : 128 Kbps
Channel(s) : 1 channel
Sampling rate : 16.0 KHz
Compression mode : Lossy
Stream size : 45.3 KiB (2%)
Language : English
This is not recognized on a vanilla codecless installation of windows 7, only played by k-lite codec libmad
I have noticed, that another test file contains similar mp3 track and is played by media player OK:
Audio
ID : 2
Format : MPEG Audio
Format version : Version 1
Format profile : Layer 3
Mode : Joint stereo
Mode extension : MS Stereo
Codec ID : 6B
Duration : 1mn 9s
Bit rate mode : Constant
Bit rate : 320 Kbps
Channel(s) : 2 channels
Sampling rate : 44.1 KHz
Compression mode : Lossy
Stream size : 2.67 MiB (38%)
Writing library : LAME3.98
The difference I noticed is in Format version number and Codec ID, which is Version 2 from ffmpeg output - I couldnt locate this version setting in ffmpeg source files, so my question is - is there a way to influence this format version identificator and set the codec id as in above playable video?
I had to hack ffmpeg sources to change the codec ID to the one I needed
Version 1 only supports sample frequencies of 32 kHz, 44.1 kHz, and 48 kHz. For 16 kHz you need version 2, or you could resample to 32 kHz (-ar 32k) if you need version 1.
If necessary you can override the codec id with -atag id (and -strict unofficial if you are doing something contrary to the standard and want ffmpeg to not be bothered by that).

Resources