Transcoding MPEG-4 video to MPEG-H in order to reduce the size in half without losing perceivable quality is relatively easy with a 2-pass approach presented within FFMPEG documentation. The scheme that I've been using is to extract the bit_rate
value from the original MPEG-4 video using ffprobe
and then multiply that value by 4 / 10
. Thus, that new lower value would be specified by -b:v
and become the bit_rate
value of the resulting MPEG-H video. This worked quite well for most of the videos, not only with MPEG-4, but also with QuickTime and Audio Video Interleave (AVI).
However, now I stumbled across the issue with transcoding MPEG-1 video in such a way. Somehow, the resulting MPEG-H video is unacceptably larger than the original video by a hefty margin. A 200MB original video could easily result in 1.5GB transcoded video. When I looked for a reason for such ridiculous behavior, I found out that somehow the advertised bit_rate
value in MPEG-1 videos is also ridiculously high. Take the following two videos as an example (output from ffprobe
):
164MB 15MB
[STREAM] [STREAM]
index=0 index=1
codec_name=mpeg4 codec_name=mpeg1video
codec_long_name=MPEG-4 part 2 codec_long_name=MPEG-1 video
profile=Simple Profile profile=unknown
codec_type=video codec_type=video
codec_time_base=1/24 codec_time_base=1/25
codec_tag_string=mp4v codec_tag_string=[0][0][0][0]
codec_tag=0x7634706d codec_tag=0x0000
width=960 width=640
height=540 height=480
coded_width=960 coded_width=0
coded_height=540 coded_height=0
closed_captions=0 closed_captions=0
has_b_frames=0 has_b_frames=1
sample_aspect_ratio=1:1 sample_aspect_ratio=1:1
display_aspect_ratio=16:9 display_aspect_ratio=4:3
pix_fmt=yuv420p pix_fmt=yuv420p
level=1 level=-99
color_range=unknown color_range=tv
color_space=unknown color_space=unknown
color_transfer=unknown color_transfer=unknown
color_primaries=unknown color_primaries=unknown
chroma_location=left chroma_location=center
field_order=unknown field_order=unknown
timecode=N/A timecode=N/A
refs=1 refs=1
quarter_sample=false
divx_packed=false
id=N/A id=0x1e0
r_frame_rate=24/1 r_frame_rate=25/1
avg_frame_rate=24/1 avg_frame_rate=25/1
time_base=1/24 time_base=1/90000
start_pts=0 start_pts=9900
start_time=0.000000 start_time=0.110000
duration_ts=7451 duration_ts=3690000
duration=310.458333 duration=41.000000
bit_rate=4096346 bit_rate=104857200
max_bit_rate=9000000 max_bit_rate=N/A
bits_per_raw_sample=N/A bits_per_raw_sample=N/A
nb_frames=7451 nb_frames=N/A
nb_read_frames=N/A nb_read_frames=N/A
nb_read_packets=N/A nb_read_packets=N/A
DISPOSITION:default=1 DISPOSITION:default=0
DISPOSITION:dub=0 DISPOSITION:dub=0
DISPOSITION:original=0 DISPOSITION:original=0
DISPOSITION:comment=0 DISPOSITION:comment=0
DISPOSITION:lyrics=0 DISPOSITION:lyrics=0
DISPOSITION:karaoke=0 DISPOSITION:karaoke=0
DISPOSITION:forced=0 DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0 DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0 DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0 DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0 DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0 DISPOSITION:timed_thumbnails=0
[/STREAM] [/STREAM]
Clearly, the MPEG-4 video is like 11 times larger than MPEG-1, but at the same time MPEG-4 video has like 100000000 less bit rate advertised than MPEG-1. And since my algorithm does not consider anything else to compute the final bit rate, that is how the problem facilitates itself. Now I tried to look into some other field values in search for a hint that maybe something else should also be included into the equation, and my suspicions lie in the following ones:
time_base=1/24 time_base=1/90000
start_pts=0 start_pts=9900
start_time=0.000000 start_time=0.110000
duration_ts=7451 duration_ts=3690000
duration=310.458333 duration=41.000000
I'm not an expert with MPEG and the documentation isn't very informative on these in a way that I could derive some math out of it or otherwise somehow connect them to resolving my issue in a meaningful way. Could anybody experienced please assist here?
By searching the web, I figured out that bit rate value of 104857200
is some kind of indication of an issue, perhaps metadata related. One can search for the ffmpeg
and 104857 kb/s
keywords. Hence, this value simply cannot be taken seriously as already presented in my question. Luckily enough, the FORMAT
section also has bit_rate
of the file as per:
ffprobe -v error -show_entries format=bit_rate -of default=noprint_wrappers=1:nokey=1 <video-file>
In case of MPEG-1, this bit_rate
value corresponds exactly to the required bit rate of the video stream only (yes, it's important that audio stream is not included there). For example, the subject MPEG-1 has a value of 2914159
.
As a result, the algorithm for transcoding videos to MPEG-H now simply tests whether the return value of
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 <video-file>
is equal to mpeg1video
, and if it is, it branches off to retrieve bit_rate
from FORMAT
section rather than video STREAM
section.