Search code examples
androidffmpegmp4codecpydub

M4a (mp4) audio file encoded with pydub+ffmpeg doesn't play on Android


I have a python script to split up some wav files and export to m4a using pydub. I'm able to get these files to play on several devices, but not on an Android device (using Google Pixel 3). When I try encoding with straight ffmpeg in terminal, that works fine on the Android device.

What is the difference in these two files, and since pydub is using ffmpeg, what do I need to change to make it do exactly the same as the ffmpeg command?

Not working

from pydub import AudioSegment
>>> audio = AudioSegment.from_wav("input.wav")
>>> slice = audio[1000:3000]
>>> slice.export("pydub_export.m4a", format="mp4", parameters=["-ac", "1", "-c:a", "libfdk_aac", "-profile:a", "aac_he", "-vbr", "2"])

mediainfo output:

General
Complete name                            : pydub_export.m4a
Format                                   : MPEG-4
Format profile                           : Base Media
Codec ID                                 : isom (isom/iso2/mp41)
File size                                : 11.7 KiB
Duration                                 : 2 s 115 ms
Overall bit rate mode                    : Constant
Overall bit rate                         : 45.1 kb/s
Writing application                      : Lavf58.29.100

Audio
ID                                       : 1
Format                                   : AAC LC SBR
Format/Info                              : Advanced Audio Codec Low Complexity with Spectral Band Replication
Commercial name                          : HE-AAC
Format settings                          : NBC
Codec ID                                 : mp4a-40-5
Duration                                 : 2 s 115 ms
Duration_LastFrame                       : -22 ms
Bit rate mode                            : Constant
Bit rate                                 : 41.4 kb/s
Channel(s)                               : 1 channel
Channel layout                           : C
Sampling rate                            : 44.1 kHz
Frame rate                               : 21.533 FPS (2048 SPF)
Compression mode                         : Lossy
Stream size                              : 10.7 KiB (92%)
Default                                  : Yes
Alternate group                          : 1

Working

$ffmpeg -i input.wav -acodec copy -ss 1 -to 3 input_slice.wav
$ffmpeg -i input_slice.wav -ac 1 -c:a libfdk_aac -profile:a aac_he -vbr 2 ffmpeg_export.m4a

mediainfo output:

General
Complete name                            : ffmpeg_export.m4a
Format                                   : MPEG-4
Format profile                           : Apple audio with iTunes info
Codec ID                                 : M4A  (isom/iso2)
File size                                : 11.2 KiB
Duration                                 : 2 s 112 ms
Overall bit rate mode                    : Constant
Overall bit rate                         : 43.6 kb/s
Writing application                      : Lavf58.29.100

Audio
ID                                       : 1
Format                                   : AAC LC SBR
Format/Info                              : Advanced Audio Codec Low Complexity with Spectral Band Replication
Commercial name                          : HE-AAC
Format settings                          : NBC
Codec ID                                 : mp4a-40-5
Duration                                 : 2 s 112 ms
Duration_LastFrame                       : -25 ms
Bit rate mode                            : Constant
Bit rate                                 : 39.9 kb/s
Channel(s)                               : 1 channel
Channel layout                           : C
Sampling rate                            : 44.1 kHz
Frame rate                               : 21.533 FPS (2048 SPF)
Compression mode                         : Lossy
Stream size                              : 10.3 KiB (91%)
Default                                  : Yes
Alternate group                          : 1

I already tried moving metadata to the front with -movflags faststart on the broken file and it didn't make a difference.


Solution

  • Using pydub's logging, I was able to see exactly the ffmpeg command it produced.

    Turns out that the format=... argument in pydub provides the flag -f ... to ffmpeg. It was just a matter of finding the right -f argument to use, and mp4 was giving me the bad file.

    @Gyan 's answer here suggested -f ipod. So using format="ipod" in pydub gives the correct output.