|
Вопрос # 2 097/ вопрос открыт / |
|
Здравствуйте уважаемые эксперты!
Во время написания видео-аудио проигрывателя столкнулся с такой проблемой,как медленная обработка медиа- файлов(музыка,видео),т.е. определения времени воспроизведения файла, и у меня вопрос:
Если кто знает напишите,как найти в медиа-файле(аудио формат,иль видео формат не важно!!) время воспроизведения видео(или аудио композиции),если сможете,то напишите хотя бы литературу,где написаны,какие байты из медиа-файла даны под информацию о времени проигрывания.
А если предоставите код,то буду просто рад.
А то время опредиления например 1700 файлов составляет 37 секунд,а в AIM'пе всего 5:((,хочу хоть чуть-чуть приблизится к нему)).
Сразу скажу,что определяю время,через DirectShow.
 |
Вопрос задал: Anatol_rus (статус: Посетитель)
Вопрос отправлен: 17 ноября 2008, 22:41
Состояние вопроса: открыт, ответов: 1.
|
Ответ #1. Отвечает эксперт: Feniks
Здравствуйте, Anatol_rus!
Я нашел несколько примеров в приложении:
1. Как прочитать свойства видео файла;
2. Информация о AVI файле, (разбор заголовка AVI);
3. Как определить продолжительность в секундах wav файла.
А по поводу MP3 ищите тут на сайте в вопросах и ответах. Как-то уже выкладывали информацию, как можно прочитать заголовки mp3.
P.S. Желаю удачи.
Приложение: Переключить в обычный режим-
- type
- TDSMediaInfo = record
- SurfaceDesc: TDDSurfaceDesc;
- Pitch: integer;
- PixelFormat: TPixelFormat;
- MediaLength: Int64;
- AvgTimePerFrame: Int64;
- FrameCount: integer;
- Width: integer;
- Height: integer;
- FileSize: Int64;
- end;
-
- function GetHugeFileSize(const FileName: string): int64;
- var
- FileHandle: hFile;
- begin
- FileHandle := FileOpen(FileName, fmOpenRead or fmShareDenyNone);
- try
- LARGE_INTEGER(Result).LowPart := GetFileSize(FileHandle, @LARGE_INTEGER(Result).HighPart);
- if LARGE_INTEGER(Result).LowPart = $FFFFFFFF then
- Win32Check(GetLastError = NO_ERROR);
- finally
- FileClose(FileHandle);
- end;
- end;
-
- function GetMediaInfo(FileName: WideString): TDSMediaInfo;
- var
- DirectDraw: IDirectDraw;
- AMStream: IAMMultiMediaStream;
- MMStream: IMultiMediaStream;
- PrimaryVidStream: IMediaStream;
- DDStream: IDirectDrawMediaStream;
- GraphBuilder: IGraphBuilder;
- MediaSeeking: IMediaSeeking;
- TimeStart, TimeStop: Int64;
- DesiredSurface: TDDSurfaceDesc;
- DDSurface: IDirectDrawSurface;
- begin
- if FileName = '' then
- raise Exception.Create('No File Name Specified');
- OleCheck(DirectDrawCreate(nil, DirectDraw, nil));
- DirectDraw.SetCooperativeLevel(GetDesktopWindow(), DDSCL_NORMAL);
- Result.FileSize := GetHugeFileSize(FileName);
- AMStream := IAMMultiMediaStream(CreateComObject(CLSID_AMMultiMediaStream));
- OleCheck(AMStream.Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, nil));
- OleCheck(AMStream.AddMediaStream(DirectDraw, MSPID_PrimaryVideo, 0, IMediaStream(nil^)));
- OleCheck(AMStream.OpenFile(PWideChar(FileName), AMMSF_NOCLOCK));
- AMStream.GetFilterGraph(GraphBuilder);
- MediaSeeking := GraphBuilder as IMediaSeeking;
- MediaSeeking.GetDuration(Result.MediaLength);
- MMStream := AMStream as IMultiMediaStream;
- OleCheck(MMStream.GetMediaStream(MSPID_PrimaryVideo, PrimaryVidStream));
- DDStream := PrimaryVidStream as IDirectDrawMediaStream;
- DDStream.GetTimePerFrame(Result.AvgTimePerFrame);
- {Result.FrameCount := Result.MediaLength div Result.AvgTimePerFrame;}
- { TODO : Test for better accuracy }
- Result.FrameCount := Round(Result.MediaLength / Result.AvgTimePerFrame);
- Result.MediaLength := Result.FrameCount * Result.AvgTimePerFrame;
- ZeroMemory(@DesiredSurface, SizeOf(DesiredSurface));
- DesiredSurface.dwSize := Sizeof(DesiredSurface);
- OleCheck(DDStream.GetFormat(TDDSurfaceDesc(nil^), IDirectDrawPalette(nil^),
- DesiredSurface, DWord(nil^)));
- Result.SurfaceDesc := DesiredSurface;
- DesiredSurface.ddsCaps.dwCaps := DesiredSurface.ddsCaps.dwCaps or
- DDSCAPS_OFFSCREENPLAIN or DDSCAPS_SYSTEMMEMORY;
- DesiredSurface.dwFlags := DesiredSurface.dwFlags or DDSD_CAPS or DDSD_PIXELFORMAT;
- {Create a surface here to get vital statistics}
- OleCheck(DirectDraw.CreateSurface(DesiredSurface, DDSurface, nil));
- OleCheck(DDSurface.GetSurfaceDesc(DesiredSurface));
- Result.Pitch := DesiredSurface.lPitch;
- if DesiredSurface.ddpfPixelFormat.dwRGBBitCount = 24 then
- Result.PixelFormat := pf24bit
- else if DesiredSurface.ddpfPixelFormat.dwRGBBitCount = 32 then
- Result.PixelFormat := pf32bit;
- Result.Width := DesiredSurface.dwWidth;
- Result.Height := DesiredSurface.dwHeight;
- end;
-
-
- unit Unit1;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls;
-
- Type
- TForm1 = class(TForm)
- Memo1: TMemo;
- OpenDialog1: TOpenDialog;
- Button1: TButton;
- procedure Button1Click(Sender: TObject);
- Public
- procedure ReadAviInfo(FileName: String);
- End;
-
- var
- Form1: TForm1;
-
- implementation
-
- {$R *.dfm}
-
- procedure TForm1.ReadAviInfo(FileName: String);
- var
-
-
-
- Aviheadersize: Integer;
- Vheadersize: Integer;
- Aviheaderstart: Integer;
- Vheaderstart: Integer;
- Aheaderstart: Integer;
- Astrhsize: Integer;
-
-
- TempTest: String[5];
- TempSize: Integer;
- TempVcodec: String[5];
- TempAcodec: Integer;
- TempMicrosec: Integer;
- TempLengthInFrames: Integer;
- TempAchannels: Integer;
- TempAsamplerate: Integer;
- TempAbitrate: Integer;
-
-
- Size: Double;
- Length: String;
- Vcodec: String;
- Vbitrate: Double;
- VWidth: Integer;
- VHeight: Integer;
- Fps: Double;
-
- LengthInSec: Double;
- Acodec: String;
- Abitrate: String;
- begin
-
- iFileHandle := FileOpen(FileName, fmOpenRead);
-
-
- FileSeek(iFileHandle, 7, 0);
- FileRead(iFileHandle, TempTest, 5);
- If copy(TempTest, 0, 4) <> 'AVI ' then
- begin
- MessageDlg('Could not open ' + FileName + ' because it is not a valid video file', mtError,
[mbOk], 0);
- Exit;
- End;
-
-
- FileSeek(iFileHandle,4,0);
- FileRead(iFileHandle, TempSize, 4);
-
-
- FileSeek(iFileHandle,28,0);
- FileRead(iFileHandle, Aviheadersize, 4);
-
-
- Aviheaderstart := 32;
-
-
- FileSeek(iFileHandle,Aviheaderstart,0);
- FileRead(iFileHandle, TempMicrosec, 4);
-
-
- FileSeek(iFileHandle,Aviheaderstart + 16,0);
- FileRead(iFileHandle, TempLengthInFrames, 4);
-
-
- FileSeek(iFileHandle,Aviheaderstart + 32,0);
- FileRead(iFileHandle, VWidth, 4);
-
-
- FileSeek(iFileHandle,Aviheaderstart + 36,0);
- FileRead(iFileHandle, VHeight, 4);
-
- FileSeek(iFileHandle,Aviheaderstart + Aviheadersize + 4,0);
- FileRead(iFileHandle, Vheadersize, 4);
-
- Vheaderstart := Aviheaderstart + Aviheadersize + 20;
-
-
- FileSeek(iFileHandle,Vheaderstart + 3,0);
- FileRead(iFileHandle, TempVCodec, 5);
-
- Aheaderstart := Vheaderstart + Vheadersize + 8;
-
- FileSeek(iFileHandle,Aheaderstart - 4,0);
- FileRead(iFileHandle, Astrhsize, 5);
-
- // Audio codec
- FileSeek(iFileHandle,Aheaderstart + Astrhsize + 8,0);
- FileRead(iFileHandle, TempACodec, 2);
-
-
- FileSeek(iFileHandle,Aheaderstart + Astrhsize + 10,0);
- FileRead(iFileHandle, TempAchannels, 2);
-
- // Audio samplerate
- FileSeek(iFileHandle,Aheaderstart + Astrhsize + 12,0);
- FileRead(iFileHandle, TempAsamplerate, 4);
-
- // Audio bitrate
- FileSeek(iFileHandle,Aheaderstart + Astrhsize + 16,0);
- FileRead(iFileHandle, TempAbitrate, 4);
-
-
- FileClose(iFileHandle);
-
-
- Vcodec := copy(TempVcodec, 0, 4);
- If Vcodec = 'div2' then Vcodec := 'MS MPEG4 v2'
- Else If Vcodec = 'DIV2' then Vcodec := 'MS MPEG4 v2'
- Else If Vcodec = 'div3' then Vcodec := 'DivX;-) MPEG4 v3'
- Else If Vcodec = 'DIV3' then Vcodec := 'DivX;-) MPEG4 v3'
- Else If Vcodec = 'div4' then Vcodec := 'DivX;-) MPEG4 v4'
- Else If Vcodec = 'DIV4' then Vcodec := 'DivX;-) MPEG4 v4'
- Else If Vcodec = 'div5' then Vcodec := 'DivX;-) MPEG4 v5'
- Else If Vcodec = 'DIV5' then Vcodec := 'DivX;-) MPEG4 v5'
- Else If Vcodec = 'divx' then Vcodec := 'DivX 4'
- Else If Vcodec = 'mp43' then Vcodec := 'Microcrap MPEG4 v3';
-
-
- Case TempAcodec of
- 0: Acodec := 'PCM';
- 1: Acodec := 'PCM';
- 85: Acodec := 'MPEG Layer 3';
- 353: Acodec := 'DivX;-) Audio';
- 8192: Acodec := 'AC3-Digital';
- Else
- Acodec := 'Unknown (' + IntToStr(TempAcodec) + ')';
- End;
-
- Case (Trunc(TempAbitrate / 1024 * 8)) of
- 246..260: Abitrate := '128 Kbit/s';
- 216..228: Abitrate := '128 Kbit/s';
- 187..196: Abitrate := '128 Kbit/s';
- 156..164: Abitrate := '128 Kbit/s';
- 124..132: Abitrate := '128 Kbit/s';
- 108..116: Abitrate := '128 Kbit/s';
- 92..100: Abitrate := '128 Kbit/s';
- 60..68: Abitrate := '128 Kbit/s';
- Else
- Abitrate := FormatFloat('# Kbit/s', TempAbitrate / 1024 * 8);
- End;
-
-
- Size := TempSize / 1024 / 1024;
- Fps := 1000000 / TempMicrosec; // FPS
- LengthInSec := TempLengthInFrames / fps; // Length In seconds
- Length := FormatFloat('# min', Int(LengthInSec / 60)) + FormatFloat(' # sec',
- Round(LengthInSec - (Int(LengthInSec / 60) * 60)));
- Vbitrate := (TempSize / LengthInSec - TempABitrate) / 1024 * 8;
-
-
- Memo1.Lines.Add('AVI INFORMATION');
- Memo1.lines.Add('Size: ' + FormatFloat('#.## MB',Size));
- Memo1.Lines.Add('Length: ' + Length);
- Memo1.Lines.Add('');
- Memo1.Lines.Add('VIDEO INFORMATION');
- Memo1.Lines.Add('Codec: ' + Vcodec);
- Memo1.Lines.Add('Bitrate: ' + FormatFloat('# Kbit/s', Vbitrate));
- Memo1.lines.Add('Width: ' + IntToStr(VWidth) + ' px');
- Memo1.lines.Add('Height: ' + IntToStr(VHeight) + ' px');
- Memo1.Lines.Add('FPS: ' + FormatFloat('#.##', fps));
- Memo1.Lines.Add('');
- Memo1.Lines.Add('AUDIO INFORMATION');
- Memo1.Lines.Add('Codec: ' + Acodec);
- Memo1.Lines.Add('Bitrate: ' + Abitrate);
- End;
-
- procedure TForm1.Button1Click(Sender: TObject);
- begin
- If OpenDialog1.Execute Then ReadAviInfo(OpenDialog1.FileName);
- End;
-
- end.
-
-
-
- -------------
- uses
- MPlayer, MMsystem;
-
- type
- EMyMCIException = class(Exception);
- TWavHeader = record
- Marker1: array[0..3] of Char;
- BytesFollowing: Longint;
- Marker2: array[0..3] of Char;
- Marker3: array[0..3] of Char;
- Fixed1: Longint;
- FormatTag: Word;
- Channels: Word;
- SampleRate: Longint;
- BytesPerSecond: Longint;
- BytesPerSample: Word;
- BitsPerSample: Word;
- Marker4: array[0..3] of Char;
- DataBytes: Longint;
- end;
-
- procedure TForm1.Button1Click(Sender: TObject);
- var
- Header: TWavHeader;
- begin
- with TFileStream.Create('C:SomeFile.wav', fmOpenRead) do
- try
- ReadBuffer(Header, SizeOf(Header));
- finally
- Free;
- end;
- ShowMessage(FloatToStr((Int64(1000) * header.DataBytes div header.BytesPerSecond) / 1000));
- end;
-
-
- -------------
- function GetWaveLength(WaveFile: string): Double;
- var
- groupID: array[0..3] of char;
- riffType: array[0..3] of char;
- BytesPerSec: Integer;
- Stream: TFileStream;
- dataSize: Integer;
- // chunk seeking function,
- // -1 means: chunk not found
-
- function GotoChunk(ID: string): Integer;
- var
- chunkID: array[0..3] of char;
- chunkSize: Integer;
- begin
- Result := -1;
-
- with Stream do
- begin
- // index of first chunk
- Position := 12;
- repeat
- // read next chunk
- Read(chunkID, 4);
- Read(chunkSize, 4);
- if chunkID <> ID then
- // skip chunk
- Position := Position + chunkSize;
- until(chunkID = ID) or (Position >= Size);
- if chunkID = ID then
- // chunk found,
- // return chunk size
- Result := chunkSize;
- end;
- end;
-
- begin
- Result := -1;
- Stream := TFileStream.Create(WaveFile, fmOpenRead or fmShareDenyNone);
- with Stream do
- try
- Read(groupID, 4);
- Position := Position + 4; // skip four bytes (file size)
- Read(riffType, 4);
-
- if(groupID = 'RIFF') and (riffType = 'WAVE') then
- begin
- // search for format chunk
- if GotoChunk('fmt') <> -1 then
- begin
- // found it
- Position := Position + 8;
- Read(BytesPerSec, 4);
- //search for data chunk
- dataSize := GotoChunk('data');
-
- if dataSize <> -1 then
- // found it
- Result := dataSize / BytesPerSec
- end
- end
- finally
- Free;
- end;
- end;
-
- function SecondsToTimeStr(RemainingSeconds: Integer): string;
- var
- Hours, Minutes, Seconds: Integer;
- HourString, MinuteString, SecondString: string;
- begin
- // Calculate Minutes
- Seconds := RemainingSeconds mod 60;
- Minutes := RemainingSeconds div 60;
- Hours := Minutes div 60;
- Minutes := Minutes - (Hours * 60);
-
- if Hours < 10 then
- HourString := '0' + IntToStr(Hours) + ':'
- else
- HourString := IntToStr(Hours) + ':';
-
- if Minutes < 10 then
- MinuteString := '0' + IntToStr(Minutes) + ':'
- else
- MinuteString := IntToStr(Minutes) + ':';
-
- if Seconds < 10 then
- SecondString := '0' + IntToStr(Seconds)
- else
- SecondString := IntToStr(Seconds);
- Result := HourString + MinuteString + SecondString;
- end;
- procedure TForm1.Button1Click(Sender: TObject);
- var
- Seconds: Integer;
- begin
- Seconds := Trunc(GetWaveLength(Edit1.Text));
- //gets only the Integer part of the length
- Label1.Caption := SecondsToTimeStr(Seconds);
- end;
- procedure TForm1.Button1Click(Sender: TObject);
- begin
- Label1.Caption := SecondsToTimeStr(Trunc(GetWaveLength(Edit1.Text)));
- end;
-
-
- -------------
- uses
- MPlayer, MMsystem;
-
- type
- EMyMCIException = class(Exception);
- TWavHeader = record
- Marker1: array[0..3] of Char;
- BytesFollowing: Longint;
- Marker2: array[0..3] of Char;
- Marker3: array[0..3] of Char;
- Fixed1: Longint;
- FormatTag: Word;
- Channels: Word;
- SampleRate: Longint;
- BytesPerSecond: Longint;
- BytesPerSample: Word;
- BitsPerSample: Word;
- Marker4: array[0..3] of Char;
- DataBytes: Longint;
- end;
-
- procedure TForm1.Button1Click(Sender: TObject);
- var
- Header: TWavHeader;
- begin
- with TFileStream.Create('C:SomeFile.wav', fmOpenRead) do
- try
- ReadBuffer(Header, SizeOf(Header));
- finally
- Free;
- end;
- ShowMessage(FloatToStr((Int64(1000) * header.DataBytes div header.BytesPerSecond) / 1000));
- end;
 |
Ответ отправил: Feniks (статус: Бакалавр)
Время отправки: 18 ноября 2008, 09:54
|
Мини-форум вопроса
Всего сообщений: 1; последнее сообщение — 18 ноября 2008, 09:45; участников в обсуждении: 1.
|
Вадим К (статус: Академик), 18 ноября 2008, 09:45 [#1]:
Вообще то один формат другому разница и универсального метода нет. Конечно, можно воспользоваться прослойкой, как вы, но она часто добавляет сколько тормозов...
AIMP воспроизводит свои файлы через bass.dll. Поищите описание этой длл и посмотрите на её возможности, может быть хватит.
Вытянуть размер с mp3 файла не сложно. Но не всякий файл, который имеет расширения mp3 им есть. плееры давно научились определять истинное содержимое по заголовку.
Галочка "подтверждения прочтения" - вселенское зло.
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|