Práce s videem ve Win32 API

Cvičení MUL č.3 - Práce s videem ve Win32 API

mul-cv3.cpp
/*
  Cvičení MUL č.3 - Práce s videem ve Win32 API
 
  Kostra programu:
  ----------------
  - umožňuje otevřít a zavřít avi soubor (proměnná AVIFile)
  - zobrazuje do okna obsah bitmapy uložené v proměnné Frame,
    funkcí SetOutputWindowSize lze nastavit velikost tohoto okna
  - pomocí scrollbaru a šipek vleve a vpravo lze vybrat snímek,
    který se zobrazuje do okna, funkcí ScrollBarSet lze nastavit
    minimalní a maximalní hodnotu scrollbaru
  - zobrazuje listbox do kterého je možné vložit řádek funkcí ListBoxAdd
    a který lze smazat funkcí ListBoxClear
  - funkcí ShowMessage je možné zobrazit okno se zprávou
  - tlačítkem Save lze uložit avi soubor s vybranou kompresí
 
  Úkol:
  -----
  0. Ve funkci DispayAVIFormat vložit kód pro zobrazení informací o avi souboru
     (minimálně rozlišení, framerate, délku) do připraveného listboxu (AVIFileInfo).
  1. Do funkce OpenAVI dodělat otevření video streamu (AVIFileGetStream)
     a do funkce CloseAVI (AVIStreamRelease) uzavření video streamu.
  2. Ve funkci DispayAVIFormat zobrazit informace a o video streamu (AVIStreamInfo).
  3. Do funkce OpenAVI dodělat nastavení velikosti okna pro bitmapu a mezí
     scrollbaru pro výběr snímku podle informací získaných z avi souboru.
  4. Do funkcí OpenAVI a CloseAVI přidat kód pro otevření a uzavření
     dekompresoru snímků (AVIStreamGetFrameOpen a AVIStreamGetFrameClose).
  5. Přidat načtení framu ze streamu do funkce DisplayAVIFrame (AVIStreamGetFrame).
  6. Prostudovat funkci SaveAVI, která ukládá otevřený video stream do nového
     souboru s vybranou kompresí.
  7. Přidat otevírání a uzavírání audio streamu a zobrazení informací o zvukovém
     formátu (počet kanálů, vzorkovací kmitočet).
(8.) Aplikace filtru z předchozího cvičení na jednotlivé zobrazované framy. (DONE)
 
  Pište vlastní kód jen do vyznačených oblastí.
*/
 
#include <windows.h>
#include <vfw.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
 
#ifndef max
#define max(a,b)			(((a) > (b)) ? (a) : (b))
#endif
 
#ifndef min
#define min(a,b)			(((a) < (b)) ? (a) : (b))
#endif
 
// velikost okna framu
#define	WS	256
#define	HS	256
// velikost okna
#define W_WS	WS+272
#define W_HS	HS+48
 
// ridici prvky okna
#define	IDC_BMP				101
#define	IDC_BUTTON_OPEN		102
#define	IDC_BUTTON_CLOSE	103
#define	IDC_BUTTON_SAVE		104
#define	IDC_LIST_BOX_INFO	105
#define	IDC_SCROLL_POSITION	106
 
//------------------------------------------------------------------------------
// prototypy
void	OpenWindow(char *);
void	OnCreate(HWND);
void	OnPaint(HWND);
LRESULT	CALLBACK MainWindowProc(HWND, UINT, WPARAM, LPARAM);
// pomocne funkce
void ShowMessage(const char *Message, ...);
void ListBoxAdd(const char *str, ...);
void ListBoxClear();
void ScrollBarSet(int Min, int Max);
void SetOutputWindowSize(int w, int h);
// funkce pro praci s avi
void DispayAVIFormat();
void OpenAVI(const char *FileName);
void CloseAVI();
void DisplayAVIFrame(unsigned int Position);
void SaveAVI(const char *FileName);
 
//------------------------------------------------------------------------------
HWND hwndMain;
HINSTANCE hInstance;
 
PAVIFILE AVIFile = NULL;
PAVISTREAM VideoStream = NULL,
           AudioStream = NULL;
PGETFRAME GetFrame = NULL;
BITMAPINFO *Frame = NULL;
 
//------------------------------------------------------------------------------
// jadro aplikace
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
// zacatek programu
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	AVIFileInit();
 
	MSG	msg;
	hInstance = hInst;
	OpenWindow("Cvičení MUL č.3 - Práce s videem ve Win32 API");
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	CloseAVI();
 
	AVIFileExit();
	return 0;
}
 
//------------------------------------------------------------------------------
// otevreni okna aplikace
void OpenWindow(char *capture)
{
	ATOM 		atom;
	WNDCLASS 	wc;
 
	wc.style = CS_HREDRAW|CS_VREDRAW;
	wc.lpfnWndProc = MainWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = (HICON)LoadIcon(hInstance, IDI_APPLICATION);
	wc.hCursor = (HCURSOR)LoadCursor(hInstance, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "MAINWINDOW";
	if ((atom = RegisterClass(&wc)) == 0)
	{
		ShowMessage("Nelze vytvořit třídu okna!");
	}
	if ((hwndMain = CreateWindow("MAINWINDOW", capture,
					WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
					W_WS, W_HS, NULL, NULL, hInstance, NULL)) == NULL)
	{
		ShowMessage("Nelze vytvořit okno!");
	}
	ShowWindow(hwndMain, SW_SHOWDEFAULT);
	UpdateWindow(hwndMain);
}
 
//------------------------------------------------------------------------------
// obsluha zprav
LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	char FileName[1024] = {0};
	OPENFILENAME ofn;
 
	switch (uMsg)
	{
	case WM_CREATE:
		OnCreate(hwnd);
		break;
 
	case WM_PAINT:
		break;
 
	case WM_DRAWITEM:
		if ((UINT)wParam == IDC_BMP)
		{
			OnPaint(((LPDRAWITEMSTRUCT)lParam)->hwndItem);
		}
		break;
 
	case WM_CLOSE:
		DestroyWindow(hwndMain);
		break;
 
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
 
	case WM_COMMAND:
		switch (GetDlgCtrlID((HWND)lParam))
		{
		case IDC_BUTTON_OPEN:
			memset(&ofn, 0, sizeof(ofn));
			ofn.lStructSize = sizeof(ofn);
			ofn.hwndOwner = hwnd;
			ofn.lpstrFilter = "AVI Files\0*.avi\0";
			ofn.lpstrFile = FileName;
			ofn.nMaxFile = sizeof(FileName);
			ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
			if (GetOpenFileName(&ofn))
			{
				OpenAVI(FileName);
			}
			DispayAVIFormat();
			break;
 
		case IDC_BUTTON_CLOSE:
			CloseAVI();
			DispayAVIFormat();
			break;
 
		case IDC_BUTTON_SAVE:
			memset(&ofn, 0, sizeof(ofn));
			ofn.lStructSize = sizeof(ofn);
			ofn.hwndOwner = hwnd;
			ofn.lpstrFilter = "AVI Files\0*.avi\0";
			ofn.lpstrFile = FileName;
			ofn.lpstrDefExt = "avi";
			ofn.nMaxFile = sizeof(FileName);
			ofn.Flags = OFN_PATHMUSTEXIST;
			if (GetSaveFileName(&ofn))
			{
				SaveAVI(FileName);
			}
			break;
		}
		break;
 
	case WM_HSCROLL:
		switch (GetDlgCtrlID((HWND)lParam))
		{
		case IDC_SCROLL_POSITION:
			if (LOWORD(wParam)==SB_THUMBTRACK ||
				LOWORD(wParam)==SB_THUMBPOSITION  /*LOWORD(wParam)==SB_ENDSCROLL*/)
			{
				SCROLLINFO si;
				si.cbSize = sizeof(SCROLLINFO);
				si.fMask = SIF_ALL;
				GetScrollInfo((HWND)lParam, SB_CTL, &si);
				SetScrollPos((HWND)lParam, SB_CTL, si.nTrackPos, TRUE);
				DisplayAVIFrame(si.nTrackPos);
			}
			break;
		}
		break;
 
	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_LEFT:
		case VK_RIGHT:
			HWND hwnd = GetDlgItem(hwndMain, IDC_SCROLL_POSITION);
			SCROLLINFO si;
			si.cbSize = sizeof(SCROLLINFO);
			si.fMask = SIF_ALL;
			GetScrollInfo(hwnd, SB_CTL, &si);
			int NewPos = si.nPos;
			if (wParam == VK_RIGHT)
			{
				NewPos++;
			}
			else
			{
				NewPos--;
			}
			NewPos = max(min(NewPos, si.nMax), si.nMin);
			SetScrollPos(hwnd, SB_CTL, NewPos, TRUE);
			DisplayAVIFrame(NewPos);
			break;
		}
		break;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
 
//------------------------------------------------------------------------------
// vytvoreni prvku okna
void OnCreate(HWND hwnd)
{
	CreateWindow("STATIC", NULL, WS_BORDER | WS_VISIBLE | WS_CHILD | SS_OWNERDRAW,
			253, 10, WS + 2, HS + 2, hwnd, (HMENU)IDC_BMP,
			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
	CreateWindow("BUTTON", "Open", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
			10, 10, 50, 20, hwnd, (HMENU)IDC_BUTTON_OPEN,
			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
	CreateWindow("BUTTON", "Close", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
			70, 10, 50, 20, hwnd, (HMENU)IDC_BUTTON_CLOSE,
			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
	CreateWindow("BUTTON", "Save", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
			130, 10, 50, 20, hwnd, (HMENU)IDC_BUTTON_SAVE,
			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
	CreateWindow("SCROLLBAR", NULL, WS_VISIBLE | WS_CHILD | SBS_HORZ,
			10, 40, 230, 20, hwnd, (HMENU)IDC_SCROLL_POSITION,
			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
	CreateWindow("LISTBOX", NULL, WS_BORDER | WS_VISIBLE | WS_CHILD | WS_HSCROLL | WS_VSCROLL,
			10, 70, 230, 150, hwnd, (HMENU)IDC_LIST_BOX_INFO,
			(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
}
 
//------------------------------------------------------------------------------
// zobrazeni framu
void OnPaint(HWND hwnd)
{
	RECT r;
	if (GetWindowRect(hwnd, &r))
	{
		long w = r.right - r.left - 2;
		long h = r.bottom - r .top - 2;
		HDC hdc = GetDC(hwnd);
		BeginPaint(hwnd, NULL);
		if (Frame != NULL)
		{
			SetDIBitsToDevice(hdc, 0, 0, min(w, Frame->bmiHeader.biWidth),
					min(h, Frame->bmiHeader.biHeight), 0, 0, 0,
					min(h, Frame->bmiHeader.biHeight),
					(char*)Frame + Frame->bmiHeader.biSize + Frame->bmiHeader.biClrUsed * sizeof(RGBQUAD),
					Frame, 0);
		}
		else
		{
			RECT fr;
			SetRect(&fr, 0, 0, w, h);
			FillRect(hdc, &fr, (HBRUSH)(COLOR_BTNFACE + 1));
		}
		EndPaint(hwnd, NULL);
		ReleaseDC(hwnd, NULL);
	}
}
 
//------------------------------------------------------------------------------
// pomocne funkce
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
// zobrazeni okna se zpravou
void ShowMessage(const char *Message, ...)
{
	char buffer[1024];
	va_list ap;
	va_start(ap, Message);
	vsnprintf(buffer, sizeof(buffer), Message, ap);
	va_end(ap);
	MessageBox(hwndMain, (LPCTSTR)buffer, "Message", MB_OK);
}
 
//------------------------------------------------------------------------------
// vymazani listboxu
void ListBoxClear()
{
	SendMessage(GetDlgItem(hwndMain, IDC_LIST_BOX_INFO), LB_RESETCONTENT, 0, 0);
}
 
//------------------------------------------------------------------------------
// vlazeni radku do listboxu
void ListBoxAdd(const char *str, ...)
{
	char buffer[1024];
	va_list ap;
	va_start(ap, str);
	vsnprintf(buffer, sizeof(buffer), str, ap);
	va_end(ap);
	SendMessage(GetDlgItem(hwndMain, IDC_LIST_BOX_INFO), LB_ADDSTRING, 0, (int)buffer);
}
 
//------------------------------------------------------------------------------
// nastaveni mezi scrollbaru
void ScrollBarSet(int Min, int Max)
{
	HWND hwnd = GetDlgItem(hwndMain, IDC_SCROLL_POSITION);
	SetScrollRange(hwnd, SB_CTL, Min, Max, TRUE);
	SetScrollPos(hwnd, SB_CTL, Min, TRUE);
}
 
//------------------------------------------------------------------------------
// nastaveni veliskoti okna pro zobrazeni framu
void SetOutputWindowSize(int w, int h)
{
	SetWindowPos(GetDlgItem(hwndMain, IDC_BMP), NULL, 0, 0, w + 2, h + 2, SWP_NOMOVE|SWP_NOZORDER);
	SetWindowPos(hwndMain, NULL, 0, 0, max(272 + w, WS) , max(h + 48, HS), SWP_NOMOVE|SWP_NOZORDER);
}
 
//------------------------------------------------------------------------------
// funkce pro praci s avi
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
void OpenAVI(const char *FileName)
{
	CloseAVI();
	int hr = AVIFileOpen(&AVIFile, FileName, OF_READ, 0L);
	if (hr == 0)
	{
		/*
		 * 1. bod úkolu
		 * otevření video streamu
		 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
		AVIFileGetStream(AVIFile, &VideoStream, streamtypeVIDEO, 0);
		AVIFileGetStream(AVIFile, &AudioStream, streamtypeAUDIO, 0);
		/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
 
		/*
		 * 4. bod úkolu
		 * načtení dekompresoru snímků
		 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
		GetFrame = AVIStreamGetFrameOpen(VideoStream, NULL);	//FIXME Funguje jen na nekomprimovane snimky (Wine?)
		//if (GetFrame == NULL) fprintf(stderr, "GetFrame!\n");
		/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
 
		/*
		 * 7. bod úkolu
		 * otevření audio streamu
		 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
 
		/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
	}
	else
	{
		ShowMessage("Nepodarilo se otevrit soubor!\nChyba %d.", hr);
	}
 
	/*
	 * 3. bod úkolu
	 * změna velikosti okna pro zobrazení snímku a rozsahu slideru
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
	if (VideoStream) {
		AVISTREAMINFO psi;
		AVIStreamInfo(VideoStream, &psi, sizeof(psi));
		SetOutputWindowSize(abs(psi.rcFrame.right - psi.rcFrame.left), abs(psi.rcFrame.bottom - psi.rcFrame.top));
		ScrollBarSet(psi.dwStart, psi.dwLength - 1);
	}
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
 
	DisplayAVIFrame(0);
}
 
//------------------------------------------------------------------------------
void CloseAVI()
{
	/*
	 * 4. bod úkolu
	 * uzavření dekompresoru snímků
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
	AVIStreamGetFrameClose(GetFrame);
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
 
	/*
	 * 1. bod úkolu
	 * uzabření video streamu
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
	if (VideoStream != NULL) {
		AVIStreamRelease(VideoStream);
	}
	if (AudioStream != NULL) {
		AVIStreamRelease(AudioStream);
	}
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
 
	/*
	 * 7. bod úkolu
	 * uzavření audio streamu
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
 
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
	if (AVIFile != NULL)
	{
		AVIFileRelease(AVIFile);
	}
 
	GetFrame = NULL;
	VideoStream = NULL;
	AudioStream = NULL;
	AVIFile = NULL;
	Frame = NULL;
	InvalidateRect(GetDlgItem(hwndMain, IDC_BMP), NULL, FALSE);
	ScrollBarSet(0, 0);
	SetOutputWindowSize(WS, HS);
}
 
//------------------------------------------------------------------------------
void DispayAVIFormat()
{
	ListBoxClear();
	if (AVIFile == NULL)
	{
		ListBoxAdd("Neni otevreny soubor.");
		return;
	}
	/*
	 * 0. bod úkolu
	 * zobrazení informací o souboru:
	 * - rozlišení, framerate, délka...
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
	AVIFILEINFO pfi;
	AVIFileInfo(AVIFile, &pfi, sizeof(pfi));
	char *aviinfo = NULL;
	if (asprintf(&aviinfo, "%d*%d, %d FPS, %d s", pfi.dwWidth, pfi.dwHeight, pfi.dwRate / pfi.dwScale, pfi.dwLength / (pfi.dwRate / pfi.dwScale)) >= 0) {
		ListBoxAdd(aviinfo);
	}
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
 
	/*
	 * 2. bod úkolu
	 * zobrazení informací o video streamu:
	 * - framerate, počáteční a koncový snímek, délka, rozlišení
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
	AVISTREAMINFO psi;
	AVIStreamInfo(VideoStream, &psi, sizeof(psi));
	if (asprintf(&aviinfo, "%d FPS, frames %d--%d, %d s, %d*%d", psi.dwRate / psi.dwScale, psi.dwStart, psi.dwLength, psi.dwLength / (psi.dwRate / psi.dwScale), abs(psi.rcFrame.right - psi.rcFrame.left), abs(psi.rcFrame.bottom - psi.rcFrame.top)) >= 0) {
		ListBoxAdd(aviinfo);
	}
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
 
	/*
	 * 7. bod úkolu
	 * zobrazení informací o audio streamu:
	 * - počet kanálů, vzorkovací frekvence, průměrný počet B/s,
	 *   počet bitů na vzorek
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
 
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
}
 
//------------------------------------------------------------------------------
void DisplayAVIFrame(unsigned int Position)
{
	/*
	 * 5. bod úkolu
	 * načtení framu ze souboru
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
	//fprintf(stderr, "DisplayAVIFrame(%u)\n", Position);
	Frame = (BITMAPINFO*) AVIStreamGetFrame(GetFrame, Position);
	//if (!Frame) fprintf(stderr, "!!!\n");
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
	InvalidateRect(GetDlgItem(hwndMain, IDC_BMP), NULL, FALSE);
}
 
//------------------------------------------------------------------------------
#define KOMPRESE
void SaveAVI(const char *FileName)
{
	/*
	 * 8. bod úkolu
	 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
 
	if (VideoStream == NULL)
	{
		ShowMessage("Zdrojovy video stream neni otevren!");
		return;
	}
 
	// nacteni parametru streamu
	AVISTREAMINFO asi;
	if (AVIStreamInfo(VideoStream, &asi, sizeof(asi)) != 0)
	{
		ShowMessage("Nelze ziskat parametry zdrojoveho streamu!");
		return;
	}
	LONG Position = AVIStreamStart(VideoStream);
	LONG Length = AVIStreamLength(VideoStream);
 
	// ziskani 1. framu pro nastaveni formatu
	DisplayAVIFrame(Position);
	if (Frame == NULL)
	{
		ShowMessage("Nepodarilo se ziskat prvni frame!");
		return;
	}
 
	// vytvoreni noveho souboru
	PAVIFILE OutAVIFile;
	int hr = AVIFileOpen(&OutAVIFile, FileName, OF_CREATE, 0L);
	if (hr != 0)
	{
		ShowMessage("Soubor nelze vytvorit!");
		return;
	}
 
	// vytvoreni noveho video streamu
	PAVISTREAM OutVideoStream;
	if (AVIFileCreateStream(OutAVIFile, &OutVideoStream, &asi) != 0)
	{
		ShowMessage("Nepodarilo se vytvorit video stream");
		AVIFileRelease(OutAVIFile);
		return;
	}
 
	// pocatecni pozice streamu noveho streamu
	LONG OutPosition = 0;
 
#ifdef KOMPRESE
	AVICOMPRESSOPTIONS opts;
	AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts};
	memset(&opts, 0, sizeof(opts));
 
	// vyber kompresoru
	if (!AVISaveOptions(NULL, ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE, 1,
				&OutVideoStream, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
	{
		ShowMessage("Nepodarilo se vybrat kompresor!");
		AVIStreamRelease(OutVideoStream);
		AVIFileRelease(OutAVIFile);
		return;
	}
 
	// vytvoreni kompresovaneho streamu
	PAVISTREAM CompressedVideoStream;
	if (AVIMakeCompressedStream(&CompressedVideoStream, OutVideoStream, &opts, NULL) != 0)
	{
		ShowMessage("Nepodarilo se vytvorit kompresovany stream");
		AVIStreamRelease(OutVideoStream);
		AVIFileRelease(OutAVIFile);
		return;
	}
	AVISaveOptionsFree(1, (LPAVICOMPRESSOPTIONS FAR *) &aopts);
 
	// nastaveni formatu ziskaneho z 1. framu
	if (AVIStreamSetFormat(CompressedVideoStream, OutPosition, Frame,
				Frame->bmiHeader.biSize + Frame->bmiHeader.biClrUsed * sizeof(RGBQUAD)) != 0)
	{
		ShowMessage("Nepodarilo se nastavit format kompresovaneho streamu!");
		AVIStreamRelease(CompressedVideoStream);
		AVIStreamRelease(OutVideoStream);
		AVIFileRelease(OutAVIFile);
		return;
	}
#else
	// nastaveni formatu ziskaneho z 1. framu
	if (AVIStreamSetFormat(OutVideoStream, OutPosition, Frame,
				Frame->bmiHeader.biSize + Frame->bmiHeader.biClrUsed * sizeof(RGBQUAD)) != 0)
	{
		ShowMessage("Nepodarilo se nastavit format streamu!");
		AVIStreamRelease(OutVideoStream);
		AVIFileRelease(OutAVIFile);
		delete [] Format;
		return;
	}
#endif
 
	// ukladani framu do streamu
	while (Position < Length)
	{
		DisplayAVIFrame(Position);
		// zapis framu
		if (Frame != NULL)
		{
#ifdef KOMPRESE
			if (AVIStreamWrite(CompressedVideoStream, OutPosition++, 1,
						(char*)Frame + Frame->bmiHeader.biSize + Frame->bmiHeader.biClrUsed * sizeof(RGBQUAD),
						Frame->bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL) != 0)
			{
				ShowMessage("Nepodarilo se kompresovat frame!");
				AVIStreamRelease(CompressedVideoStream);
				AVIStreamRelease(OutVideoStream);
				AVIFileRelease(OutAVIFile);
				return;
			}
#else
			if (AVIStreamWrite(OutVideoStream, OutPosition++, 1,
						(char*)Frame + Frame->bmiHeader.biSize + Frame->bmiHeader.biClrUsed * sizeof(RGBQUAD),
						Frame->bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL) != 0)
			{
				ShowMessage("Nepodarilo se ulozit frame!");
				AVIStreamRelease(CompressedVideoStream);
				AVIStreamRelease(OutVideoStream);
				AVIFileRelease(OutAVIFile);
				return;
			}
#endif
		}
		else
		{
			break;
		}
		Position++;
	}
 
	// uzavreni streamu a souboru
#ifdef KOMPRESE
	AVIStreamRelease(CompressedVideoStream);
#endif
	AVIStreamRelease(OutVideoStream);
	AVIFileRelease(OutAVIFile);
 
	/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
}