Borewit / music-metadata

Stream and file based music metadata parser for node. Supporting a wide range of audio and tag formats.
MIT License
972 stars 93 forks source link

Mp3 duration issues #788

Closed adrydez closed 3 years ago

adrydez commented 3 years ago

Mp3 files with variable bitrate haven't the info of "duration" in seconds

To have that information. For instance, if mp3s are constant bitrate, "CBR" is recognized and "duration" is available

MP3 with constant rate info:

format: bitrate: 192000 codecProfile: "CBR" dataformat: "MPEG" duration: 15.296 encoder: "mp3" lossless: false numberOfChannels: 2 sampleRate: 48000 tagTypes: ["ID3v2.4"] tool: "LAME 3.100U"

MP3 with variable bitrate info

firmat: bitrate: 160000 dataformat: "MPEG" encoder: "mp3" lossless: false numberOfChannels: 1 sampleRate: 48000

Borewit commented 3 years ago

That is not necessary true @adrydez . If the duration is available in the LAME (VBR) header, it is provided. If not, there is no way to know the duration without decoding the entire audio stream, and that is not the job of the module. It decodes metadata, and does sometimes even a bit more then that, but it's not a metadata re-constructor.

Please provide a sample of you believe the duration is available and not provided.

adrydez commented 3 years ago

You can find two mp3 files at this address: WeTranfer One of them is constant, the other one, variable. The content on them is the same and the files have been created with adobe audition

Borewit commented 3 years ago

aws_Var.mp3 has no VBR header:

image

if there is a VBR header, the length can be derived from that: image

Try the LAME encoder and you will see that it will just work fine. This is considered the best MP3 encoder.

Borewit commented 3 years ago

Forget what I said before, if you enable the duration flag, it will get the duration: {duration: true} by adding up the duration of each MPEG frame:

describe('#788', () => {

  const filePath = path.join(issue_path, '#788', 'aws_Var.mp3');

  it('Duration VBR', async () => {
    const {format, common} = await mm.parseFile(filePath, {duration: true});
    assert.strictEqual(format.container, 'MPEG', 'format.container');
    assert.strictEqual(format.codec, 'MPEG 1 Layer 3', 'format.codec');
    assert.isDefined(format.duration, 'format.duration');
  });

});