saecki / mp4ameta

A library for reading and writing iTunes style MPEG-4 audio metadata
Apache License 2.0
35 stars 5 forks source link

Reading chapters info. #18

Open vlabo opened 3 years ago

vlabo commented 3 years ago

Is there a way of reading chapters info from m4b files?

saecki commented 3 years ago

I don't think there is a standard key for chapters in mp4 files (at least I couldn't find one in the hydrogenaudio or musicbrainz tag mappings). If you have a file that contains chapters or know of a key that should be used let me know.

vlabo commented 3 years ago

Kind of strange I cannot find free m4b file with chapters. I convert my audible .aax audiobook files to m4b and they have chapters, but I cannot share them.

But I found .3gp file with chapters: https://archive.org/download/art_of_war_librivox/ArtOfWar-64kb_librivox.m4b

It's still the same file format right?

Edit:

$> ffprobe ArtOfWar-64kb_librivox.3gp
ffprobe version n4.4 Copyright (c) 2007-2021 the FFmpeg developers
  built with gcc 11.1.0 (GCC)
  configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec --enable-nvenc --enable-shared --enable-version3
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x560ca6cba440] Unknown cover type: 0x0.
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'ArtOfWar-64kb_librivox.3gp':
  Metadata:
    major_brand     : M4A
    minor_version   : 0
    compatible_brands: 3gp5isom
    creation_time   : 2010-04-09T08:47:43.000000Z
    genre           : Audiobook
    media_type      : 2
    encoder         : Chapter and Verse V 1.4
    title           : The Art of War
    artist          : Sun Tzu
    album           : The Art of War
    comment         : http://librivox.org/the-art-of-war-by-sun-tzu/
                    :
                    : More free M4B files @  http://wiki.librivox.org/index.php/M4B_Catalog
    Encoding Params : vers
  Duration: 01:12:18.28, start: 0.000000, bitrate: 33 kb/s
  Chapters:
    Chapter #0:0: start 0.000000, end 506.042540
      Metadata:
        title           : 1 Laying Plans - 2 Waging War
    Chapter #0:1: start 506.042540, end 972.020454
      Metadata:
        title           : 3 Attack By Stratagem - 4 Tactical Dispositions
    Chapter #0:2: start 972.020454, end 1609.010658
      Metadata:
        title           : 5 Energy - 6 Weak Points and Strong
    Chapter #0:3: start 1609.010658, end 2140.001950
      Metadata:
        title           : 7 Maneuvering - 8 Variation in Tactics
    Chapter #0:4: start 2140.001950, end 3022.022404
      Metadata:
        title           : 9 The Army on the March - 10 Terrain
    Chapter #0:5: start 3022.022404, end 3799.007029
      Metadata:
        title           : 11 The Nine Situations
    Chapter #0:6: start 3799.007029, end 4338.277007
      Metadata:
        title           : 12 The Attack By Fire - 13 The Use of Spies
  Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 22050 Hz, mono, fltp, 32 kb/s (default)
    Metadata:
      creation_time   : 2010-04-09T08:47:43.000000Z
      vendor_id       : [0][0][0][0]
  Stream #0:1(und): Data: bin_data (text / 0x74786574)
    Metadata:
      creation_time   : 2010-04-09T08:47:47.000000Z
saecki commented 3 years ago

Yes the format is very similar. It seems like the chapters are stored somewhere inside the traks themselves. I will look into parsing that information.

vlabo commented 3 years ago

I did some testing with the current version. Great work so far. And thanks for the quick response.

It seems like there is noting standard as you said. With some file Im not able to read the chapters with the current version.

When I can I'll do some more research and find more test files.

20000_Leagues_Under_Seas_Part_1_64kb.m4b

Edit: Here is a chaptered m4a file that I generated with ffmpeg chaptered.zip

> ffprobe 20000_Leagues_Under_Seas_Part_1_64kb.m4b 
ffprobe version 4.2.4-1ubuntu0.1 Copyright (c) 2007-2020 the FFmpeg developers
  built with gcc 9 (Ubuntu 9.3.0-10ubuntu2)
  configuration: --prefix=/usr --extra-version=1ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x55b776513f00] Unknown cover type: 0x0.
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '20000_Leagues_Under_Seas_Part_1_64kb.m4b':
  Metadata:
    major_brand     : M4A
    minor_version   : 0
    compatible_brands: 3gp5isom
    creation_time   : 2011-10-13T14:24:39.000000Z
    genre           : Blues
    media_type      : 2
    encoder         : Chapter and Verse V 1.4
    title           : 20,000 Leagues Under the Seas, Part 1
    artist          : Jules Verne
    album           : 20,000 Leagues Under the Seas
    Encoding Params : vers
  Duration: 07:00:15.90, start: 0.000000, bitrate: 66 kb/s
    Chapter #0:0: start 0.000000, end 731.007596
    Metadata:
      title           : Introduction and Units of Measure
    Chapter #0:1: start 731.007596, end 1647.014512
    Metadata:
      title           : Chapter 1
    Chapter #0:2: start 1647.014512, end 2392.021633
    Metadata:
      title           : Chapter 2
    Chapter #0:3: start 2392.021633, end 3062.010839
    Metadata:
      title           : Chapter 3
    Chapter #0:4: start 3062.010839, end 3896.015896
    Metadata:
      title           : Chapter 4
    Chapter #0:5: start 3896.015896, end 4679.004308
    Metadata:
      title           : Chapter 5
    Chapter #0:6: start 4679.004308, end 5688.017460
    Metadata:
      title           : Chapter 6
    Chapter #0:7: start 5688.017460, end 6709.009138
    Metadata:
      title           : Chapter 7
    Chapter #0:8: start 6709.009138, end 7897.010227
    Metadata:
      title           : Chapter 8
    Chapter #0:9: start 7897.010227, end 8843.018209
    Metadata:
      title           : Chapter 9
    Chapter #0:10: start 8843.018209, end 10128.001179
    Metadata:
      title           : Chapter 10
    Chapter #0:11: start 10128.001179, end 11335.001088
    Metadata:
      title           : Chapter 11
    Chapter #0:12: start 11335.001088, end 12214.004036
    Metadata:
      title           : Chapter 12
    Chapter #0:13: start 12214.004036, end 13265.008345
    Metadata:
      title           : Chapter 13
    Chapter #0:14: start 13265.008345, end 14788.012472
    Metadata:
      title           : Chapter 14
    Chapter #0:15: start 14788.012472, end 15945.005170
    Metadata:
      title           : Chapter 15
    Chapter #0:16: start 15945.005170, end 16809.004966
    Metadata:
      title           : Chapter 16
    Chapter #0:17: start 16809.004966, end 17686.013787
    Metadata:
      title           : Chapter 17
    Chapter #0:18: start 17686.013787, end 19055.019093
    Metadata:
      title           : Chapter 18
    Chapter #0:19: start 19055.019093, end 20434.004558
    Metadata:
      title           : Chapter 19
    Chapter #0:20: start 20434.004558, end 21489.002925
    Metadata:
      title           : Chapter 20
    Chapter #0:21: start 21489.002925, end 22837.007914
    Metadata:
      title           : Chapter 21
    Chapter #0:22: start 22837.007914, end 24102.016848
    Metadata:
      title           : Chapter 22
    Chapter #0:23: start 24102.016848, end 25215.895510
    Metadata:
      title           : Chapter 23
    Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 64 kb/s (default)
    Metadata:
      creation_time   : 2011-10-13T14:24:39.000000Z
    Stream #0:1(und): Data: bin_data (text / 0x74786574)
    Metadata:
      creation_time   : 2011-10-13T14:25:26.000000Z
saecki commented 3 years ago

There are standards, I was just looking in the wrong place at first. Though there seems to be at least one other way of storing chapter information. Sometimes a chapter list (chpl) atom is used for that. That is the case for the m4a file you generated using ffmpeg. The other file uses the other way so I'm going to take a look what is failing there.

saecki commented 3 years ago

So after looking around at what others do a bit more, it turns out there is no real standard timescale for chapter list (chpl) atoms. Everyone seems to do their own thing. So I added a configuration option to specify either a fixed timescale, or use the global timescale of the file. By default a fixed timescale of 10,000,000 is used.

I had no issues reading the 20000_Leagues_Under_Seas_Part_1_64kb.m4b file.

The chaptered.m4a file also read (rather) successfully. The first chapter is also stored in the alternative format, so it appears as a duplicate. FFMpeg merges these two but we (so far) don't, because I haven't decided what's the best way to this.

vlabo commented 3 years ago

Thanks for the update.

In my use case if there is support for the FFMpeg way of storing chapters it will be sufficient. I'm developing Audiobook player for linux and if the format is not the right way it can me easily converted with simple script.