PDA

Ver la Versión Completa : acceder a frames de Divx


etruel
22-10-2003, 16:08:56
Hola.
Antes que nada, ME doy la bienvenida en esta magnifica Comunidad de Programadores. Y espero no meter la pata en mi primer post.

He buscado muchisimo por la web y no encontre nada que me lo solucione. Hay multitud de ejemplos, pero andan solo con avi comunes, no con Divx.

Lo que quiero hacer es acceder frame x frame a un Divx y mandarlo a un TBitmap, sin necesidad de reproducirlo.
Esto es para recorrer el video de forma mas rapida que en tiempo real.

Pongo un codigo que "casi" anduvo:
(usando vfw.pas)

AVIFileInit;
// The AVIFileOpen function opens an AVI file
Error := AVIFileOpen(pFile, PChar(FileName), 0, nil);
...
// AVIFileInfo obtains information about an AVI file

if AVIFileInfo(pFile, @AVIINFO, SizeOf(AVIINFO)) <> AVIERR_OK then
...
MediaWidth := AVIINFO.dwWidth;
MediaHeight:= AVIINFO.dwHeight;
MediaFrames:= AVIINFO.dwLength;
MediaScale := AVIINFO.dwScale;

// Open a Stream from the file
Error := AVIFileGetStream(pFile, AVIStream, streamtypeVIDEO, 0);
...
// Prepares to decompress video frames
gapgf := AVIStreamGetFrameOpen(AVIStream, nil);
...
// Read current Frame
// AVIStreamGetFrame Returns the address of a decompressed video frame
lpbi := AVIStreamGetFrame(gapgf, iFrameNum);
...

TmpBmp := TBitmap.Create;
try
TmpBmp.Height := lpbi.biHeight;
TmpBmp.Width := lpbi.biWidth;
bits := Pointer(Integer(lpbi) + SizeOf(TBITMAPINFOHEADER));

DC_Handle := CreateDC('Display', nil, nil, nil);
try
hBmp := CreateDIBitmap(DC_Handle, // handle of device context
lpbi^, // address of bitmap size and format data
CBM_INIT, // initialization flag
bits, // address of initialization data
PBITMAPINFO(lpbi)^, // address of bitmap color-format data
DIB_RGB_COLORS); // color-data usage
finally
DeleteDC(DC_Handle);
end;
TmpBmp.Handle := hBmp;
finally
TmpBmp.Free;
end;


Esto me anda para AVIs comunes pero para videos Divx la linea
gapgf := AVIStreamGetFrameOpen(AVIStream, nil); siempre me devuelve nil, entoces falla el getframe.

Probe tambien el TmediaPlayer y no me reproduce divx.
y probé el DSPack con directshow pero no se como acceder a los frames sin tener que reproducir el video.

¿Alguien me puede dar una mano con esto?
Gracias

etruel
24-10-2003, 15:08:42
¿Ni siquiera un post de bienvenida? :confused:
Bueno, ya lo solucioné.
Gracias a los 4 que por lo menos leyeron el post. ;)
Saludos

SnaKe
24-10-2003, 16:08:09
Hola Etruel,

Antes que nada bienvenido... yo fui uno de los que leyó tu post y no te contesté porque no tenía ni idea, tampoco me fijé que erá tu primer post...

Bueno, me gustaría saber como lo resolviste, la verdad es que me parece muy interesante el tema. Puede poner un mensaje poniendo que componentes y código has utilizado??

Gracias y un saludo.

etruel
24-10-2003, 16:25:32
pero como no!! aca esta el código
Use el Media Detector del Direct Show9. Que aunque creo que no permite acceder frame x frame, pude acceder a segundo x segundo que igual me sirve.



var
Res: HRESULT;
bmih: tagBITMAPINFOHEADER;
hdcDest: HDC;
bmi: tagBITMAPINFO;
Bitmap: HBITMAP;
Size: Integer;
Buffer: array of PChar;
cantstream, actualstream: Integer;
Player: IMediaDet;

Begin
CoCreateInstance(CLSID_MediaDet,nil,CLSCTX_INPROC_SERVER,IID_IMediaDet,Player);
Player.put_Filename(Filename);
Player.get_OutputStreams(CantStream);
Res := Player.GetBitmapBits(ActualSeg, @Size, 0, MediaWidth, MediaHeight);
if Res = S_OK then
begin
SetLength(Buffer, Size);
hdcDest := GetDC(0);

Res := Player.GetBitmapBits(ActualSeg, 0, @Buffer[0], MediaWidth, MediaHeight);

ZeroMemory(@bmi, SizeOf(tagBITMAPINFO));

CopyMemory(@bmih, @Buffer[0], SizeOf(tagBITMAPINFOHEADER));

CopyMemory(@bmi.bmiHeader, @bmih, SizeOf(tagBITMAPINFOHEADER));

Bitmap := CreateDIBitmap(hdcDest, bmih, CBM_INIT, @Buffer[SizeOf(tagBITMAPINFOHEADER)], bmi, DIB_RGB_COLORS);

image1.Picture.Bitmap.Handle := Bitmap;

end;
end;

etruel
24-10-2003, 17:43:39
Otras Preguntas Mas Sencillas
Lo que quiero es poder trabajar con la imagen extraida antes de mostrarla.

Si en vez de hacer esto:
image1.Picture.Bitmap.Handle := Bitmap;

Hago esto:
image1.Picture.Bitmap.Canvas.Handle := Bitmap;

Las preguntas son:
¿Como accedo a los pixels de la imagen extraida en el canvas?
¿Como muestro el canvas luego en image1?

Por ahora se me ocurrió esto. No se si estoy bien orientado.
Si alguien sabe una forma mejor por favor que lo postee
Gracias

SnaKe
27-10-2003, 11:05:16
Hola Etruel,

Lo primero gracias por mostrarnos la solución pero me queda una duda, cuando dices que usas el Media Detector del Direct Show 9 das a entender de que ¿para que ese código funcione es necesario tener DirectX 9 ? igual acabo de preguntar una barbaridad...

Otra cosa, referente a las cuestiones en el mensaje de después del código...

Por que no haces algo así:


var
........
........
Bitmp : TBitmap;
begin
...................... // Tu código pero no asignes al TImage
...................... // sino que haz esto:

Bitmp := TBitmap.Create;
Bitmp.Handle := Bitmap;

// Ahora pintas en el canvas de Bitmp

// Bitmp.Canvas.xxxxxxxxxx

// Y una vez que hayas terminado de pintar se lo asocias al image

Image1.Picture.Bitmap.Assign(Bitmp);



No se si te servirá....

Salu2.

etruel
27-10-2003, 14:11:47
Snake:
En mi equipo tengo instalado el directx 9 no se si andará en otras versiones una vez compilado.
Use las librerias de DirectX para delphi que hay en http://www.progdigy.com.
En esos foros encontre un codigo similar al que usé yo (es decir, me basé en ese código ;) )

Gracias por el código del canvas, algo así habia pensado; aunque sigo buscando una forma mas rapida porque tengo que acceder a cada pixel de la imagen y modificar el color uno por uno.

Saludos
PD: No tengo mucha experiencia en delphi, voy buscando información acerca de lo que quiero hacer.