Odczyt nagłówka pliku wideo w Delphi

0

Witam.
Podobne tematy były już poruszane, lecz nie ma wnich odpowiedzi na mój problem.
Próbowałem używać VFW.pas jednak raczej nie o to mi chodzi.
Potrzebuję odczytywać z plików wideo (głównie mpg i avi) dane o rozdzielczości i długości. Porównując nagłówki plików avi stworzyłem procedurę odczytu rozdzielczości i ilości klatek, ale nie mogę wydobyć fps.
Czy może ktoś z Was robił procedurę wydobywania danych z takich plików (docelowo chodzi o avi, mpg, rm i mkv) porównywanie długości i rozdzielczości plików.
Chcę żeby wszysko umieszczone było w moim programie, a nie korzystać z dodatkowych dll.
Przepraszam jeśli mój problem wydaje się banalny, ale pierwszy raz zajmuję się plikami wideo. Propozycja odczytu nagłówka z Długiść filmu (bez MediaPlayer)
powoduje u mnie błąd 998 (Jak się doczytałem jest to No Access - Invalid access to memory location).
Pozdrawiam,
Piotr.

0

W Googlu: nazwa_formatu + "header"

0

Wujka Googla pytałem na początku i z jego rad korzystam.
Ale chodziło mi o poradę od kogoś kto być może to robił, lub kto ma fragment gotowca.

0

Pobierasz kilka bajtów z odpowiedniego offsetu. Takie trudne, że potrzebujesz gotowca?

1

Do wyciągania informacji z pliku video musisz skorzystać z interfejsu IMEDIADET.


Procedure DS_IMediaDet(FileName: WideString);
var MediaDet: IMediaDet; pDur,FPS: double; FrameCount, Seconds: int64;
Count : integer;
 Streams     : Integer;
 StreamType  : TGUID;
begin
  pDur := 0;

  if CoCreateInstance(CLSID_MediaDet, nil, CLSCTX_INPROC_SERVER, IID_IMediaDet,
    MediaDet) = S_OK then
  Begin

FPS := 0.0;


   if MediaDet.put_Filename(FileName) = S_OK then
   Begin
     If (MediaDet.get_OutputStreams(Streams) = S_OK) Then
     Begin
       if MediaDet.get_StreamLength(pDur) <> S_OK then pDur := 0;
       For Count := 0 To (Streams - 1) Do
       Begin
         If (MediaDet.get_StreamType(StreamType) = S_OK) Then
         Begin
             If (MediaDet.get_FrameRate(FPS) = S_OK) Then break; // Framerate 29.97
           End;
         End;
       End;
     End;


  FrameCount := TRUNC(FPS * pDur); //Liczba klatek
  Seconds := TRUNC(pDur);               //dlugosc w sekundach 

  //Tu przekazuje dane do jakiegos rekordu
  {
  Mediainfo.FramesPerSecond := FPS;
  Mediainfo.LengthInSeconds := Seconds;
  Mediainfo.LengthInFrames := FrameCount;
  }


  MediaDet := nil;
  End;

end;
 

Do pobrania rozdzielczosci, typu kodeka i i inych informacji zerknij tu:
http://www.progdigy.com/forums/viewtopic.php?t=1068

1

Tutaj masz bibliotekę do *.avi
http://yaai.sourceforge.net/

0

Tak, masz rację prosto jest wyciągnąć parę bajtów z nagłówka pliku, i tak zrobiłem mam rozdzielczości i ilość klatek.
Lecz nie mogę rozgryźć fps, próbowałem odczytywać dane jako real, single, a nawet word i nic mi nie pasuje do rzeczywistych danych pliku.
Jest to pracochłonne, dlatego pytałem o gotowiec, żeby mieć chociaż offset pliku. W avi i mpg się dogrzebałem, ale nie mam fps i danych do RealMedia i mkv.
Co do porady kolegi entek to jakiego modułu muszę użyć żeby IMediaDet działało?
U mnie
var MediaDet: IMediaDet;
powoduje: E2003 Undeclared identifier: 'IMediaDet', a w helpie nic o tym nie ma.
Jeszcze muszę spróbować porady Młodego (po wycięciu niepotrzebnych mi danych).
Dziękuję za dotychczasową pomoc, na pewno przyda mi się troszkę wiadomości, muszę się tylko przez nie "przegryźć".
Pozdrawiam.

1

Ale marudzisz ten interfejs jest zdefiniowany w module DirectShow9.pas

http://code.google.com/p/dspack/source/browse/trunk/src/DirectX9/DirectShow9.pas?r=7

0

Nom, marudziłem, ale wielkie dzięki za pomoc. Fps i inne odczytuję. Później zobaczę jak pójdzie z mkv.
Pozdrawiam.

0

Witam ponownie.
Czy można i czy warto zainstalować DSPack w RAD XE2? Jeśli tak to które (najnowsze jakie znalazłem jest do Delphi 7)?
Drugie pytanie dotyczy wcześniejszych moich postów. Do odczytu danych pliku wideo używam MediaDet. Jednak czasami podaje mi złe wartości, drugi raz wczytanie tego samego pliku podaje już dobre wartości. Nie mogę znaleźć błedu, gdyż wczytując po kolei np pliki a, b i c raz mam błąd przy pliku c, a po ponownym wczytaniu tej serii nie. Po ponownym uruchomieniu też nie. Wrzucam poniżej moją procedurę, czy jest w niej błąd? Najpierw odczytywałem tylko czas pliku, następnie dorzuciłem rozdzielczości i kodek. Dlaczego rezultat GetStreamMediaType jest raz ok a raz nie?
Proszę o pomoc.

Function Dlugosc(plik:string; var width,height,kdk:longint):double;
var   MediaDet : IMediaDet;
       Streams   : Integer;
       StreamType  : TGUID;
       pDur,FPS : double;
       x     : integer;
      mt    :  AM_MEDIA_TYPE;
      pVih  : ^VIDEOINFOHEADER;
begin
    pDur := 0;
    width:=0; height:=0;kdk:=0;
    if CoCreateInstance(CLSID_MediaDet, nil, CLSCTX_INPROC_SERVER, IID_IMediaDet,
       MediaDet) = S_OK then Begin
       FPS := 0.0;
       if MediaDet.put_Filename(plik) = S_OK then Begin
         If (MediaDet.get_OutputStreams(Streams) = S_OK) Then Begin
            if MediaDet.get_StreamLength(pDur) <> S_OK then pDur := 0;
            For x := 0 To (Streams - 1) Do Begin
               If (MediaDet.get_StreamType(StreamType) = S_OK) Then
                 If (MediaDet.get_FrameRate(FPS) = S_OK) Then break; // Framerate 29.97
            End;
         End;
       End;
//       If (MediaDet.get_StreamMediaType(MT) <> S_OK) then  MediaDet.get_StreamMediaType(MT);
       If (MediaDet.get_StreamMediaType(MT) = S_OK) Then Begin
          if (mt.formattype = FORMAT_VideoInfo) then begin
             pVih := mt.pbFormat;
             width := pVih.bmiHeader.biWidth;
             height := pVih.bmiHeader.biHeight;
             kdk:= pVih.bmiHeader.biCompression;
          end;
       end;
       MediaDet := nil;
    End;
    Dlugosc:=pdur;
end;

P.S.
Sprawdziłem że dwukrotne wywołanie GetStreamMediaType nie rozwiązało problemu, a ponowne wywołanie funkcji daje rezultat.

    dl:=Dlugosc(s,wx,wy,kdk);
    if kdk=0 then dl:=Dlugosc(s,wx,wy,kdk);
1

Czy można i czy warto zainstalować DSPack w RAD XE2?

Czy można ? - Tak.
Czy warto ? - Tak.

Pliki pod Xe2 znajdziesz tu:
https://code.google.com/p/dspack/source/browse/#svn%2Ftrunk

Opis Instalacji:
http://www.progdigy.com/forums/viewtopic.php?t=5000&sid=1f3f41b9863b511a7f0bcc90edba921f

Z mediadet jest problem, że używa systemowych kodeków do odczytywania informacji z plików. Przykładowo u mnie wywala się przy kodeku "Divx Hd", - w ogóle nie czyta informacji o fps.
Nie znalazłem konkretnego sposobu, aby ten filtr działał zawsze prawidłowo.

Ja staram się odczytywać dane przed utworzeniem Graphu, wtedy szanse odczytu są największe. Przy braku danych korzystam z interfejsu IQualProp - odczytuje fps z renderera w trakcie odtwarzania filmu.
A gdy to się nie powiedzie, ustawiam na sztywno 23.97fps i większość napisów leci OK.

Możesz skorzystać z biblioteki MediaInfo, chyba jedyny skuteczny sposób na odczyt parametrów wprost z pliku.
http://mediainfo.svn.sourceforge.net/viewvc/mediainfo/MediaInfoLib/trunk/Project/Delphi/Example/

To tyle na dzisiaj :)

0

Dziękuję za pomoc.
Pozdrawiam.

0

Pobierasz kilka bajtów z odpowiedniego offsetu. Takie trudne, że potrzebujesz gotowca?
plik .AVI ma format RIFF, więc najpierw trzeba by zrobić parser do RIFFa, co takie proste nie jest (RIFF to upraszczając taki binarny XML).

0

@Azarien: Według tego: http://www.fastgraph.com/help/avi_header_format.html można pobrać odstęp między klatkami bezpośrednio z bajtów 32-36.

0

Tak, z początku pobierałem rozdzielczość z offsetów 32 i 36, lecz to dotyczy tylko avi. W przypadku rmvb czy mpg to nie dawało efektu, gdyż dany offset w jednym pliku skutkował a w innym nie. Tak samo długość filmu. Dlatego musiałem szukać innych sposobów. Za pomocą MediaDet udało mi się to w prosty sposób odczytać bez wnikania w typ pliku. Nie jest to ideał, lecz działa. Co do odczytu kodeka to MediaDet podaje "NV12" i dla rmvb i dla mkv.

0
Klakierus napisał(a)

Co do odczytu kodeka to MediaDet podaje "NV12" i dla rmvb i dla mkv.

Dodaj sobie małego Fixa do
Dxsutil.pas

  function GetFOURCC(Fourcc: Cardinal): string;
  type TFOURCC= array[0..3] of AnsiChar;
  var  CC: TFOURCC;
  begin
    case Fourcc of
      0 : result := 'RGB';
      1 : result := 'RLE8';
      2 : result := 'RLE4';
      3 : result := 'BITFIELDS';
      461487720: result :='AVC1';  // I mam Avc1 zamiast nv12 :)
    else
      PDWORD(@CC)^ := Fourcc; // abracadabra
      result := string(CC);            // tu bylo wczesniej       result := CC;
    end;
  end; 

Best Regards.

0

W przypadku rmvb czy mpg to nie dawało efektu, gdyż dany offset w jednym pliku skutkował a w innym nie
To jest właśnie konsekwencja zakładania jakiegoś stałego offsetu, zamiast przeczytania dokumentacji danego formatu pliku.

Źródłem wiedzy jest specyfikacja standardu, nie uproszczona tabelka na Wikipedii czy innej stronce.

1 użytkowników online, w tym zalogowanych: 0, gości: 1