Hallo!
Die MediaPlayer-Serie von MS kommt ja bekanntlich nicht mit VBR zurecht und zeigt falsche Songlängen an. Selbes passiert mir (erwartungsgemäss), wenn ich über Microsoft.DirectX.AudioVideoPlayback die Länge auslese.
Gibt es denn noch eine andere Möglichkeit, VBR richtig zu interpretieren? Hat nicht Winamp zufällig auch eine freie dll zum Benutzen?
wird die bitrate denn korrekt ausgegeben?
wenn ja, dann rechnest du dir die länge einfach selber aus:
länge: 3200 / 16 = 200 s = 3 min 20 s
grtz
chief
genaugenommen sollte man natürlich noch den MPEG-header u. evtl. die ID-Tags abziehen...
also ist diese rechnung ungenau.
grtz
chief
_Original von Chief Brodie_bitrate: 128 kb/s = 16 kB/s
Wer lesen kann, ist klar im Vorteil ... da gibt es nicht DIE Bitrate ...
Wissensvermittler und Technologieberater
für .NET, Codequalität und agile Methoden
Wer lesen kann, ist klar im Vorteil ... da gibt es nicht DIE Bitrate ...
wer jede abkürzung kennt, vielleicht...
...eine dumme und überflüssige bemerkung!
🙄
grtz
chief
Hatte mir selber mal nen kleinen Player gebastelt.
Ich weiß nicht ob dir das hier weiterhilft:
using DX_AudioVideo;
using System;
using System.IO;
using System.Collections;
using Microsoft.DirectX.AudioVideoPlayback;
class MP3_Header
{
FileInfo fi = null;
FileStream fs;
Track track;
// Daten um Header zu finden und zu speichern
int neue_Zahl;
int ergebnis;
int rest;
string temp = "";
string output = ""; // binär Ausgabe des Headers als String
byte[] header = new byte[4]; // 4 Bytes des Headers
int[] IntBytes = new int[4];
int headerpos; // Headerheaderposition
// MP3 Header-Daten Bit
string SyncWord; // 0 - 11
string MPEG_Version; // 12
string MPEG_Layer; // 13 - 14
string ProtectionBit; // 15
string Bitrate; // 16 - 19
string SamplingFrequency; // 20 - 21
string PaddingBit; // 22
string PrivateBit; // 23
string Mode; // 24 - 25
string ModeExtension; // 26 - 27
string Copyright; // 28
string OriginalHome; // 29
string Emphasis; // 30 - 31
// MPEG 1 & 2 Layer 1 are the same kbit/s
string[] Layer1 = new string[]{"-","32","64","96","128","160","192","224","256","288","320","352","384","416","448","-"};
// MPEG 1 & 2 Layer 2 are the same kbit/s
string[] Layer2 = new string[]{"-","32","48","56","64","80","96","112","128","160","192","224","256","320","384","-"};
// MPEG 1 Layer 3
string[] Layer3_1 = new string[]{"-","32","40","48","56","64","80","96","112","128","160","192","224","256","320","-"};
// MPEG 2 Layer 3
string[] Layer3_2 = new string[]{"-","8","16","24","32","64","80","56","64","128","160","112","128","256","320","-"};
int FrameCount;
public MP3_Header(Track track)
{
//this.GetHeader();
this.track = track;
Console.WriteLine("MP3_Header angelegt mit: MP3_Header("+track.GetPath()+")");
this.GetHeaderPos();
this.GetHeaderParts(output);
this.CountFrames();
}
public void GetHeader(byte[] header)
{
/*
* Jedes Byte wird per "Restverfahren" in seine 8 Bits zerlegt.
* Dabei wird die Reihenfolge der Bits umgekehrt.
* Zur Kontrolle kann jeder Rechenschritt ausgegeben werden. (Kommentierung entfernen)
* */
foreach( byte b in header ) // für jedes Element in "ByteArray"
{
neue_Zahl = b;
for(int i = 0; i < 8; ++i) // 8 mal ( 8 bit = 1 byte)
{
ergebnis = neue_Zahl/2; // Ergebnis der Division
rest = neue_Zahl%2; // Restwert der Division
//Console.WriteLine("{0,3} durch 2 = {1,3} Rest: {2}", neue_Zahl, ergebnis, rest);
temp = temp.Insert(0,rest.ToString()); // Rest im temporären String an Position 0 einfügen
// wegen umgekehrter Reihenfolge der bits
neue_Zahl = ergebnis; // zum Weiterrechnen im nächsten Durchlauf
}
output += temp;//+" "; // Einfügen eines Leerzeichens um jeweils 8 Bit voneinander zu trennen
temp = ""; // temporären String wieder "leeren"
}
Console.WriteLine(output);
fs.Close();
}
public void GetHeaderPos()
{
//fi = new FileInfo(@"C:\mp3\Track 01-.mp3");
//fi = new FileInfo(@"C:\mp3\01 - Flat On The Floor.mp3");
//fi = new FileInfo(@"C:\mp3\10 - Another Hole In The Head.mp3");
fi = new FileInfo(track.GetPath());
Console.WriteLine("MP3_Header.GetHeaderPos():"+track.GetPath());
fs = fi.OpenRead();
byte b;
headerpos = 0;
do
{
b = (byte)fs.ReadByte();
//Console.WriteLine("Byte Nr: {0,4}: {1} ",headerpos,(int)header[0]);
headerpos++;
}while(b != 0xff);
Console.WriteLine("\nHeader:\n******");
header[0] = b;
Console.WriteLine("Byte 0 = {0:x}",(int)b);
for(int i = 1; i <= 3; ++i)
{
header[i] = (byte)fs.ReadByte();
Console.WriteLine("Byte {0} = {1:x}",i+1,(int)header[i]);
}
Console.WriteLine("\n\nHeader bei: " +(headerpos-1));
this.GetHeader(header);
// 11111111 11111011 10110000 01100100
// 11111111 11111011 10110000 01100100
fs.Close();
}
public void GetHeaderParts(string output)
{
this.SyncWord = output.Substring(0,12);
this.MPEG_Version = output.Substring(12,1);
this.MPEG_Layer = output.Substring(13,2);
this.ProtectionBit = output.Substring(15,1);
this.Bitrate = output.Substring(16,4);
this.SamplingFrequency = output.Substring(20,2);
this.PaddingBit = output.Substring(22,1);
this.PrivateBit = output.Substring(23,1);
this.Mode = output.Substring(24,2);
this.ModeExtension = output.Substring(26,2);
this.Copyright = output.Substring(28,1);
this.OriginalHome = output.Substring(29,1);
this.Emphasis = output.Substring(30,2);
// Console.WriteLine("SyncWord: " + SyncWord +
// "\nMPEG_Version: "+ MPEG_Version +
// "\nMPEG_Layer: "+ MPEG_Layer +
// "\nProtectionBit:"+ ProtectionBit +
// "\nBitrate: "+ Bitrate);
// Console.WriteLine("Version: "+this.GetMPEG_Version());
// Console.WriteLine(this.GetMPEG_Layer());
// Console.WriteLine("CRC-Prüfsumme: "+this.GetProtectionBit());
// Console.WriteLine(this.GetBitrate()+" kbit/s");
// Console.WriteLine(this.GetSamplingFrequency()+" Hz");
// Console.WriteLine("Padding: " +this.GetPaddingBit());
// Console.WriteLine("Private: " +this.GetPrivateBit());
// Console.WriteLine("Mode: " +this.GetMode());
// Console.WriteLine("Copyright: " +this.GetCopyright());
// Console.WriteLine("Original: " + this.GetOriginalHome());
// Console.WriteLine("Rauschunterdr.: " +this.GetEmphasis());
}
// SyncWord (ungenutzt, ausser bei MPEG 2.5)
public string GetSyncWord()
{
return SyncWord;
}
// MPEG Version
public string GetMPEG_Version()
{
if(MPEG_Version.Equals("0"))
return "MPEG 2";
else
return "MPEG 1";
}
// Layer
public string GetMPEG_Layer()
{
if(MPEG_Layer.Equals("00"))
return "undefiniert";
else if(MPEG_Layer.Equals("01"))
return "Layer III";
else if(MPEG_Layer.Equals("10"))
return "Layer II";
else
return "Layer I";
}
// CRC Prüfsumme (ja: 16 Bit nach dem Header)
public string GetProtectionBit()
{
if(this.ProtectionBit.Equals("1"))
return "nein"; // 0: CRC = ja ; 1: CRC = nein
else
return "ja";
}
// Bitrate
public string GetBitrate()
{
if(this.MPEG_Version.Equals("1")) // MPEG 1 ???
{
return this.MPEG_1_Bitrate();
}
else // MPEG 2 ???
{
return this.MPEG_2_Bitrate();
}
}
// Sample Frequenz
public string GetSamplingFrequency()
{
if(MPEG_Version.Equals("1"))
{
switch(this.SamplingFrequency)
{
case "00": return "44100";
case "01": return "48000";
case "10": return "32000";
case "11": return "-";
default: return "error";
}
}
else
{
switch(this.SamplingFrequency)
{
case "00": return "22050";
case "01": return "24000";
case "10": return "16000";
case "11": return "-";
default: return "error";
}
}
}
// Padding Bit
public string GetPaddingBit()
{
if(this.PaddingBit.Equals("1"))
return "ja";
else
return "nein";
}
// Private Bit (ungenutzt)
public string GetPrivateBit()
{
if(this.PrivateBit.Equals("1"))
return "ja";
else
return "nein";
}
// Audio Modus
public string GetMode()
{
switch(this.Mode)
{
case "00": return "Stereo";
case "01": return "Joint Stereo";
case "10": return "Dual-Channel";
case "11": return "Mono";
default: return "error";
}
}
// Nur interessant bei Joint Stereo
//
// public string GetModeExtension(string ModeExtension)
// {
//
// }
// Copyright ja/nein
public string GetCopyright()
{
if(this.Copyright.Equals("1"))
return "ja";
else
return "nein";
}
// Original-Datenstrom
public string GetOriginalHome()
{
if(this.OriginalHome.Equals("1"))
return "ja";
else
return "nein";
}
// Rauschunterdrückung
public string GetEmphasis()
{
switch(this.Emphasis)
{
case "00": return "keine";
case "01": return "50/15ms";
case "10": return "reserviert";
case "11": return "CCITT j.17";
default: return "error";
}
}
private string MPEG_1_Bitrate()
{
if(this.MPEG_Layer.Equals("11")) // MPEG 1 Layer I ???
{
return this.Layer1[this.Bitrates()];
}
else if(this.MPEG_Layer.Equals("10")) // MPEG 1 Layer II ???
{
return this.Layer2[this.Bitrates()];
}
else // MPEG 1 Layer III ???
{
return this.Layer3_1[this.Bitrates()];
}
}
private string MPEG_2_Bitrate()
{
if(this.MPEG_Layer.Equals("11")) // MPEG 2 Layer I ???
{
return this.Layer1[this.Bitrates()];
}
else if(this.MPEG_Layer.Equals("10")) // MPEG 2 Layer II ???
{
return this.Layer2[this.Bitrates()];
}
else // MPEG 2 Layer III ???
{
return this.Layer3_2[this.Bitrates()];
}
}
private int Bitrates()
{
switch(this.Bitrate)
{
case "0000": return 0;
case "0001": return 1;
case "0010": return 2;
case "0011": return 3;
case "0100": return 4;
case "0101": return 5;
case "0110": return 6;
case "0111": return 7;
case "1000": return 8;
case "1001": return 9;
case "1010": return 10;
case "1011": return 11;
case "1100": return 12;
case "1101": return 13;
case "1110": return 14;
case "1111": return 15;
default: return -1;
}
}
void CountFrames()
{
double framelength = 0;
double bitrate = (Convert.ToDouble(this.GetBitrate()))*1000; // kbps * 1000
double frequency = (Convert.ToDouble(this.GetSamplingFrequency()));
double padding = Convert.ToDouble(this.PaddingBit);
if(this.GetMPEG_Layer().Equals("Layer I"))
{
Console.WriteLine(this.GetMPEG_Layer());
framelength = (12 * bitrate / frequency + padding) * 4;
Console.WriteLine("(12 * {0} / {1} + {2}) * 4 = {3}", bitrate, frequency, padding, framelength);
}
else
{
Console.WriteLine(this.GetMPEG_Layer());
framelength = 144 * bitrate;
Console.WriteLine("144 * bitrate = " + framelength);
framelength = framelength / frequency;
Console.WriteLine("framelength / frequency = " + framelength);
framelength = framelength + padding;
Console.WriteLine("framelength + padding = " + framelength);
Console.WriteLine("144 * {0} / {1} + {2} = {3}", bitrate, frequency, padding, framelength);
}
FrameCount = (int)framelength;
Console.WriteLine("Framelength in Bytes: {0}",(int)framelength);
//return FrameCount;
}
public int GetFrameCount()
{
return FrameCount;
}
}
Ist mit Sicherheit nicht die elgenteste Lösung, aber ich hatte mit der Tracklänge nie Probleme. 😁
*************************
Ich bin root, ich darf das... 😜
root>_
*************************
Das ist auch nicht die Lösung. Ganz unten gibt es eine CountFrames-Methode, die funktioniert aber nur für feste Bitraten.
Ich habe (vor zwei Jahren) aus dem C-Code des Frauenhofer Mp3-Decoders eine C#-Version entwickelt. Guter, objektorientierter Code: es gibt nur ein Mp3-Frame-Objekt. Über einen BitStream (und ein BitReservoir) wird der Mp3-Frame immer wieder von neuem aufgefüllt, kein einziges "new" im Code. Performance-kritische Teile sind nativ implementiert (IMDCT, Subband-Synthese).
Das müsste ich mal veröffentlichen. Bisher liegt es nur bei mir rum, komm irgendwie nicht dazu.
Jedenfalls, um die Spieldauer eines VBR-Files zu ermitteln, müssen erstmal alle Frame-Headers gelesen werden. Es sei denn über VBR soll eine feste, aber unübliche Bitrate eingestellt werden (z.B. 100 kb). Ich glaub da gab es Bits, anhand derer man das untescheiden konnte. Auf jeden Fall sind zwei VBR-Verfahren beschrieben: feste Bitrate und qualitätsgesteuerte Bitrate.
Gruss
Pulpapex