Log in

View Full Version : Cutting clips from AVI videos


marnix88
28th June 2008, 14:21
Hi, I'd like to create my own small tool for cutting clips from AVI videos. Unfortunately there isn't a lot of information available about the AVI API's. I'm using VB6 (don't flame me please :P).

I have two problems with the code below.

1) The data written to the new file is too large. A frame is for example 14 KiloBytes in size. The frame is written to the new file, but also 1 or 2 MegaBytes of space characters. Then the second frame is written with another 1 or 2 MegaBytes of space characters, etc, etc. A video that normally should be about 5 MegaBytes is now more than 1 GigaByte!

The following array is dimmed too large: ReDim pAVIStreamTmp(bitmapInfo.biSizeImage - 1) As Byte
How do I get the correct size of each compressed frame, so I can redim the array correctly?


2) How do I get the audio as well?
I can get the audio stream with AVIFileGetStream and streamtypeAUDIO, but I don't exactly know how to write both the video and audio to the new file.

Small code samples in C++ are fine too. I don't understand much of it, but the API syntax is the same.


Option Explicit

Public Declare Function AVIFileOpen Lib "avifil32.dll" (pAVIFile As Long, ByVal szFile As String, _
ByVal uMode As Long, ByVal pclsidHandler As Long) As Long 'HRESULT
Private Declare Sub AVIFileInit Lib "avifil32.dll" ()
Private Declare Sub AVIFileExit Lib "avifil32.dll" ()
Private Declare Function AVIFileRelease Lib "avifil32.dll" (ByVal pAVIFile As Long) As Long
Public Declare Function AVIFileGetStream Lib "avifil32.dll" (ByVal pAVIFile As Long, pAVIStream As Long, _
ByVal fccType As Long, ByVal lParam As Long) As Long
Private Declare Function AVIStreamWrite Lib "avifil32.dll" (ByVal pavi As Long, ByVal lStart As Long, _
ByVal lSamples As Long, ByVal lpBuffer As Long, ByVal cbBuffer As Long, ByVal dwFlags As Long, _
ByRef plSampWritten As Long, ByRef plBytesWritten As Long) As Long
Public Declare Function AVIFileCreateStream Lib "avifil32.dll" Alias "AVIFileCreateStreamA" _
(ByVal pAVIFile As Long, pAVIStream As Long, ByRef psi As AVI_STREAM_INFO) As Long
Public Declare Function AVIFileInfo Lib "avifil32.dll" (ByVal pAVIFile As Long, pfi As AVI_FILE_INFO, _
ByVal lSize As Long) As Long 'HRESULT
Public Declare Function AVIStreamInfo Lib "avifil32.dll" (ByVal pAVIStream As Long, _
ByRef pAVIStreamInfo As AVI_STREAM_INFO, ByVal lSize As Long) As Long
Public Declare Function AVIStreamRelease Lib "avifil32.dll" (ByVal pAVIStream As Long) As Long 'ULONG
Public Declare Function AVIStreamClose Lib "avifil32.dll" Alias "AVIStreamRelease" (ByVal pAVIStream As Long) As Long
Public Declare Function AVIStreamSetFormat Lib "avifil32.dll" (ByVal pAVIStream As Long, ByVal lPos As Long, _
ByRef lpFormat As Any, ByVal cbFormat As Long) As Long
Private Declare Function AVIStreamReadFormat Lib "avifil32.dll" (ByVal pAVIStream As Long, ByVal lPos As Long, _
lpFormat As Any, ByRef lpcbFormat As Long) As Long
'Private Declare Function AVIStreamOpenFromFile Lib "avifil32.dll" Alias "AVIStreamOpenFromFileA" _
(pAVIFile As Long, ByVal szFile As String, ByVal fccType As Long, ByVal lParam As Long, _
ByVal mode As Long, pclsidHandler As Any) As Long
Private Declare Function AVIStreamLength Lib "avifil32.dll" (ByVal pAVIStream As Long) As Long
Private Declare Function AVIStreamRead Lib "avifil32.dll" (ByVal pAVIStream As Long, ByVal lStart As Long, _
ByVal lSamples As Long, ByVal lpBuffer As Long, ByVal cbBuffer As Long, _
ByRef pBytesWritten As Long, ByRef pSamplesWritten As Long) As Long
Public Declare Function AVIStreamStart Lib "avifil32.dll" (ByVal pAVIStream As Long) As Long

Global Const AVIIF_KEYFRAME As Long = &H10
Global Const OF_READ As Long = &H0
Global Const OF_WRITE As Long = &H1
Global Const OF_CREATE As Long = &H1000
Global Const AVIERR_OK As Long = 0&
Global Const streamtypeVIDEO As Long = 1935960438 '= mmioStringToFOURCC("vids", 0&)
Global Const streamtypeAUDIO As Long = 1935963489 '= mmioStringToFOURCC("auds", 0&)
Global Const BI_RGB As Long = 0&

Public Type AVI_RECT
left As Long
top As Long
right As Long
bottom As Long
End Type

Public Type AVI_FILE_INFO '108 bytes
dwMaxBytesPerSecond As Long
dwFlags As Long
dwCaps As Long
dwStreams As Long
dwSuggestedBufferSize As Long
dwWidth As Long
dwHeight As Long
dwScale As Long
dwRate As Long
dwLength As Long
dwEditCount As Long
szFileType As String * 64
End Type

Public Type AVI_STREAM_INFO
fccType As Long
fccHandler As Long
dwFlags As Long
dwCaps As Long
wPriority As Integer
wLanguage As Integer
dwScale As Long
dwRate As Long
dwStart As Long
dwLength As Long
dwInitialFrames As Long
dwSuggestedBufferSize As Long
dwQuality As Long
dwSampleSize As Long
rcFrame As AVI_RECT
dwEditCount As Long
dwFormatChangeCount As Long
szName As String * 64
End Type

Private Type TBITMAPINFOHEADER '40 bytes
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type

'Private Type TRGBQUAD
' Red As Byte
' Green As Byte
' Blue As Byte
' Reserved As Byte
'End Type

Dim streamInfo As AVI_STREAM_INFO
Dim bitmapInfo As TBITMAPINFOHEADER
Dim fileInfo As AVI_FILE_INFO

Public Sub LoadAVIFile(szInputAVIFile As String, szOutputAVIFile As String)
Dim pAVIFileIn As Long
Dim pAVIFileOut As Long
Dim pAVIStreamOut As Long
Dim pAVIStreamIn As Long
Dim res As Long
Dim streamLength As Long
Dim i As Long
Dim pAVIStreamTmp() As Byte

AVIFileInit
res = AVIFileOpen(pAVIFileIn, szInputAVIFile, OF_READ, 0) 'open source avi
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIFileOpen(pAVIFileOut, szOutputAVIFile, OF_WRITE Or OF_CREATE, 0) 'open destination avi
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIFileInfo(pAVIFileIn, fileInfo, Len(fileInfo)) 'read source avi info
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIFileGetStream(pAVIFileIn, pAVIStreamIn, streamtypeVIDEO, 0) 'get 1st stream from source avi
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIStreamInfo(pAVIStreamIn, streamInfo, Len(streamInfo)) 'get stream info from source avi
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIFileCreateStream(pAVIFileOut, pAVIStreamOut, streamInfo) 'create a stream in destination avi
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIStreamReadFormat(pAVIStreamIn, 0, bitmapInfo, Len(bitmapInfo))
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIStreamSetFormat(pAVIStreamOut, 0, bitmapInfo, Len(bitmapInfo)) 'set destination avi format
If res <> AVIERR_OK Then GoTo ErrHandler

streamLength = AVIStreamLength(pAVIStreamIn)
Debug.Print streamLength

ReDim pAVIStreamTmp(bitmapInfo.biSizeImage - 1) As Byte

For i = AVIStreamStart(pAVIStreamIn) To AVIStreamLength(pAVIStreamIn)
res = AVIStreamRead(pAVIStreamIn, i, 1, VarPtr(pAVIStreamTmp(i)), bitmapInfo.biSizeImage, 0, 0)
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIStreamWrite(pAVIStreamOut, i, 1, VarPtr(pAVIStreamTmp(i)), bitmapInfo.biSizeImage, AVIIF_KEYFRAME, 0, 0)
If res <> AVIERR_OK Then GoTo ErrHandler
Next i

ErrHandler:
AVIStreamRelease pAVIStreamIn
AVIStreamRelease pAVIStreamOut
AVIFileRelease pAVIFileIn
AVIFileRelease pAVIFileOut
AVIFileExit
End Sub


Here's some code which allows me to extract the audio or the video stream from an AVI , but I don't know how to interleave them. This code also takes the entire stream and won't allow me to cut a piece from it.

Public Sub ExtractAudio(szInputAVIFile As String, szOutputWAV As String)
Dim pAVIFileIn As Long
Dim pAVIStreamIn As Long
Dim res As Long

AVIFileInit
res = AVIFileOpen(pAVIFileIn, szInputAVIFile, OF_READ, 0) 'open source avi
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVIFileGetStream(pAVIFileIn, pAVIStreamIn, streamtypeAUDIO, 0) 'get 1st stream from source avi
If res <> AVIERR_OK Then GoTo ErrHandler

res = AVISave(szOutputWAV, 0&, AddressOf AVISaveCallback, 1, pAVIStreamIn, 0)
If res <> AVIERR_OK Then GoTo ErrHandler

ErrHandler:
AVIStreamRelease pAVIStreamIn
AVIFileRelease pAVIFileIn
AVIFileExit
End Sub

halsboss
17th April 2009, 12:30
How did you go ?

I'm a dinosaur with access to only VB6, doing a similar thing without the API calls, parsing the AVI RIFF document "by hand" according to the specs. The purpose is to get a cut-down mpeg4modifier (--unpack and --pack only) without the .NET stuff which some PCs don't have.

Got the AVI RIFF document parsing going in a console-linked VB6 app; now looking for specs on the XVID video chunk content and the MP3 video chunk content so that I can interpret/rearrange the video frames ... I'll probably have to look at mpeg4modifier C# source, but not being a C# person it's a bit hard and the constructs don't generally translate well into old VB6.

Any pointers much appreciated.