Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 2 097

/ вопрос открыт /

Здравствуйте уважаемые эксперты!

Во время написания видео-аудио проигрывателя столкнулся с такой проблемой,как медленная обработка медиа- файлов(музыка,видео),т.е. определения времени воспроизведения файла, и у меня вопрос:
Если кто знает напишите,как найти в медиа-файле(аудио формат,иль видео формат не важно!!) время воспроизведения видео(или аудио композиции),если сможете,то напишите хотя бы литературу,где написаны,какие байты из медиа-файла даны под информацию о времени проигрывания.
А если предоставите код,то буду просто рад.
А то время опредиления например 1700 файлов составляет 37 секунд,а в AIM'пе всего 5:((,хочу хоть чуть-чуть приблизится к нему)).

Сразу скажу,что определяю время,через DirectShow.

Anatol_rus Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: Anatol_rus (статус: Посетитель)
Вопрос отправлен: 17 ноября 2008, 22:41
Состояние вопроса: открыт, ответов: 1.

Ответ #1. Отвечает эксперт: Feniks

Здравствуйте, Anatol_rus!
Я нашел несколько примеров в приложении:
1. Как прочитать свойства видео файла;
2. Информация о AVI файле, (разбор заголовка AVI);
3. Как определить продолжительность в секундах wav файла.
А по поводу MP3 ищите тут на сайте в вопросах и ответах. Как-то уже выкладывали информацию, как можно прочитать заголовки mp3.

P.S. Желаю удачи.

Приложение:
  1.  
  2. type
  3. TDSMediaInfo = record
  4. SurfaceDesc: TDDSurfaceDesc;
  5. Pitch: integer;
  6. PixelFormat: TPixelFormat;
  7. MediaLength: Int64;
  8. AvgTimePerFrame: Int64;
  9. FrameCount: integer;
  10. Width: integer;
  11. Height: integer;
  12. FileSize: Int64;
  13. end;
  14.  
  15. function GetHugeFileSize(const FileName: string): int64;
  16. var
  17. FileHandle: hFile;
  18. begin
  19. FileHandle := FileOpen(FileName, fmOpenRead or fmShareDenyNone);
  20. try
  21. LARGE_INTEGER(Result).LowPart := GetFileSize(FileHandle, @LARGE_INTEGER(Result).HighPart);
  22. if LARGE_INTEGER(Result).LowPart = $FFFFFFFF then
  23. Win32Check(GetLastError = NO_ERROR);
  24. finally
  25. FileClose(FileHandle);
  26. end;
  27. end;
  28.  
  29. function GetMediaInfo(FileName: WideString): TDSMediaInfo;
  30. var
  31. DirectDraw: IDirectDraw;
  32. AMStream: IAMMultiMediaStream;
  33. MMStream: IMultiMediaStream;
  34. PrimaryVidStream: IMediaStream;
  35. DDStream: IDirectDrawMediaStream;
  36. GraphBuilder: IGraphBuilder;
  37. MediaSeeking: IMediaSeeking;
  38. TimeStart, TimeStop: Int64;
  39. DesiredSurface: TDDSurfaceDesc;
  40. DDSurface: IDirectDrawSurface;
  41. begin
  42. if FileName = '' then
  43. raise Exception.Create('No File Name Specified');
  44. OleCheck(DirectDrawCreate(nil, DirectDraw, nil));
  45. DirectDraw.SetCooperativeLevel(GetDesktopWindow(), DDSCL_NORMAL);
  46. Result.FileSize := GetHugeFileSize(FileName);
  47. AMStream := IAMMultiMediaStream(CreateComObject(CLSID_AMMultiMediaStream));
  48. OleCheck(AMStream.Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, nil));
  49. OleCheck(AMStream.AddMediaStream(DirectDraw, MSPID_PrimaryVideo, 0, IMediaStream(nil^)));
  50. OleCheck(AMStream.OpenFile(PWideChar(FileName), AMMSF_NOCLOCK));
  51. AMStream.GetFilterGraph(GraphBuilder);
  52. MediaSeeking := GraphBuilder as IMediaSeeking;
  53. MediaSeeking.GetDuration(Result.MediaLength);
  54. MMStream := AMStream as IMultiMediaStream;
  55. OleCheck(MMStream.GetMediaStream(MSPID_PrimaryVideo, PrimaryVidStream));
  56. DDStream := PrimaryVidStream as IDirectDrawMediaStream;
  57. DDStream.GetTimePerFrame(Result.AvgTimePerFrame);
  58. {Result.FrameCount := Result.MediaLength div Result.AvgTimePerFrame;}
  59. { TODO : Test for better accuracy }
  60. Result.FrameCount := Round(Result.MediaLength / Result.AvgTimePerFrame);
  61. Result.MediaLength := Result.FrameCount * Result.AvgTimePerFrame;
  62. ZeroMemory(@DesiredSurface, SizeOf(DesiredSurface));
  63. DesiredSurface.dwSize := Sizeof(DesiredSurface);
  64. OleCheck(DDStream.GetFormat(TDDSurfaceDesc(nil^), IDirectDrawPalette(nil^),
  65. DesiredSurface, DWord(nil^)));
  66. Result.SurfaceDesc := DesiredSurface;
  67. DesiredSurface.ddsCaps.dwCaps := DesiredSurface.ddsCaps.dwCaps or
  68. DDSCAPS_OFFSCREENPLAIN or DDSCAPS_SYSTEMMEMORY;
  69. DesiredSurface.dwFlags := DesiredSurface.dwFlags or DDSD_CAPS or DDSD_PIXELFORMAT;
  70. {Create a surface here to get vital statistics}
  71. OleCheck(DirectDraw.CreateSurface(DesiredSurface, DDSurface, nil));
  72. OleCheck(DDSurface.GetSurfaceDesc(DesiredSurface));
  73. Result.Pitch := DesiredSurface.lPitch;
  74. if DesiredSurface.ddpfPixelFormat.dwRGBBitCount = 24 then
  75. Result.PixelFormat := pf24bit
  76. else if DesiredSurface.ddpfPixelFormat.dwRGBBitCount = 32 then
  77. Result.PixelFormat := pf32bit;
  78. Result.Width := DesiredSurface.dwWidth;
  79. Result.Height := DesiredSurface.dwHeight;
  80. end;
  81.  
  82.  
  83. unit Unit1;
  84.  
  85. interface
  86.  
  87. uses
  88. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  89. Dialogs, StdCtrls;
  90.  
  91. Type
  92. TForm1 = class(TForm)
  93. Memo1: TMemo;
  94. OpenDialog1: TOpenDialog;
  95. Button1: TButton;
  96. procedure Button1Click(Sender: TObject);
  97. Public
  98. procedure ReadAviInfo(FileName: String);
  99. End;
  100.  
  101. var
  102. Form1: TForm1;
  103.  
  104. implementation
  105.  
  106. {$R *.dfm}
  107.  
  108. procedure TForm1.ReadAviInfo(FileName: String);
  109. var
  110.  
  111.  
  112.  
  113. Aviheadersize: Integer;
  114. Vheadersize: Integer;
  115. Aviheaderstart: Integer;
  116. Vheaderstart: Integer;
  117. Aheaderstart: Integer;
  118. Astrhsize: Integer;
  119.  
  120.  
  121. TempTest: String[5];
  122. TempSize: Integer;
  123. TempVcodec: String[5];
  124. TempAcodec: Integer;
  125. TempMicrosec: Integer;
  126. TempLengthInFrames: Integer;
  127. TempAchannels: Integer;
  128. TempAsamplerate: Integer;
  129. TempAbitrate: Integer;
  130.  
  131.  
  132. Size: Double;
  133. Length: String;
  134. Vcodec: String;
  135. Vbitrate: Double;
  136. VWidth: Integer;
  137. VHeight: Integer;
  138. Fps: Double;
  139.  
  140. LengthInSec: Double;
  141. Acodec: String;
  142. Abitrate: String;
  143. begin
  144.  
  145. iFileHandle := FileOpen(FileName, fmOpenRead);
  146.  
  147.  
  148. FileSeek(iFileHandle, 7, 0);
  149. FileRead(iFileHandle, TempTest, 5);
  150. If copy(TempTest, 0, 4) <> 'AVI ' then
  151. begin
  152. MessageDlg('Could not open ' + FileName + ' because it is not a valid video file', mtError, [mbOk], 0);
  153. Exit;
  154. End;
  155.  
  156.  
  157. FileSeek(iFileHandle,4,0);
  158. FileRead(iFileHandle, TempSize, 4);
  159.  
  160.  
  161. FileSeek(iFileHandle,28,0);
  162. FileRead(iFileHandle, Aviheadersize, 4);
  163.  
  164.  
  165. Aviheaderstart := 32;
  166.  
  167.  
  168. FileSeek(iFileHandle,Aviheaderstart,0);
  169. FileRead(iFileHandle, TempMicrosec, 4);
  170.  
  171.  
  172. FileSeek(iFileHandle,Aviheaderstart + 16,0);
  173. FileRead(iFileHandle, TempLengthInFrames, 4);
  174.  
  175.  
  176. FileSeek(iFileHandle,Aviheaderstart + 32,0);
  177. FileRead(iFileHandle, VWidth, 4);
  178.  
  179.  
  180. FileSeek(iFileHandle,Aviheaderstart + 36,0);
  181. FileRead(iFileHandle, VHeight, 4);
  182.  
  183. FileSeek(iFileHandle,Aviheaderstart + Aviheadersize + 4,0);
  184. FileRead(iFileHandle, Vheadersize, 4);
  185.  
  186. Vheaderstart := Aviheaderstart + Aviheadersize + 20;
  187.  
  188.  
  189. FileSeek(iFileHandle,Vheaderstart + 3,0);
  190. FileRead(iFileHandle, TempVCodec, 5);
  191.  
  192. Aheaderstart := Vheaderstart + Vheadersize + 8;
  193.  
  194. FileSeek(iFileHandle,Aheaderstart - 4,0);
  195. FileRead(iFileHandle, Astrhsize, 5);
  196.  
  197. // Audio codec
  198. FileSeek(iFileHandle,Aheaderstart + Astrhsize + 8,0);
  199. FileRead(iFileHandle, TempACodec, 2);
  200.  
  201.  
  202. FileSeek(iFileHandle,Aheaderstart + Astrhsize + 10,0);
  203. FileRead(iFileHandle, TempAchannels, 2);
  204.  
  205. // Audio samplerate
  206. FileSeek(iFileHandle,Aheaderstart + Astrhsize + 12,0);
  207. FileRead(iFileHandle, TempAsamplerate, 4);
  208.  
  209. // Audio bitrate
  210. FileSeek(iFileHandle,Aheaderstart + Astrhsize + 16,0);
  211. FileRead(iFileHandle, TempAbitrate, 4);
  212.  
  213.  
  214. FileClose(iFileHandle);
  215.  
  216.  
  217. Vcodec := copy(TempVcodec, 0, 4);
  218. If Vcodec = 'div2' then Vcodec := 'MS MPEG4 v2'
  219. Else If Vcodec = 'DIV2' then Vcodec := 'MS MPEG4 v2'
  220. Else If Vcodec = 'div3' then Vcodec := 'DivX;-) MPEG4 v3'
  221. Else If Vcodec = 'DIV3' then Vcodec := 'DivX;-) MPEG4 v3'
  222. Else If Vcodec = 'div4' then Vcodec := 'DivX;-) MPEG4 v4'
  223. Else If Vcodec = 'DIV4' then Vcodec := 'DivX;-) MPEG4 v4'
  224. Else If Vcodec = 'div5' then Vcodec := 'DivX;-) MPEG4 v5'
  225. Else If Vcodec = 'DIV5' then Vcodec := 'DivX;-) MPEG4 v5'
  226. Else If Vcodec = 'divx' then Vcodec := 'DivX 4'
  227. Else If Vcodec = 'mp43' then Vcodec := 'Microcrap MPEG4 v3';
  228.  
  229.  
  230. Case TempAcodec of
  231. 0: Acodec := 'PCM';
  232. 1: Acodec := 'PCM';
  233. 85: Acodec := 'MPEG Layer 3';
  234. 353: Acodec := 'DivX;-) Audio';
  235. 8192: Acodec := 'AC3-Digital';
  236. Else
  237. Acodec := 'Unknown (' + IntToStr(TempAcodec) + ')';
  238. End;
  239.  
  240. Case (Trunc(TempAbitrate / 1024 * 8)) of
  241. 246..260: Abitrate := '128 Kbit/s';
  242. 216..228: Abitrate := '128 Kbit/s';
  243. 187..196: Abitrate := '128 Kbit/s';
  244. 156..164: Abitrate := '128 Kbit/s';
  245. 124..132: Abitrate := '128 Kbit/s';
  246. 108..116: Abitrate := '128 Kbit/s';
  247. 92..100: Abitrate := '128 Kbit/s';
  248. 60..68: Abitrate := '128 Kbit/s';
  249. Else
  250. Abitrate := FormatFloat('# Kbit/s', TempAbitrate / 1024 * 8);
  251. End;
  252.  
  253.  
  254. Size := TempSize / 1024 / 1024;
  255. Fps := 1000000 / TempMicrosec; // FPS
  256. LengthInSec := TempLengthInFrames / fps; // Length In seconds
  257. Length := FormatFloat('# min', Int(LengthInSec / 60)) + FormatFloat(' # sec',
  258. Round(LengthInSec - (Int(LengthInSec / 60) * 60)));
  259. Vbitrate := (TempSize / LengthInSec - TempABitrate) / 1024 * 8;
  260.  
  261.  
  262. Memo1.Lines.Add('AVI INFORMATION');
  263. Memo1.lines.Add('Size: ' + FormatFloat('#.## MB',Size));
  264. Memo1.Lines.Add('Length: ' + Length);
  265. Memo1.Lines.Add('');
  266. Memo1.Lines.Add('VIDEO INFORMATION');
  267. Memo1.Lines.Add('Codec: ' + Vcodec);
  268. Memo1.Lines.Add('Bitrate: ' + FormatFloat('# Kbit/s', Vbitrate));
  269. Memo1.lines.Add('Width: ' + IntToStr(VWidth) + ' px');
  270. Memo1.lines.Add('Height: ' + IntToStr(VHeight) + ' px');
  271. Memo1.Lines.Add('FPS: ' + FormatFloat('#.##', fps));
  272. Memo1.Lines.Add('');
  273. Memo1.Lines.Add('AUDIO INFORMATION');
  274. Memo1.Lines.Add('Codec: ' + Acodec);
  275. Memo1.Lines.Add('Bitrate: ' + Abitrate);
  276. End;
  277.  
  278. procedure TForm1.Button1Click(Sender: TObject);
  279. begin
  280. If OpenDialog1.Execute Then ReadAviInfo(OpenDialog1.FileName);
  281. End;
  282.  
  283. end.
  284.  
  285.  
  286.  
  287. -------------
  288. uses
  289. MPlayer, MMsystem;
  290.  
  291. type
  292. EMyMCIException = class(Exception);
  293. TWavHeader = record
  294. Marker1: array[0..3] of Char;
  295. BytesFollowing: Longint;
  296. Marker2: array[0..3] of Char;
  297. Marker3: array[0..3] of Char;
  298. Fixed1: Longint;
  299. FormatTag: Word;
  300. Channels: Word;
  301. SampleRate: Longint;
  302. BytesPerSecond: Longint;
  303. BytesPerSample: Word;
  304. BitsPerSample: Word;
  305. Marker4: array[0..3] of Char;
  306. DataBytes: Longint;
  307. end;
  308.  
  309. procedure TForm1.Button1Click(Sender: TObject);
  310. var
  311. Header: TWavHeader;
  312. begin
  313. with TFileStream.Create('C:SomeFile.wav', fmOpenRead) do
  314. try
  315. ReadBuffer(Header, SizeOf(Header));
  316. finally
  317. Free;
  318. end;
  319. ShowMessage(FloatToStr((Int64(1000) * header.DataBytes div header.BytesPerSecond) / 1000));
  320. end;
  321.  
  322.  
  323. -------------
  324. function GetWaveLength(WaveFile: string): Double;
  325. var
  326. groupID: array[0..3] of char;
  327. riffType: array[0..3] of char;
  328. BytesPerSec: Integer;
  329. Stream: TFileStream;
  330. dataSize: Integer;
  331. // chunk seeking function,
  332. // -1 means: chunk not found
  333.  
  334. function GotoChunk(ID: string): Integer;
  335. var
  336. chunkID: array[0..3] of char;
  337. chunkSize: Integer;
  338. begin
  339. Result := -1;
  340.  
  341. with Stream do
  342. begin
  343. // index of first chunk
  344. Position := 12;
  345. repeat
  346. // read next chunk
  347. Read(chunkID, 4);
  348. Read(chunkSize, 4);
  349. if chunkID <> ID then
  350. // skip chunk
  351. Position := Position + chunkSize;
  352. until(chunkID = ID) or (Position >= Size);
  353. if chunkID = ID then
  354. // chunk found,
  355. // return chunk size
  356. Result := chunkSize;
  357. end;
  358. end;
  359.  
  360. begin
  361. Result := -1;
  362. Stream := TFileStream.Create(WaveFile, fmOpenRead or fmShareDenyNone);
  363. with Stream do
  364. try
  365. Read(groupID, 4);
  366. Position := Position + 4; // skip four bytes (file size)
  367. Read(riffType, 4);
  368.  
  369. if(groupID = 'RIFF') and (riffType = 'WAVE') then
  370. begin
  371. // search for format chunk
  372. if GotoChunk('fmt') <> -1 then
  373. begin
  374. // found it
  375. Position := Position + 8;
  376. Read(BytesPerSec, 4);
  377. //search for data chunk
  378. dataSize := GotoChunk('data');
  379.  
  380. if dataSize <> -1 then
  381. // found it
  382. Result := dataSize / BytesPerSec
  383. end
  384. end
  385. finally
  386. Free;
  387. end;
  388. end;
  389.  
  390. function SecondsToTimeStr(RemainingSeconds: Integer): string;
  391. var
  392. Hours, Minutes, Seconds: Integer;
  393. HourString, MinuteString, SecondString: string;
  394. begin
  395. // Calculate Minutes
  396. Seconds := RemainingSeconds mod 60;
  397. Minutes := RemainingSeconds div 60;
  398. Hours := Minutes div 60;
  399. Minutes := Minutes - (Hours * 60);
  400.  
  401. if Hours < 10 then
  402. HourString := '0' + IntToStr(Hours) + ':'
  403. else
  404. HourString := IntToStr(Hours) + ':';
  405.  
  406. if Minutes < 10 then
  407. MinuteString := '0' + IntToStr(Minutes) + ':'
  408. else
  409. MinuteString := IntToStr(Minutes) + ':';
  410.  
  411. if Seconds < 10 then
  412. SecondString := '0' + IntToStr(Seconds)
  413. else
  414. SecondString := IntToStr(Seconds);
  415. Result := HourString + MinuteString + SecondString;
  416. end;
  417. procedure TForm1.Button1Click(Sender: TObject);
  418. var
  419. Seconds: Integer;
  420. begin
  421. Seconds := Trunc(GetWaveLength(Edit1.Text));
  422. //gets only the Integer part of the length
  423. Label1.Caption := SecondsToTimeStr(Seconds);
  424. end;
  425. procedure TForm1.Button1Click(Sender: TObject);
  426. begin
  427. Label1.Caption := SecondsToTimeStr(Trunc(GetWaveLength(Edit1.Text)));
  428. end;
  429.  
  430.  
  431. -------------
  432. uses
  433. MPlayer, MMsystem;
  434.  
  435. type
  436. EMyMCIException = class(Exception);
  437. TWavHeader = record
  438. Marker1: array[0..3] of Char;
  439. BytesFollowing: Longint;
  440. Marker2: array[0..3] of Char;
  441. Marker3: array[0..3] of Char;
  442. Fixed1: Longint;
  443. FormatTag: Word;
  444. Channels: Word;
  445. SampleRate: Longint;
  446. BytesPerSecond: Longint;
  447. BytesPerSample: Word;
  448. BitsPerSample: Word;
  449. Marker4: array[0..3] of Char;
  450. DataBytes: Longint;
  451. end;
  452.  
  453. procedure TForm1.Button1Click(Sender: TObject);
  454. var
  455. Header: TWavHeader;
  456. begin
  457. with TFileStream.Create('C:SomeFile.wav', fmOpenRead) do
  458. try
  459. ReadBuffer(Header, SizeOf(Header));
  460. finally
  461. Free;
  462. end;
  463. ShowMessage(FloatToStr((Int64(1000) * header.DataBytes div header.BytesPerSecond) / 1000));
  464. end;


Ответ отправил: Feniks (статус: Бакалавр)
Время отправки: 18 ноября 2008, 09:54


Мини-форум вопроса

Всего сообщений: 1; последнее сообщение — 18 ноября 2008, 09:45; участников в обсуждении: 1.
Вадим К

Вадим К (статус: Академик), 18 ноября 2008, 09:45 [#1]:

Вообще то один формат другому разница и универсального метода нет. Конечно, можно воспользоваться прослойкой, как вы, но она часто добавляет сколько тормозов...
AIMP воспроизводит свои файлы через bass.dll. Поищите описание этой длл и посмотрите на её возможности, может быть хватит.
Вытянуть размер с mp3 файла не сложно. Но не всякий файл, который имеет расширения mp3 им есть. плееры давно научились определять истинное содержимое по заголовку.
Галочка "подтверждения прочтения" - вселенское зло.

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:43
Выполнено за 0.03 сек.