mifi / lossless-cut

The swiss army knife of lossless video/audio editing
https://losslesscut.app/
GNU General Public License v2.0
28.15k stars 1.36k forks source link

Metadata preservation #1027

Open mifi opened 2 years ago

mifi commented 2 years ago

There have been many requests for preserving metadata, or some metadata getting lost when exporting. In my experience it seems to happen more often in older or more obscure codecs. Some related issues:

Although it seems there is no silver bullet, I will gather and summarise challenges and possible options here.

Default ffmpeg -i mp4 -c copy out.mp4

This seems to copy only some metadata, like some timestamps (both global and per-track).

ffmpeg -map_metadata X

Where X is the file input index. Typically -map_metadata 0 for mapping metadata from the first input to the output.

LosslessCut uses this by default when cutting (also for merge, but only if keep original metadata when merging is enabled).

ffmpeg -movflags use_metadata_tags

If you enable the Preserve all MP4/MOV metadata, it will use this flag. This flag will make ffmpeg copy additional tags (for MOV/MP4 only). However it will copy them into a different location than the source file. Example tag shown in exiftool:

See https://github.com/mifi/lossless-cut/issues/853#issuecomment-1036192500

Problems:

Copy tags with exiftool

See branch https://github.com/mifi/lossless-cut/tree/exiftool-integration

Although not yet implemented in LosslessCut (feb 2022), this command will copy some more useful metadata than -movflags use_metadata_tags, for example:

However, exiftool will also skip some tags that ffmpeg -movflags use_metadata_tags will copy:

Here is the command:

exiftool -tagsFromFile original.mp4 -all:all -overwrite_original with-exiftool.mp4

Exiftool can also give other benefits:

pgassmann commented 1 year ago

exiftool will also show the track name, which is displayed by many players.

Track names would be very useful to be displayed and preserved. There was an issue that was closed, but it was only a workaround for the user. Support for track name metadata would still be nice to have. https://github.com/mifi/lossless-cut/issues/1174

example mp4 with 3 audio tracks.

$ exiftool Downloads/720p-1640211643002.mp4 
ExifTool Version Number         : 12.40
File Name                       : 720p-1640211643002.mp4
Directory                       : Downloads
File Size                       : 7.0 MiB
File Modification Date/Time     : 2022:02:05 18:42:39+01:00
File Access Date/Time           : 2023:03:01 21:51:13+01:00
File Inode Change Date/Time     : 2022:02:05 18:42:52+01:00
File Permissions                : -rw-rw-r--
File Type                       : MP4
File Type Extension             : mp4
MIME Type                       : video/mp4
Major Brand                     : MP4 Base Media v1 [IS0 14496-12:2003]
Minor Version                   : 0.2.0
Compatible Brands               : isom, iso2, avc1, mp41
Media Data Size                 : 7294743
Media Data Offset               : 48
Movie Header Version            : 0
Create Date                     : 0000:00:00 00:00:00
Modify Date                     : 0000:00:00 00:00:00
Time Scale                      : 1000
Duration                        : 0:00:52
Preferred Rate                  : 1
Preferred Volume                : 100.00%
Preview Time                    : 0 s
Preview Duration                : 0 s
Poster Time                     : 0 s
Selection Time                  : 0 s
Selection Duration              : 0 s
Current Time                    : 0 s
Next Track ID                   : 5
Track Header Version            : 0
Track Create Date               : 0000:00:00 00:00:00
Track Modify Date               : 0000:00:00 00:00:00
Track ID                        : 1
Track Duration                  : 0:00:52
Track Layer                     : 0
Track Volume                    : 0.00%
Image Width                     : 960
Image Height                    : 720
Graphics Mode                   : srcCopy
Op Color                        : 0 0 0
Compressor ID                   : avc1
Source Image Width              : 960
Source Image Height             : 720
X Resolution                    : 72
Y Resolution                    : 72
Bit Depth                       : 24
Buffer Size                     : 0
Max Bitrate                     : 762394
Average Bitrate                 : 762394
Video Frame Rate                : 30
Track 2 Name                    : DE - Deutsch
Track 3 Name                    : FR - Français
Matrix Structure                : 1 0 0 0 1 0 0 0 1
Media Header Version            : 0
Media Create Date               : 0000:00:00 00:00:00
Media Modify Date               : 0000:00:00 00:00:00
Media Time Scale                : 48000
Media Duration                  : 0:00:51
Media Language Code             : fra
Handler Description             : SoundHandler
Balance                         : 0
Audio Format                    : mp4a
Audio Channels                  : 2
Audio Bits Per Sample           : 16
Audio Sample Rate               : 48000
Track 4 Name                    : FR - Français (translation only)
Handler Type                    : Metadata
Handler Vendor ID               : Apple
Encoder                         : Lavf58.76.100
Image Size                      : 960x720
Megapixels                      : 0.691
Avg Bitrate                     : 1.12 Mbps
Rotation                        : 0

ffprobe does not show the track names:

$ ffprobe -v error -show_streams  Downloads/720p-1640211643002.mp4  
[STREAM]
index=0
codec_name=h264
codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
profile=High
codec_type=video
codec_tag_string=avc1
codec_tag=0x31637661
width=960
height=720
coded_width=960
coded_height=720
closed_captions=0
has_b_frames=0
sample_aspect_ratio=N/A
display_aspect_ratio=N/A
pix_fmt=yuv420p
level=31
color_range=unknown
color_space=unknown
color_transfer=unknown
color_primaries=unknown
chroma_location=left
field_order=unknown
refs=1
is_avc=true
nal_length_size=4
id=N/A
r_frame_rate=30/1
avg_frame_rate=30/1
time_base=1/15360
start_pts=0
start_time=0.000000
duration_ts=802304
duration=52.233333
bit_rate=762394
max_bit_rate=N/A
bits_per_raw_sample=8
nb_frames=1567
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:language=und
TAG:handler_name=VideoHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]
[STREAM]
index=1
codec_name=aac
codec_long_name=AAC (Advanced Audio Coding)
profile=LC
codec_type=audio
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=fltp
sample_rate=48000
channels=2
channel_layout=stereo
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/48000
start_pts=0
start_time=0.000000
duration_ts=2459520
duration=51.240000
bit_rate=107821
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=2403
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:language=deu
TAG:handler_name=SoundHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]
[STREAM]
index=2
codec_name=aac
codec_long_name=AAC (Advanced Audio Coding)
profile=LC
codec_type=audio
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=fltp
sample_rate=48000
channels=2
channel_layout=stereo
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/48000
start_pts=0
start_time=0.000000
duration_ts=2459520
duration=51.240000
bit_rate=128088
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=2403
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=0
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:language=fra
TAG:handler_name=SoundHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]
[STREAM]
index=3
codec_name=aac
codec_long_name=AAC (Advanced Audio Coding)
profile=LC
codec_type=audio
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=fltp
sample_rate=48000
channels=2
channel_layout=stereo
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/48000
start_pts=0
start_time=0.000000
duration_ts=2459520
duration=51.240000
bit_rate=125825
max_bit_rate=N/A
bits_per_raw_sample=N/A
nb_frames=2403
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=0
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:language=fra
TAG:handler_name=SoundHandler
TAG:vendor_id=[0][0][0][0]
[/STREAM]
pgassmann commented 1 year ago

track title can be set with ffmpeg. -map 3:a -metadata:s:a:2 language=fra -metadata:s:a:2 title="FR Français"

but strangely, I also couldn't find a way to read it with ff tools

mifi commented 1 year ago

Anyone tried ffmpeg 6 yet? Maybe it's got improvements for this

FireEmerald commented 1 year ago

I made some research, and as i can tell you ffmpeg does by default set all handler names to SoundHandler.

To prevent this behaviour you have to tell ffmpeg to use a different sound handler name. The best is to use a empty name, which keeps the default/normal stream names intact -metadata:s:a:0 handler_name=''. In addition you also need to allow empty handler names by setting -empty_hdlr_name 1.

So in full: ffmpeg -i input.mkv -metadata:s:a:0 handler_name='' -empty_hdlr_name 1 out.mp4 (reference)

marfire commented 1 year ago

+1 for Exiftool.

I can confirm that the current process fails to transfer GPS data, and that Exiftool does so successfully. (Specifically, it preserves the GPSCoordinates field in UserData.)

If you do use Exiftool you'll probably want to add the -api largefilesupport=1 flag; otherwise it will fail on large files.