Skip to main content
Topic: Possible FFMPEG bug with libopus (Read 2502 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Possible FFMPEG bug with libopus

ffmpeg version:  version N-48905-ge45e6005ce-static https://johnvansickle.com/ffmpeg/

ffmpeg command:

Code: [Select]
 ffmpeg -nostdin -i "$1" -map 0:a -map 0:v -b:v 1800k \
  -minrate 900k -maxrate 2610k -tile-columns 2 -g 240 -threads 8 \
  -quality good -crf 31 -c:v libvpx-vp9 -c:a libopus \
  -pass 1 -speed 4 -b:a 256k  -y "$1".1920x1080-24-30fps.webm && \

 ffmpeg -nostdin -i "$1" -map 0:a -map 0:v -b:v 1800k \
  -minrate 900k -maxrate 2610k -tile-columns 4 -g 240 -threads 8 \
  -quality good -crf 31 -c:v libvpx-vp9 -c:a libopus \
  -pass 2 -speed 4 -b:a 256k -y "$1".1920x1080-24-30fps.webm

Trying to transcode my files to VP9 using google recommended settings and all audio tracks to opus. However this will fail with this error:

Code: [Select]
[libopus @ 0x65381c0] Invalid channel layout 5.1(side) for specified mapping family -1.

You can fix it with this:

Code: [Select]
-af "channelmap=channel_layout=5.1"

However, this causes issues if the input file has a stereo audio track.

Code: [Select]
Stream mapping:
  Stream #0:1 -> #0:0 (ac3 (native) -> opus (libopus))
  Stream #0:2 -> #0:1 (dts (dca) -> opus (libopus))
  Stream #0:3 -> #0:2 (dts (dca) -> opus (libopus))
  Stream #0:0 -> #0:3 (vc1 (native) -> vp9 (libvpx-vp9))
[Parsed_channelmap_0 @ 0x6c3e980] input channel #2 not available from input layout 'stereo'
[Parsed_channelmap_0 @ 0x6c3e980] input channel #3 not available from input layout 'stereo'

However, if I remove the 5.1 channel layout it goes back to the first error.  This also means is somewhat impossible to encode a file if it has 5.1 and 2.0 audio tracks.

I was almost opening a ffmpeg ticket, but want to ask here first If i'm not being dumb and doing something wrong.

I just want to batch process my files, and I can't micromanage my input files like that. FFMPEG should just keep the number of audio channels by default right? So I don't know why I'm even having to bother with this.

It also seems ffmpeg is broken with regards to LFE optimization and channel coupling. How can I be sure that I'm creating the highest quality possible opus audio, and how can I check after encoding if they have those optimizations or not?

Re: Possible FFMPEG bug with libopus

Reply #1
Please give some proof about last claim about LFE optimization and channel coupling.

Re: Possible FFMPEG bug with libopus

Reply #2
Code: [Select]
[libopus @ 0x65381c0] Invalid channel layout 5.1(side) for specified mapping family -1.
This is because ffmpeg's libopusenc only accepts L+R+C+LF+BL+BR (using back channels) for 5.1ch surround, while your input is  L+R+C+LF+SL+SR (using side channels).
Indeed it's not very convenient, and is less forgiving compared to Vorbis and FLAC.

Quote
It also seems ffmpeg is broken with regards to LFE optimization and channel coupling. How can I be sure that I'm creating the highest quality possible opus audio, and how can I check after encoding if they have those optimizations or not?
As far as I can see, you have to explicitly specify "-mapping_family 1" to let ffmpeg use newer surround api of libopus, and it seems intentional:
https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libopusenc.c#L336

Re: Possible FFMPEG bug with libopus

Reply #3
Mapping_family 1 should be safe to use on stereo files as well, but you could use this topic as a springboard for requesting that mapping not be used if the files don't require it, like mono or stereo files.

This information may also be useful to others who are looking for a solution to the same problem.

Re: Possible FFMPEG bug with libopus

Reply #4
It does seem to be a bug: https://trac.ffmpeg.org/ticket/5718

As far as I can see, you have to explicitly specify "-mapping_family 1" to let ffmpeg use newer surround api of libopus, and it seems intentional:
https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libopusenc.c#L336

What ffmpeg documentation says is different:

Code: [Select]
Set channel mapping family to be used by the encoder. The default value of -1 uses mapping family 0 for mono and stereo inputs, and mapping family 1 otherwise. The default also disables the surround masking and LFE bandwidth optimzations in libopus, and requires that the input contains 8 channels or fewer.

I can't really read that code, but I believe you...their documentation could be wrong too. Sad to see ffmpeg opus in such a poor state :/

Because of this issue I've been unable to easily batch process my files to Opus and can't use tools like https://github.com/slhck/ffmpeg-normalize too.

I'm not a linux expert or developer.

I just want to convert thousands of file to opus, which should be something simple, without requiring a 200 line script to workaround ffmpeg bugs, having to control input, build complex ffmpeg commands to handle files with 2.0 and 5.1 audio/etc.

Can someone recommend a solution to my issue, that doesn't require me to be a ffmpeg/linux expert?

I wonder how youtube is doing this to all videos uploaded... why they wouldn't push a fix to ffmpeg... I bet they have a patched ffmpeg version they paid developers to create and are refusing to share it upstream... or they made someone write a super complex script to handle any input people upload....

Re: Possible FFMPEG bug with libopus

Reply #5
Even better, you should probably know that FFmpeg's own Opus decoder is known to be buggy with low bitrate input material, and therefore it is advisable to use the libopus decoder instead.

Re: Possible FFMPEG bug with libopus

Reply #6
I hear you have sent patch to fix that bug.

Re: Possible FFMPEG bug with libopus

Reply #7
Here is the workflow I came up for someone trying to batch process files to opus:

Code: [Select]
#!/bin/bash

# Normalize audio files to pcm

ffmpeg-normalize -vn -sn -cn "$1"

# Extrac desired audios to feed opusenc

ffmpeg -nostdin -i "$1" -map 0:m:language:eng -vn -acodec copy "${1%.mkv}".en.wav

# Encode them with opusenc

opusenc "${1%.mkv}".en.wav "${1%.mkv}".en.mkv


This way you first convert input to pcm_s16le, then you extract the desired audio language from output, assuming ffmpeg will copy the highest quality (channel) audio track of that language by default to a .wav file.

Then we encode the .wav file with opusenc. To keep it simple, we will just go with the defaults, because otherwise we would have to find out if the file is 5.1 or 2.0 to set bitrate manually. It seems to use 96 kb/s for 2.0 and 320 kb/s for 5.1 input.

if you want to encode the video to vp9, which makes sense with opus audio you could use this ffmpeg command adapted from google (1080p 30 fps)

Code: [Select]
ffmpeg -y -nostdin -i "$1" -an -b:v 1800k \
  -minrate 900k -maxrate 2610k -tile-columns 2 -g 240 -threads 8 -quality good -crf 31 -c:v libvpx-vp9 \
  -pass 1 -speed 4 tos-1920x1080-24-30fps.webm && \

ffmpeg -y -nostdin -i "$1" -an -b:v 1800k \
  -minrate 900k -maxrate 2610k -tile-columns 4 -g 240 -threads 8 -quality good -crf 31 -c:v libvpx-vp9 \
  -pass 2 -speed 4 tos-1920x1080-24-30fps.webm

This should convert only the video and subtitles if SRT. For some reason after removing the audio options, it breaks the reporting of time and speed in the 1 pass.

Then just merge the files after you are done with mkvmerge.

It's not efficient, but it works. I accept criticism and help too :P

I have a few questions too:

1. If I wanted to just convert only all the audio tracks of a input to pcm_s16le with mkv, keeping language metadata with ffmpeg how you'd do it?

Code: [Select]
ffmpeg -nostdin -i *mkv -vn -sn -map 0:a -acodec pcm_s16le output.mkv

For some reason this give some strange error:

Code: [Select]
[matroska,webm @ 0x70483c0] Element at 0xc7288e2c ending at 0xc72a6569 exceeds containing master element ending at 0xc7288e25

2. When converting to opus after doing loudness normalization is it lost or kept?

3. Assuming lossy input, is pcm_s16le lossless? Doing lossy input > pcm_s16le > opus is the same as doing lossy input > opus?


Re: Possible FFMPEG bug with libopus

Reply #9
What ffmpeg documentation says is different:

Code: [Select]
Set channel mapping family to be used by the encoder. The default value of -1 uses mapping family 0 for mono and stereo inputs, and mapping family 1 otherwise. The default also disables the surround masking and LFE bandwidth optimzations in libopus, and requires that the input contains 8 channels or fewer.

I can't really read that code, but I believe you...their documentation could be wrong too. Sad to see ffmpeg opus in such a poor state :/

No it's not different, the doc is correct.
  • Unless explicitly specified by -mapping_family, the default value of mapping_family option is -1.
  • When the value of mapping_family option is -1, opus_multistream_encoder_create() is used. The mapping_family field in OpusHead will be set to either 0 or 1, depending on the number of channels.
  • Otherwise, opus_multistream_surround_encoder_create() is used. The mapping_family field in OpusHead will be set to the specified value.

So, if you want surround encoder to be used, you need -mapping_family option. This is what I've said.

Re: Possible FFMPEG bug with libopus

Reply #10
It does seem to be a bug: https://trac.ffmpeg.org/ticket/5718
Nice find.

In libopus_check_vorbis_layout(), they just check the layout against the predefined static array named ff_vorbis_channel_layouts[].
It's simple, but as a result, only one layout for each number of channels is allowed:
https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libopusenc.c#L182

What they really need to do is to adapt a logic used in Vorbis and FLAC:
https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libvorbisenc.c#L131
https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/flacenc.c#L435

It's surprising that they've left this for 3 years, without even anybody mentioning inconsistency with Vorbis and FLAC (both of which share the same channel mapping as Opus)

Re: Possible FFMPEG bug with libopus

Reply #11
Thanks for the information :)

I now understand it better.

Since there is probably no fix coming for ffmpeg for now, I'll use the workflow described in my last reply to batch process files.

I hope this helps anyone that struggled like me to convert stuff to opus. I assume opusenc will just handle any channel layout you throw at it without issues right?

Re: Possible FFMPEG bug with libopus

Reply #12
Code: [Select]
-speed 4

Why??


 
SimplePortal 1.0.0 RC1 © 2008-2019