3

At this point, I've transcoded dozens if not hundreds of files with FFMPEG, but I have one particular file that's giving me trouble and I can't figure out why.

For testing, I'm using a 10 second snippet of my original file (I'd upload it as part of this question if that was a feature here). This source test file looks like this:

Input #0, matroska,webm, from 'Trimmed.mkv':
HD.MA.5.1-RARBG
    ENCODER         : Lavf61.9.106
  Duration: 00:00:10.26, start: 0.000000, bitrate: 33873 kb/s
  Chapters:
    [[excluded for relevance]]
  Stream #0:0(eng): Video: h264 (High), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn
    Metadata:
      DURATION        : 00:00:10.260000000
  Stream #0:1(eng): Audio: dts (dca) (DTS-HD MA), 48000 Hz, 5.1(side), s32p (24 bit) (default)
    Metadata:
      DURATION        : 00:00:10.005000000
  Stream #0:2(eng): Audio: dts (dca) (DTS), 48000 Hz, 5.1(side), fltp, 1536 kb/s
    Metadata:
      DURATION        : 00:00:10.005000000
  Stream #0:3(eng): Audio: ac3, 48000 Hz, stereo, fltp, 192 kb/s
    Metadata:
      DURATION        : 00:00:10.016000000

I can open the above file in VLC player and confirm that each of the audio streams (and the video stream) play correctly. However, many players are not as supportive as VLC (don't have as many codecs baked in), and I need to support more than that. In my case, I need to support the built-in Windows Media Player, which (at least on my computer) can't play either of the first two audio streams (can't play 0:1 dts (dca) (DTS-HD MA) or 0:2 dts (dca) (DTS)). (Technically, I need to support Chrome playback, but both applications seem to have the same issue here, and Windows Media Player is easier for me to test.)

I've been able to work around this in all previous cases by duplicating the stream I want and transcoding the copy as AAC. To that end, I used the following command:

ffmpeg -i Trimmed.mkv -map 0:v -map 0:a -map 0:a:0 -c copy -c:a:3 aac Converted.mkv

I copy over the video stream and all the audio streams, and then map the first audio stream a second time. I set the codec for all streams to 'copy', but then override that final audio stream to use AAC instead.

The output from running that command is as follows:

[aost#0:4 @ 000001f6a555fb40] Multiple -codec/-c/-acodec/-vcodec/-scodec/-dcodec options specified for stream 4, only the last option '-codec:a:3 aac' will be used.
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
  Stream #0:2 -> #0:2 (copy)
  Stream #0:3 -> #0:3 (copy)
  Stream #0:1 -> #0:4 (dts (dca) -> aac (native))
Press [q] to stop, [?] for help
[aac @ 000001f6a591c240] Using a PCE to encode channel layout "5.1(side)"
Output #0, matroska, to 'Converted.mkv':
HD.MA.5.1-RARBG
    encoder         : Lavf61.9.106
  Chapters:
    [[excluded for relevance]]
  Stream #0:0(eng): Video: h264 (High) (H264 / 0x34363248), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], q=2-31, 23.98 fps, 23.98 tbr, 1k tbn
    Metadata:
      DURATION        : 00:00:10.260000000
  Stream #0:1(eng): Audio: dts (DTS-HD MA) ([1] [0][0] / 0x2001), 48000 Hz, 5.1(side), s32p (24 bit) (default)
    Metadata:
      DURATION        : 00:00:10.005000000
  Stream #0:2(eng): Audio: dts (DTS) ([1] [0][0] / 0x2001), 48000 Hz, 5.1(side), fltp, 1536 kb/s
    Metadata:
      DURATION        : 00:00:10.005000000
  Stream #0:3(eng): Audio: ac3 ([0] [0][0] / 0x2000), 48000 Hz, stereo, fltp, 192 kb/s
    Metadata:
      DURATION        : 00:00:10.016000000
  Stream #0:4(eng): Audio: aac (LC) ([255][0][0][0] / 0x00FF), 48000 Hz, 5.1(side), fltp, 394 kb/s (default)
    Metadata:
      encoder         : Lavc61.32.101 aac
      DURATION        : 00:00:10.005000000
[out#0/matroska @ 000001f6a4be8840] video:37636KiB audio:5207KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.053611%
frame=  244 fps=203 q=-1.0 Lsize=   42866KiB time=00:00:10.00 bitrate=35098.3kbits/s speed=8.32x
[aac @ 000001f6a591c240] Qavg: 7222.731

Again, I can open the resulting 'Converted.mkv' in VLC and confirm that all four audio tracks play. But when I test this new file in Windows Media Player, this new, 4th, AAC stream is silent. It's different than the first two unsupported streams, which I can't select. This new stream can be selected, it's just silent.

What could be happening that would cause this track to not play correctly? Where would I start in debugging that?

Ali Khakbaz
  • 1,057

1 Answers1

2

I think I've narrowed down specifically what's causing the problem and a nearly perfect work around.

I noticed something in my hours of debugging and research. In my original question, notice the output produced for that new audio stream:

Stream #0:4(eng): Audio: aac (LC) ([255][0][0][0] / 0x00FF), 48000 Hz, 5.1(side), fltp, 394 kb/s (default)

Looks fine, right? However, if I then reanalyze that same file using ffprobe, I get the following:

Stream #0:4(eng): Audio: aac (LC), 48000 Hz, 6 channels, fltp (default)

Notice the channel layout data seems to be totally missing. Even though ffmpeg thinks it's properly encoding with 5.1(side), it seems like that might not be properly happening. There was a hint that something might be amiss with the channel layout when I was transcoding, too. A little info message:

Using a PCE to encode channel layout "5.1(side)"

Researching this further led me to Using a PCE to encode channel layout 5.1(side):

AAC uses a 4-bit flag to store the channel layout, so there are 16 possible channel layouts, 5.1(side) isn't one of them. But if that value is set to 0, the channel layout is explicitly described in the PCE (Program Config Element).

My theory is that either this PCE block isn't being properly written, or that Windows Media Player (and the media player built into iOS) don't know how to properly handle the data being read.

Holding that assumption, I decided to try converting the 5.1(side) layout to just plain 5.1, which is one of the 16 preset channel layouts supported by AAC. To do so, I used the answer to a similar question, Correctly mapping 5.1 to Opus:

Opus spec only allows the 5.1 layout (FL FR FC LFE BL BR). The easiest solution is to use the channelmap -filter to map the two side speakers to the back speakers.

-filter:a "channelmap=FL-FL|FR-FR|FC-FC|LFE-LFE|SL-BL|SR-BR:5.1"

When I added the above channelmap into my original command, the resulting file was playable across all my devices (including iOS if I changed the container to .mp4).