HydrogenAudio

Lossy Audio Compression => AAC => AAC - General => Topic started by: haigoyamakun on 2012-04-25 22:34:26

Title: ffmpeg: Copy tag from audio file to AAC pre-encoded file
Post by: haigoyamakun on 2012-04-25 22:34:26
I am using neroAacEnc to encode my music, using FFMPEG and pipe conections i connect the ffmpeg output to the neroaacenc input.
ffmpeg -i "somefile"."somecontainer" -acodec pcm_s16le -f wav - | neroaacenc "Some encode options" -ignorelength -if - -of "My new aac file.m4a"

The problem is: The output file does not keep the meta-tags of the input.

But, when ffmpeg decodes the audio to wav, it shows the meta-tags.

Here is my example.

Code: [Select]
C:\Users\lucman\Desktop\FFtoACC\bin>ffmpeg.exe -i flac.flac -acodec pcm_s16le -f
 wav - | neroaacenc -lc -br 80000 -ignorelength -if - -of aac.m4a
*************************************************************
*                                                          *
*  Nero AAC Encoder                                        *
*  Copyright 2009 Nero AG                                  *
*  All Rights Reserved Worldwide                            *
*                                                          *
*  Package build date: Feb 18 2010                          *
ffmpeg version N-38632-g4cda8aa*  Package version:    1.5.4.0
          *
 Copyright © 2000-2012 the FFmpeg developers
  built on Mar  8 2012 02:38:08 with gcc 4.5.0 20100414 (Fedora MinGW 4.5.0-1.fc
14)
  configuration: --prefix=/var/www/users/research/ffmpeg/snapshots/build --arch=
x86 --target-os=mingw32 --cross-prefix=i686-pc-mingw32- --cc='ccache i686-pc-min
gw32-gcc' --enable-w32threads --enable-memalign-hack --enable-runtime-cpudetect
--enable-cross-compile --enable-static --disable-shared --extra-libs='-lws2_32 -
lwinmm' --extra-cflags='--static -I/var/www/users/research/ffmpeg/snapshots/buil
d/include' --extra-ldflags='-static -L/var/www/users/research/ffmpeg/snapshots/b
uild/lib' --enable-bzlib --enable-zlib --enable-gpl --enable-version3 --enable-n
onfree --enable-libx264 --enable-libspeex --enable-libtheora --enable-libvorbis
--enable-libfaac --enable-libxvid --enable-libopencore-amrnb --enable-libopencor
e-amrwb --enable-libmp3lame --enable-libvpx --disable-decoder=libvpx
*                                                          *
  libavutil      51. 42.100 / 51. 42.100
*  See -help for a complete list of available parameters.  *
*                                                          *
  libavcodec    54. 10.100 / 54. 10.100
*************************************************************

  libavformat    54.  2.100 / 54.  2.100
  libavdevice    53.  4.100 / 53.  4.100
  libavfilter    2. 63.100 /  2. 63.100
  libswscale      2.  1.100 /  2.  1.100
  libswresample  0.  7.100 /  0.  7.100
  libpostproc    52.  0.100 / 52.  0.100
[flac @ 0x378fc0] max_analyze_duration 5000000 reached at 5015510
Input #0, flac, from 'flac.flac':
  Metadata:
    ARTIST          : the GazettE
    TITLE          : THE INVISIBLE WALL
    track          : 02
    ALBUM          : DIM
  Duration: 00:04:33.40, bitrate: 1038 kb/s
    Stream #0:0: Audio: flac, 44100 Hz, stereo, s16
Output #0, wav, to 'pipe:':
  Metadata:
    ARTIST          : the GazettE
    TITLE          : THE INVISIBLE WALL
    track          : 02
    ALBUM          : DIM
    encoder        : Lavf54.2.100
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16
, 1411 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (flac -> pcm_s16le)
Press [q] to stop, [?] for help
size=  47097kB time=00:04:33.40 bitrate=1411.2kbits/s
video:0kB audio:47097kB global headers:0kB muxing overhead 0.000095%


C:\Users\lucman\Desktop\FFtoACC\bin>
Can I copy tag information from one file to another using ffmpeg ??
Something like:
ffmpeg -y -i original-song.flac -copy-metadata my-preencoded-aac.m4a

Also i tried with "TAG.exe" but it can not tag AAC files.

I know i can do with Graphical programs, but i need a command-line program, because i'm codding a Bat file generator to Convert FFMPEG to NeroAAC.

Help please.
Title: ffmpeg: Copy tag from audio file to AAC pre-encoded file
Post by: Takla on 2012-04-26 07:46:24
I'd suggest not using ffmpeg for mapping metadata in this case as it has a couple of drawbacks:  ffmpeg can accept multiple input files and then, by using "-map" or "-map_metadata", either ignore or use (convert or copy) streams/metadata from each input file, writing the desired ones to output while discarding the others, but it can't add metadata into an pre-existing file as it always needs to write (or overwrite) to a file (or standard out).  Another limitation is that not all audio containers handle metadata and audio streams in the same way, so you'd need to know in advance which stream is which and perhaps if the metadata is read by ffmpeg before or after the audio, which is all too impractical.  It's easy enough to write a script which encodes from flac to a temporary m4a (piping ffmpeg wav to neroAacEnc), and then combines the original metadata with the new aac by writing them to yet another new file and then deletes the temp file.  But it's clumsy, relatively slow, and while it works with flac or mp3 sources it fails with ogg vorbis.  I didn't try with musepack, wavpack, wma or other source audio.

Fortunately there are cross platform command line tools which can read metadata from any kind of multimedia and present it in a standardized form which is easily manipulated.  I use mediainfo for this.

And a better approach for the tagging itself is to use neroAacTag because it can insert metadata into an existing file, so no need for temp files.

This bash script does what you're looking for, both encoding from any source and adding the tags to the output, but it's for GNU/Linux, Mac OS X, BSD etc. and not for Windows.  However all the same tools are available for Windows so it should be possible to adapt it for a Windows bat (sed can be used in place of the bash parameter substitutions).


Code: [Select]
#!/bin/bash

for i in "$@"; do

ARTIST=$(mediainfo "$i" |grep "Performer  " | awk -F ': ' '{print $2}')
TITLE=$(mediainfo "$i" |grep "Track name  " | awk -F ': ' '{print $2}')
ALBUM=$(mediainfo "$i" |grep "Album  " | awk -F ': ' '{print $2}')
GENRE=$(mediainfo "$i" |grep "Genre  " | awk -F ': ' '{print $2}')
DATE=$(mediainfo "$i" |grep "Recorded date  " | awk -F ': ' '{print $2}')
TRN=$(mediainfo "$i" |grep "Track name/Position" | awk -F ': ' '{print $2}')
COMPOSER=$(mediainfo "$i" |grep "Composer  " | awk -F ': ' '{print $2}')

ffmpeg -i "$i" -acodec pcm_s16le -f wav - |\
neroAacEnc -ignorelength -if - -of "${i%.*}".m4a && \

neroAacTag "${i%.*}".m4a -meta:artist="$ARTIST" -meta:title="$TITLE" \
-meta:album="$ALBUM" -meta:genre="$GENRE" -meta:year="$DATE" \
-meta:track="$TRN" -meta:composer="$COMPOSER"

done
It's easy to add other tags such as disc number, comment and so on.

Mediainfo:
http://mediainfo.sourceforge.net/en/Download/Windows (http://mediainfo.sourceforge.net/en/Download/Windows)
Windows binaries for sed, (g)awk, grep:
http://gnuwin32.sourceforge.net/packages.html (http://gnuwin32.sourceforge.net/packages.html)
Title: ffmpeg: Copy tag from audio file to AAC pre-encoded file
Post by: Takla on 2012-05-05 07:10:42
I had another look at this because mediainfo is just too slow for this task for anything except occasional use.  It is possible to get the metadata from ffmpeg because ffmpeg passes its messages to stderr, which makes it easy to dump into a text file and then grep for whichever fields are wanted.  This is massively quicker.

This is what I'm using now:

Code: [Select]
#!/bin/bash

function get_metadata ()
{
awk -F ": " '{$1="";$0=substr($0,2)}1'|\
sed 's/[;]/-/g;s/[/]/-/g;s/[<]/-/g;s/[>]/-/g;s/[:]/-/g;s/[|]/-/g'
}

for i in "$@"; do

TAG="${i%.*}"_tag

ffmpeg -i "$i" -acodec pcm_s16le -f wav - 2>"$TAG" |\
neroAacEnc -ignorelength -if - -of "${i%.*}".m4a;

ARTIST=$(grep -m 1 -i ARTIST "$TAG"|get_metadata)
TITLE=$(grep -m 1 -i TITLE "$TAG"|get_metadata)
ALBUM=$(grep -m 1 -i ALBUM "$TAG"|get_metadata)
GENRE=$(grep -m 1 -i GENRE "$TAG"|get_metadata)
TOT=$(grep -m 1 -i TRACKTOTAL "$TAG"|get_metadata)
DATE=$(grep -m 1 -i DATE "$TAG"|get_metadata)
TRN=$(grep -m 1 -i TRACK "$TAG"|get_metadata)
COMPOSER=$(grep -m 1 -i COMPOSER "$TAG"|get_metadata)
COMMENT=$(grep -m 1 -i COMMENT "$TAG"|get_metadata)
DISC=$(grep -m 1 -i DISC "$TAG"|get_metadata)

neroAacTag "${i%.*}".m4a -meta:artist="$ARTIST" -meta:title="$TITLE" \
-meta:album="$ALBUM" -meta:genre="$GENRE" -meta:year="$DATE" \
-meta:track="$TRN" -meta:totaltracks="$TOT" -meta:composer="$COMPOSER" \
-meta:comment="$COMMENT" -meta:disc="$DISC"
rm "$TAG"
done
exit 0
The worrying looking awk expression: it's so awk will print every column after the delimiter ": " because the number of columns and the characters or symbols they might contain is unknown (especially true of long comment fields, some of which can be 100s of words).

The sed command just strips out any characters such as : ; <> | which might otherwise get interpreted as a termination signal (I found neroAacTag will quit on encountering ";" in a comment field).

Anyway this works much better than the mediainfo method, so it is all possible with ffmpeg, neroAac and standard tools after all.