How to change metadata with ffmpeg/avconv without creating a new file?

Question:

I am writing a python script for producing audio and video podcasts. There are a bunch of recorded media files (audio and video) and text files containing the meta information.

Now I want to program a function which shall add the information from the meta data text files to all media files (the original and the converted ones). Because I have to handle many different file formats (wav, flac, mp3, mp4, ogg, ogv…) it would be great to have a tool which add meta data to arbitrary formats.

My Question:

How can I change the metadata of a file with ffmpeg/avconv without changing the audio or video of it and without creating a new file? Is there another commandline/python tool which would do the job for me?

What I tried so far:

I thought ffmpeg/avconv could be such a tool, because it can handle nearly all media formats. I hoped, that if I set -i input_file and the output_file to the same file, ffmpeg/avconv will be smart enough to leave the file unchanged. Then I could set -metadata key=value and just the metadata will be changed.

But I noticed, that if I type avconv -i test.mp3 -metadata title='Test title' test.mp3 the audio test.mp3 will be reconverted in another bitrate.

So I thought to use -c copy to copy all video and audio information. Unfortunately also this does not work:

:~$ du -h test.wav # test.wav is 303 MB big
303M    test.wav

:~$ avconv -i test.wav -c copy -metadata title='Test title' test.wav
avconv version 0.8.3-4:0.8.3-0ubuntu0.12.04.1, Copyright (c) 2000-2012 the
Libav    developers
built on Jun 12 2012 16:37:58 with gcc 4.6.3
[wav @ 0x846b260] max_analyze_duration reached
Input #0, wav, from 'test.wav':
Duration: 00:29:58.74, bitrate: 1411 kb/s
    Stream #0.0: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s
File 'test.wav' already exists. Overwrite ? [y/N] y
Output #0, wav, to 'test.wav':
Metadata:
    title           : Test title
    encoder         : Lavf53.21.0
    Stream #0.0: Audio: pcm_s16le, 44100 Hz, 2 channels, 1411 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Press ctrl-c to stop encoding
size=     896kB time=5.20 bitrate=1411.3kbits/s    
video:0kB audio:896kB global headers:0kB muxing overhead 0.005014%

:~$ du -h test.wav # file size of test.wav changed dramatically
900K    test.wav

You see, that I cannot use -c copy if input_file and output_file are the same. Of course I could produce a temporarily file:

:-$ avconv -i test.wav -c copy -metadata title='Test title' test_temp.mp3
:-$ mv test_tmp.mp3 test.mp3

But this solution would create (temporarily) a new file on the filesystem and is therefore not preferable.

Asked By: Stephan Kulla

||

Answers:

You can do this with FFmpeg like so:

ffmpeg -i input.avi -metadata key=value -codec copy output.avi

Example:

$ du -h test.mov 
 27M    test.mov
$ ffprobe -loglevel quiet -show_format out.mov | grep title    # nothing found
$ ffmpeg -loglevel quiet -i test.mov -codec copy -metadata title="My title" out.mov
$ du -h out.mov
 27M    out.mov
$ ffprobe -loglevel quiet -show_format out.mov | grep title
TAG_title=My title

See the documentation for -metadata and on stream copying for more information.

Note also that not all formats allow setting arbitrary metadata, for, e.g., Quicktime doing -metadata title="my title" does what you’d expect, but -metadata foo=bux does nothing.

Answered By: blahdiblah

I asked on the mailing list of avconv and got the following answer:

„No, it’s not possible [to change the metadata without creating a new file], neither libavformat API nor avconv design allows for in-place editing of files.“

Answered By: Stephan Kulla

Since changing the metadata will change the length of the file, and I expect the metadata is near the beginning of the file, the audio and video would start at a different offset from the beginning of the file. So you cannot alter the metadata without first creating a temporary file, then renaming files after.

If the new metadata were exactly the same size, and you know where the metadata was located in the container (file) you might be able to use a hex editor of some kind to simply replace characters. Good luck with that.

Also. you might be able to put shorter data in place directly if you paded with nulls, but this might be problematic for some players.

Answered By: Cool Javelin

With ffmpeg, you will always have to copy to a new file. But it has the advantage that it can handle many different formats.

The alternative, without copying the whole file, depends on the format. For many, there are tools wich will allow you to edit metadata "in-place".

  • exiftool for many formats
  • metaflac for FLAC
  • MP4Box for .mp4
  • eyeD3, mid3v2, etc. for MP3
  • etc.

So you would really have to check for what works for you for each specific file format.

Answered By: mivk

You can also make something like this that deletes the file on success and rename the output

ffmpeg -i default.mp4 -metadata title="my title" -codec copy output.mp4 && mv output.mp4 default.mp4
Answered By: Jeremy

If like me you have a lot of files with long name (and spaces) to rename, you can save file name and title as variable before and execute always same ffmpeg command after:

input="My default video.mp4" && title="My title video"
ffmpeg -i "$input" -metadata title="$title" -codec copy output.mp4 && mv output.mp4 "$input"

If you have ffmpeg < v.3.2, you can prevent Codec for stream 0 does not use global headers but container format requires global headers warning by adding -flags +global_header flag:

ffmpeg -i "$input" -metadata title="$title" -codec copy -flags +global_header output.mp4 && mv output.mp4 "$input"

Note: I also have to change rights to retrieve same file as before (sudo may be needed):

chmod 774 "$input" && chown admin:users "$input"
Answered By: Klemart3D

This depends on the physical location of the metadata in the file. If the data is at the head of the file, you might be able to ‘slice’ that section off and edit the data then ‘splice’ the sections back together. This would only be useful if you had a lot of files to do in a batch. If only one is to be edited, use one of the two-copy methods.

Answered By: Jim Julian