Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2596 lines
76 KiB

  1. /****************************************************************************
  2. *
  3. * AVILIB.CPP
  4. *
  5. * routines for reading a AVIStream
  6. *
  7. * Copyright (c) 1992-1995 Microsoft Corporation. All Rights Reserved.
  8. *
  9. * You have a royalty-free right to use, modify, reproduce and
  10. * distribute the Sample Files (and/or any modified version) in
  11. * any way you find useful, provided that you agree that
  12. * Microsoft has no warranty obligations or liability for any
  13. * Sample Application Files which are modified.
  14. *
  15. ***************************************************************************/
  16. #include <win32.h>
  17. #ifndef _WIN32
  18. #include <ole2.h>
  19. #endif
  20. #include <vfw.h>
  21. #include <shellapi.h>
  22. #include <memory.h> // for _fmemset
  23. #include "avifilei.h"
  24. #include "aviopts.h" // string resources
  25. #include "debug.h"
  26. #include <stdlib.h>
  27. #include "olehack.h"
  28. #if !defined NUMELMS
  29. #define NUMELMS(aa) (sizeof(aa)/sizeof((aa)[0]))
  30. #endif
  31. #ifndef _WIN32
  32. #undef HKEY_CLASSES_ROOT
  33. #define HKEY_CLASSES_ROOT 0x00000001
  34. #define AVIFileOpenA AVIFileOpen
  35. #define AVIFileCreateStreamA AVIFileCreateStream
  36. BOOL gfOleInitialized;
  37. STDAPI_(void) MyFreeUnusedLibraries(void);
  38. #endif
  39. #define ValidPAVI(pavi) (pavi != NULL)
  40. #define V_PAVI(pavi, err) \
  41. if (!ValidPAVI(pavi)) \
  42. return err;
  43. #ifdef SHELLOLE
  44. #ifdef _WIN32
  45. #define CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv) \
  46. SHCoCreateInstance(NULL, (const CLSID FAR *)&rclsid, pUnkOuter, riid, ppv)
  47. #undef Assert
  48. #include <shlobj.h>
  49. #include <shellp.h>
  50. #endif
  51. #endif
  52. /****************************************************************************
  53. strings
  54. ****************************************************************************/
  55. #undef SZCODE
  56. #define SZCODE const TCHAR _based(_segname("_CODE"))
  57. ///////////////////////////////////////////////////////////////////////////
  58. ///////////////////////////////////////////////////////////////////////////
  59. EXTERN_C HINSTANCE ghMod;
  60. static int iInit = 0;
  61. #define InRange(id, idFirst, idLast) ((UINT)(id-idFirst) <= (UINT)(idLast-idFirst))
  62. // scan lpsz for a number of hex digits (at most 8); update lpsz, return
  63. // value in Value; check for chDelim; return TRUE for success.
  64. BOOL HexStringToDword(LPCTSTR FAR * lplpsz, DWORD FAR * lpValue, int cDigits, char chDelim)
  65. {
  66. int ich;
  67. LPCTSTR lpsz = *lplpsz;
  68. DWORD Value = 0;
  69. BOOL fRet = TRUE;
  70. for (ich = 0; ich < cDigits; ich++)
  71. {
  72. TCHAR ch = lpsz[ich];
  73. if (InRange(ch, '0', '9'))
  74. {
  75. Value = (Value << 4) + ch - '0';
  76. }
  77. else if ( InRange( (ch |= ('a'-'A')), 'a', 'f') )
  78. {
  79. Value = (Value << 4) + ch - 'a' + 10;
  80. }
  81. else
  82. return(FALSE);
  83. }
  84. if (chDelim)
  85. {
  86. fRet = (lpsz[ich++]==chDelim);
  87. }
  88. *lpValue = Value;
  89. *lplpsz = lpsz+ich;
  90. return fRet;
  91. }
  92. // parse above format; return TRUE if succesful; always writes over *pguid.
  93. STDAPI_(BOOL) GUIDFromString(LPCTSTR lpsz, LPGUID pguid)
  94. {
  95. DWORD dw;
  96. if (*lpsz++ != '{' /*}*/ )
  97. return FALSE;
  98. if (!HexStringToDword(&lpsz, &pguid->Data1, sizeof(DWORD)*2, '-'))
  99. return FALSE;
  100. if (!HexStringToDword(&lpsz, &dw, sizeof(WORD)*2, '-'))
  101. return FALSE;
  102. pguid->Data2 = (WORD)dw;
  103. if (!HexStringToDword(&lpsz, &dw, sizeof(WORD)*2, '-'))
  104. return FALSE;
  105. pguid->Data3 = (WORD)dw;
  106. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, 0))
  107. return FALSE;
  108. pguid->Data4[0] = (BYTE)dw;
  109. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, '-'))
  110. return FALSE;
  111. pguid->Data4[1] = (BYTE)dw;
  112. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, 0))
  113. return FALSE;
  114. pguid->Data4[2] = (BYTE)dw;
  115. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, 0))
  116. return FALSE;
  117. pguid->Data4[3] = (BYTE)dw;
  118. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, 0))
  119. return FALSE;
  120. pguid->Data4[4] = (BYTE)dw;
  121. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, 0))
  122. return FALSE;
  123. pguid->Data4[5] = (BYTE)dw;
  124. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, 0))
  125. return FALSE;
  126. pguid->Data4[6] = (BYTE)dw;
  127. if (!HexStringToDword(&lpsz, &dw, sizeof(BYTE)*2, /*(*/ '}'))
  128. return FALSE;
  129. pguid->Data4[7] = (BYTE)dw;
  130. return TRUE;
  131. }
  132. ///////////////////////////////////////////////////////////////////////////
  133. ///////////////////////////////////////////////////////////////////////////
  134. /**************************************************************************
  135. * @doc INTERNAL InitRegistry()
  136. *
  137. * @api void | write all the default AVIFile/AVIStream handlers to the
  138. * registry.
  139. *
  140. * @comm This function should be enhanced so that some of the key values
  141. * can be loaded from resources, instead of a static string table....
  142. *
  143. * @xref AVIStreamInit
  144. *
  145. *************************************************************************/
  146. #if 0 // Registry is now setup on install or upgrade
  147. #ifndef CHICAGO
  148. // !!! Chicago currently sets these registry entries up at setup time.
  149. // NT should someday do the same thing.
  150. #include "avireg.h"
  151. static void InitRegistry()
  152. {
  153. TCHAR **ppch = aszReg;
  154. TCHAR ach[80];
  155. LONG cb;
  156. // !!! This should have a version number or something in it....
  157. if (RegQueryValue(HKEY_CLASSES_ROOT, ppch[0], ach, (cb = sizeof(ach),&cb)) == ERROR_SUCCESS &&
  158. lstrcmpi(ach, ppch[1]) == 0) {
  159. DPF("Registry is up to date: %ls\n\t%ls\n\t%ls\n", ach, ppch[0], ppch[1]);
  160. return;
  161. }
  162. DPF("Setting: (was) %ls\n\t%ls\n\t(now) %ls\n", ach, ppch[0], ppch[1]);
  163. while (ppch[0])
  164. {
  165. #ifdef MAX_RC_CONSTANT
  166. if (((UINT) ppch[1]) < MAX_RC_CONSTANT) {
  167. LoadString(ghMod, (UINT) ppch[1], ach, sizeof(ach)/sizeof(TCHAR));
  168. RegSetValue(HKEY_CLASSES_ROOT, ppch[0], REG_SZ, ach, 0L);
  169. } else
  170. #endif
  171. {
  172. #ifdef _WIN32
  173. // string is too long for win 16
  174. #endif
  175. if (*ppch[1] == TEXT('@')) {
  176. // This can only be generously described as a hack. We
  177. // need to set a named value, but without restructuring
  178. // avireg.h completely (or reimplementing something different)
  179. // we cannot do so. Hence we allow "special" values. If the
  180. // "value" starts with "@" we interpret it to mean that this
  181. // is the value name, and the actual value follows.
  182. HKEY hKey = 0;
  183. DWORD Type = REG_SZ;
  184. RegOpenKeyEx(HKEY_CLASSES_ROOT, ppch[0], 0, KEY_SET_VALUE, &hKey);
  185. if (hKey) {
  186. LONG l =
  187. RegSetValueEx(hKey, ppch[1]+1, 0,
  188. REG_SZ,
  189. (LPBYTE)(ppch[2]),
  190. (1+lstrlen(ppch[2]))*sizeof(TCHAR)); // include NULL length
  191. DPF2("Set Value Ex, return is %d\n\tValue is:%ls\n\tData is:%ls\n", l, ppch[1]+1, ppch[2]);
  192. RegCloseKey(hKey);
  193. }
  194. ++ppch; // we must step three strings for named values
  195. } else {
  196. DPF2("Setting registry value: %ls\n\t%ls\n", ppch[0], ppch[1]);
  197. RegSetValue(HKEY_CLASSES_ROOT, ppch[0], REG_SZ, ppch[1], 0L);
  198. }
  199. }
  200. ppch += 2;
  201. }
  202. }
  203. #endif
  204. #endif
  205. /**************************************************************************
  206. * @doc EXTERNAL AVIFileInit
  207. *
  208. * @api void | AVIFileInit | This function initalizes the AVIFILE library.
  209. *
  210. * @comm Call this function before using any other AVIFILE functions.
  211. *
  212. * @xref <f AVIFileExit>
  213. *
  214. *************************************************************************/
  215. // Force dynlink to OLE on NT as we use link to CoCreateInstance whereas
  216. // Win95 uses the Shell instance call.
  217. #ifdef DAYTONA
  218. #define INITOLE (iInit==1) //Force load on NT if this is the first init
  219. #else
  220. #define INITOLE FALSE
  221. #endif
  222. STDAPI_(void) AVIFileInit()
  223. {
  224. iInit++;
  225. DPF("AVIFileInit: level now==%d\n", iInit);
  226. #if defined(SHELLOLE) || defined(DAYTONA)
  227. #ifndef _WIN32
  228. CoInitialize(NULL);
  229. #endif
  230. InitOle(INITOLE);
  231. #else
  232. OleInitialize(NULL);
  233. #endif
  234. #if 0 // Registry is now setup on install or upgrade
  235. #ifndef CHICAGO
  236. if (iInit == 1) {
  237. InitRegistry();
  238. }
  239. #endif
  240. #endif
  241. }
  242. /**************************************************************************
  243. * @doc EXTERNAL AVIFileExit
  244. *
  245. * @api void | AVIFileExit | This function exits the AVIFILE library.
  246. *
  247. * @comm Call this function after using any other AVIFILE functions.
  248. *
  249. * @xref <f AVIFileInit>
  250. *
  251. *************************************************************************/
  252. STDAPI_(void) AVIFileExit()
  253. {
  254. iInit--;
  255. DPF("AVIFileExit: level now %d\n", iInit);
  256. #if defined(SHELLOLE) || defined(DAYTONA)
  257. TermOle();
  258. #ifndef _WIN32
  259. MyFreeUnusedLibraries();
  260. CoUninitialize();
  261. #endif
  262. #else // not SHELLOLE
  263. CoFreeUnusedLibraries();
  264. OleUninitialize();
  265. #endif
  266. }
  267. /**************************************************************************
  268. * @doc INTERNAL AVIFileCreate
  269. *
  270. * @api LONG | AVIFileCreate | Initializes an empty AVI File interface
  271. * pointer.
  272. *
  273. * @parm PAVIFILE FAR * | ppfile | Pointer to where the new <t PAVIFILE>
  274. * should be returned.
  275. *
  276. * @parm LONG | lParam | Specifies a parameter passed to the handler.
  277. *
  278. * @parm CLSID FAR * | pclsidHandler | Specifies a pointer to a
  279. * class ID used to create the file.
  280. *
  281. * @devnote Nobody should have to call this function, because AVIFileOpen
  282. * does it. In fact, why do we even have this?
  283. *
  284. * @rdesc Returns zero if successful; otherwise it returns an error code.
  285. *
  286. * @xref AVIFileOpen
  287. *
  288. *************************************************************************/
  289. STDAPI AVIFileCreate (PAVIFILE FAR *ppfile, LONG lParam,
  290. CLSID FAR *pclsidHandler)
  291. {
  292. CLSID clsid;
  293. HRESULT hr;
  294. if (!iInit) {
  295. return ResultFromScode(CO_E_NOTINITIALIZED);
  296. }
  297. // AVIStreamInit();
  298. if (pclsidHandler)
  299. clsid = *pclsidHandler;
  300. else {
  301. // if (pfh == NULL)
  302. // pfh = &AVIFFileHandler;
  303. }
  304. if (FAILED(GetScode(hr = CoCreateInstance((REFCLSID) clsid,
  305. NULL, CLSCTX_INPROC,
  306. (REFIID) IID_IAVIFile,
  307. (void FAR* FAR*)ppfile)))) {
  308. DPF("AVIFileCreate: CoCreateInstance failed code == %8x\n", hr);
  309. return hr; // !!! PropagateHResult?
  310. }
  311. return AVIERR_OK;
  312. }
  313. // Remove trailing spaces after a file...
  314. void FixFourCC(LPSTR lp)
  315. {
  316. int i;
  317. for (i = 3; i >= 0; i--) {
  318. if (lp[i] == ' ')
  319. lp[i] = '\0';
  320. else
  321. break;
  322. }
  323. }
  324. // Returns a pointer to the extension of a filename....
  325. LPCOLESTR FindExtension(LPCOLESTR lp)
  326. {
  327. LPCOLESTR lpExt = lp;
  328. int i;
  329. // Goto end of string
  330. while (*lpExt != TEXT('\0'))
  331. {
  332. ++lpExt;
  333. }
  334. // Must be at least 2 characters in string
  335. if (lpExt - lp < 2 * sizeof(TCHAR))
  336. return NULL;
  337. lpExt -= 1;
  338. // Does not count if last character is '.'
  339. if (*lpExt == TEXT('.'))
  340. return NULL;
  341. lpExt -= 1;
  342. // Now looking at second to the last character. Check this and the two
  343. // previous characters for a '.'
  344. for (i=1; i<=3; ++i)
  345. {
  346. // Cannot have path separator here
  347. if (*lpExt == TEXT('/') || *lpExt == TEXT('\\'))
  348. return NULL;
  349. if (*lpExt == TEXT('.'))
  350. {
  351. ++lpExt;
  352. return lpExt;
  353. }
  354. if (lpExt == lp)
  355. return NULL;
  356. --lpExt;
  357. }
  358. return NULL;
  359. }
  360. /**************************************************************************
  361. * @doc INTERNAL GetHandlerFromFile
  362. *
  363. * @api PAVIFILEHANDLER | GetHandlerFromFile | Figure out what handler
  364. * to use for a file by looking at its extension, its RIFF type,
  365. * and possibly other things.
  366. *
  367. * @parm LPCTSTR | szFile | The file to look at.
  368. *
  369. * @parm CLSID FAR * | pclsidHandler | Pointer to a classID.
  370. *
  371. * @comm We don't look at the extensions yet. We need a better way to
  372. * add handlers.
  373. *
  374. * @rdesc Returns the <PAVIFILEHANDLER> to use, or NULL if it can't find
  375. * one.
  376. *
  377. * @xref AVIFileOpen AVIRegisterLoader
  378. *
  379. *************************************************************************/
  380. #define HKEY_AVIFILE_ROOT HKEY_CLASSES_ROOT
  381. #ifdef _WIN32
  382. static SZCODE aszRegRIFF[] = TEXT("AVIFile\\RIFFHandlers\\%.4hs");
  383. #else
  384. static SZCODE aszRegRIFF[] = TEXT("AVIFile\\RIFFHandlers\\%.4s");
  385. #endif
  386. static SZCODE aszRegExt[] = TEXT("AVIFile\\Extensions");
  387. static SZCODE aszRegClsid[] = TEXT("Clsid");
  388. static SZCODE aszRegExtTmpl[] = TEXT("%s\\%.3ls");
  389. BOOL GetHandlerFromFile(LPCOLESTR szFile, CLSID FAR *pclsid)
  390. {
  391. LPCOLESTR lpExt;
  392. TCHAR achKey[100];
  393. TCHAR achClass[100];
  394. LONG lcbClass;
  395. #if !defined _WIN32 || defined UNICODE
  396. DWORD dw[3];
  397. HMMIO hmmio;
  398. // I hate share
  399. hmmio = mmioOpen((LPTSTR) szFile, NULL, MMIO_READ | MMIO_DENYWRITE);
  400. if (hmmio == NULL)
  401. hmmio = mmioOpen((LPTSTR) szFile, NULL, MMIO_READ | MMIO_DENYNONE);
  402. if (hmmio == NULL)
  403. hmmio = mmioOpen((LPTSTR) szFile, NULL, MMIO_READ);
  404. if (hmmio == NULL)
  405. goto UseExtension;
  406. if (mmioRead(hmmio, (HPSTR) dw, sizeof(dw)) != sizeof(dw)) {
  407. mmioClose(hmmio, 0);
  408. goto UseExtension;
  409. }
  410. mmioClose(hmmio, 0);
  411. if (dw[0] != FOURCC_RIFF)
  412. goto UseExtension;
  413. FixFourCC((LPSTR) &dw[2]);
  414. // Look up the RIFF type in the registration database....
  415. wsprintf(achKey, aszRegRIFF, (LPSTR) &dw[2]);
  416. lcbClass = sizeof(achClass);
  417. RegQueryValue(HKEY_CLASSES_ROOT, achKey, achClass, &lcbClass);
  418. if (GUIDFromString(achClass, pclsid))
  419. return TRUE;
  420. UseExtension:
  421. #endif
  422. lpExt = FindExtension(szFile);
  423. if (lpExt) {
  424. // Look up the extension in the registration database....
  425. wsprintf(achKey, aszRegExtTmpl, (LPTSTR) aszRegExt, lpExt);
  426. lcbClass = sizeof(achClass);
  427. RegQueryValue(HKEY_CLASSES_ROOT, achKey, achClass, &lcbClass);
  428. if (GUIDFromString(achClass, pclsid))
  429. return TRUE;
  430. }
  431. // !!! Use IStorage?
  432. return FALSE;
  433. }
  434. /**************************************************************************
  435. * @doc EXTERNAL AVIFileOpen
  436. *
  437. * @api LONG | AVIFileOpen | Opens an AVI file and returns a file interface
  438. * pointer used to access it.
  439. *
  440. * @parm PAVIFILE FAR * | ppfile | Pointer to the location used to return
  441. * the new <t PAVIFILE> file pointer.
  442. *
  443. * @parm LPCTSTR | szFile | Specifies a zero-terminated string
  444. * containing the name of the file to open.
  445. *
  446. * @parm UINT | mode | Specifies the mode to use when opening the file.
  447. *
  448. *
  449. * @flag OF_READ | Opens the file for reading only. This is the
  450. * default, if OF_WRITE and OF_READWRITE are not specified.
  451. *
  452. * @flag OF_WRITE | Opens the file for writing. You should not
  453. * read from a file opened in this mode.
  454. *
  455. * @flag OF_READWRITE | Opens the file for both reading and writing.
  456. *
  457. * @flag OF_CREATE | Creates a new file.
  458. * If the file already exists, it is truncated to zero length.
  459. *
  460. * @flag OF_DENYWRITE | Opens the file and denies other
  461. * processes write access to the file. <f AVIFileOpen> fails
  462. * if the file has been opened in compatibility or for write
  463. * access by any other process.
  464. *
  465. * @flag OF_DENYREAD | Opens the file and denies other
  466. * processes read access to the file. <f AVIFileOpen> fails if the
  467. * file has been opened in compatibility mode or for read access
  468. * by any other process.
  469. *
  470. * @flag OF_DENYNONE | Opens the file without denying other
  471. * processes read or write access to the file. <f AVIFileOpen>
  472. * fails if the file has been opened in compatibility mode
  473. * by any other process.
  474. *
  475. * @flag OF_EXCLUSIVE | Opens the file and denies other processes
  476. * any access to the file. <f AVIFileOpen> will fail if any
  477. * other process has opened the file.
  478. *
  479. * See <f OpenFile> for more information about these flags.
  480. *
  481. * @parm CLSID FAR * | pclsidHandler | Specifies a pointer to a class ID
  482. * identifying the handler you want to use. If NULL, the system
  483. * chooses one from the registration database based on the file
  484. * extension or the file's RIFF type.
  485. *
  486. * @comm In general, the mode specified is used to open
  487. * the file.
  488. *
  489. * Be sure to call <f AVIFileInit> at least once in your
  490. * application before calling this function, and to balance each
  491. * call to <f AVIFileInit> with a call to <f AVIFileExit>.
  492. *
  493. * @rdesc Returns zero if successful; otherwise returns an error code.
  494. * Possible error returns include:
  495. *
  496. * @flag AVIERR_BADFORMAT | The file was corrupted or not in the
  497. * proper format, and could not be read.
  498. *
  499. * @flag AVIERR_MEMORY | The file could not be opened because
  500. * there was not enough memory.
  501. *
  502. * @flag AVIERR_FILEREAD | A disk error occurred while reading the
  503. * file.
  504. *
  505. * @flag AVIERR_FILEOPEN | A disk error occurred while opening the
  506. * file.
  507. *
  508. * @flag REGDB_E_CLASSNOTREG | No handler could be found to open
  509. * this type of file.
  510. *
  511. * @xref <f AVIFileRelease> <f AVIFileInit>
  512. *
  513. *************************************************************************/
  514. STDAPI
  515. #ifdef _WIN32
  516. AVIFileOpenW
  517. #else
  518. AVIFileOpen
  519. #endif
  520. (PAVIFILE FAR *ppfile,
  521. LPCOLESTR szFile,
  522. UINT mode,
  523. CLSID FAR *pclsidHandler)
  524. {
  525. CLSID clsid;
  526. HRESULT hr;
  527. LPUNKNOWN punk;
  528. // We used to just fail if AVIFileInit wasn't called
  529. #if 0
  530. if (!iInit) {
  531. return ResultFromScode(E_UNEXPECTED);
  532. }
  533. #endif
  534. #if 0
  535. // Now we do it for them
  536. hr = CoInitialize(NULL);
  537. // Let them know what they did wrong
  538. if (GetScode(hr) == NOERROR) {
  539. #ifdef DEBUG
  540. MessageBoxA(NULL, "You didn't call AVIFileInit!", "Bad dog!",
  541. MB_OK | MB_ICONHAND);
  542. #endif
  543. } else
  544. CoUninitialize();
  545. #endif
  546. *ppfile = 0;
  547. if (pclsidHandler) {
  548. clsid = *pclsidHandler;
  549. DPF2("AVIFileOpen using explicit clsid %8x, %8x, %8x, %8x\n", clsid);
  550. }
  551. else {
  552. if (!GetHandlerFromFile(szFile, &clsid)) {
  553. DPF("Couldn't find handler for %s\n", (LPTSTR) szFile);
  554. return ResultFromScode(REGDB_E_CLASSNOTREG);
  555. }
  556. }
  557. if (FAILED(GetScode(hr = CoCreateInstance((REFCLSID) clsid,
  558. NULL, CLSCTX_INPROC,
  559. (REFIID) IID_IUnknown,
  560. (void FAR* FAR*)&punk)))) {
  561. DPF("CoCreateInstance returns %08lx\n", (DWORD) hr);
  562. return hr;
  563. }
  564. //
  565. // Let's simplify things for the handlers. They will only see...
  566. // OF_CREATE | OF_READWRITE or...
  567. // OF_READWRITE or...
  568. // OF_READ
  569. //
  570. if (mode & OF_READWRITE)
  571. mode &= ~(OF_WRITE | OF_READ);
  572. if (mode & OF_CREATE) {
  573. mode &= ~(OF_WRITE | OF_READ);
  574. mode |= OF_READWRITE;
  575. }
  576. if (mode & OF_WRITE) {
  577. mode &= ~(OF_WRITE | OF_READ);
  578. mode |= OF_READWRITE;
  579. }
  580. #ifdef _WIN32
  581. IPersistFile * lpPersist = NULL;
  582. hr = punk->QueryInterface(IID_IPersistFile, ( LPVOID FAR *) &lpPersist);
  583. if (SUCCEEDED(GetScode(hr))) {
  584. hr = punk->QueryInterface(IID_IAVIFile, ( LPVOID FAR *) ppfile);
  585. if (SUCCEEDED(GetScode(hr))) {
  586. if (FAILED(GetScode(hr = lpPersist->Load(szFile, mode)))) {
  587. DPF("Open method returns %08lx\n", (DWORD) hr);
  588. (*ppfile)->Release();
  589. *ppfile = NULL;
  590. }
  591. }
  592. lpPersist->Release();
  593. }
  594. #else
  595. hr = punk->QueryInterface(IID_IAVIFile, ( LPVOID FAR *) ppfile);
  596. if (SUCCEEDED(GetScode(hr))) {
  597. if (FAILED(GetScode(hr = (*ppfile)->Open(szFile, mode)))) {
  598. DPF("Open method returns %08lx\n", (DWORD) hr);
  599. (*ppfile)->Release();
  600. *ppfile = NULL;
  601. }
  602. }
  603. #endif
  604. punk->Release();
  605. return hr;
  606. }
  607. #ifdef _WIN32
  608. /*
  609. * Ansi thunk for AVIFileOpen
  610. */
  611. STDAPI AVIFileOpenA (PAVIFILE FAR *ppfile,
  612. LPCSTR szFile,
  613. UINT mode,
  614. CLSID FAR *pclsidHandler)
  615. {
  616. LPWSTR lpW;
  617. int sz;
  618. HRESULT hr;
  619. // remember the null
  620. sz = lstrlenA(szFile) + 1;
  621. lpW = (LPWSTR) (LocalAlloc(LPTR, sz * sizeof(WCHAR)));
  622. if (lpW == NULL) {
  623. return ResultFromScode(AVIERR_MEMORY);
  624. }
  625. MultiByteToWideChar(CP_ACP, 0, szFile, -1, lpW, sz);
  626. hr = AVIFileOpenW(ppfile, lpW, mode, pclsidHandler);
  627. LocalFree((HANDLE)lpW);
  628. return hr;
  629. }
  630. #endif
  631. /**************************************************************************
  632. * @doc EXTERNAL AVIFileAddRef
  633. *
  634. * @api LONG | AVIFileAddRef | Increases the reference count of an AVI file.
  635. *
  636. * @parm PAVIFILE | pfile | Specifies the handle for an open AVI file.
  637. *
  638. * @rdesc Returns the reference count of the file. This return value
  639. * should be used only for debugging purposes.
  640. *
  641. * @comm Balance each call to <f AVIFileAddRef> with a call to
  642. * <f AVIFileRelease>.
  643. *
  644. * @xref <f AVIFileRelease>
  645. *
  646. *************************************************************************/
  647. STDAPI_(ULONG) AVIFileAddRef(PAVIFILE pfile)
  648. {
  649. return pfile->AddRef();
  650. }
  651. /**************************************************************************
  652. * @doc EXTERNAL AVIFileRelease
  653. *
  654. * @api LONG | AVIFileRelease | Reduces the reference count of an AVI file
  655. * interface handle by one, and closes the file if the count reaches
  656. * zero.
  657. *
  658. * @parm PAVIFILE | pfile | Specifies a handle to an open AVI file.
  659. *
  660. * @comm Balance each call to <f AVIFileAddRef> or <f AVIFileOpen>
  661. * a call to <f AVIFileRelease>.
  662. *
  663. * @devnote Currently, this saves all changes to the file. Should a separate
  664. * Save command be needed to do this?
  665. *
  666. * @rdesc Returns the reference count of the file. This return value
  667. * should be used only for debugging purposes.
  668. *
  669. * @xref AVIFileOpen AVIFileAddRef
  670. *
  671. *************************************************************************/
  672. STDAPI_(ULONG) AVIFileRelease(PAVIFILE pfile)
  673. {
  674. return pfile->Release();
  675. }
  676. /**************************************************************************
  677. * @doc EXTERNAL AVIFileInfo
  678. *
  679. * @api LONG | AVIFileInfo | Obtains information about an AVI file.
  680. *
  681. * @parm PAVIFILE | pfile | Specifies a handle to an open AVI file.
  682. *
  683. * @parm AVIFILEINFO FAR * | pfi | Pointer to the structure used to
  684. * return file information.
  685. *
  686. * @parm LONG | lSize | Specifies the size of the structure. This value
  687. * should be at least sizeof(AVIFILEINFO), obviously.
  688. *
  689. * @rdesc Returns zero if successful; otherwise it returns an error code.
  690. *
  691. *************************************************************************/
  692. STDAPI AVIFileInfoW (PAVIFILE pfile, AVIFILEINFOW FAR * pfi,
  693. LONG lSize)
  694. {
  695. _fmemset(pfi, 0, (int)lSize);
  696. return pfile->Info(pfi, lSize);
  697. }
  698. #ifdef _WIN32
  699. // ansi thunk for above function
  700. STDAPI AVIFileInfoA(
  701. PAVIFILE pfile,
  702. LPAVIFILEINFOA pfiA,
  703. LONG lSize)
  704. {
  705. AVIFILEINFOW fiW;
  706. HRESULT hr;
  707. // if size too small - tough
  708. if (lSize < sizeof(AVIFILEINFOA)) {
  709. return ResultFromScode(AVIERR_BADSIZE);
  710. }
  711. hr = AVIFileInfoW(pfile, &fiW, sizeof(fiW));
  712. pfiA->dwMaxBytesPerSec = fiW.dwMaxBytesPerSec;
  713. pfiA->dwFlags = fiW.dwFlags;
  714. pfiA->dwCaps = fiW.dwCaps;
  715. pfiA->dwStreams = fiW.dwStreams;
  716. pfiA->dwSuggestedBufferSize = fiW.dwSuggestedBufferSize;
  717. pfiA->dwWidth = fiW.dwWidth;
  718. pfiA->dwHeight = fiW.dwHeight;
  719. pfiA->dwScale = fiW.dwScale;
  720. pfiA->dwRate = fiW.dwRate;
  721. pfiA->dwLength = fiW.dwLength;
  722. pfiA->dwEditCount = fiW.dwEditCount;
  723. // convert the name
  724. WideCharToMultiByte(CP_ACP, 0, fiW.szFileType, -1,
  725. pfiA->szFileType, NUMELMS(pfiA->szFileType), NULL, NULL);
  726. return hr;
  727. }
  728. #endif
  729. /**************************************************************************
  730. * @doc EXTERNAL AVIFileGetStream
  731. *
  732. * @api LONG | AVIFileGetStream | Returns a pointer to a stream interface
  733. * that is a component of a file.
  734. *
  735. * @parm PAVIFILE | pfile | Specifies a handle to an open AVI file.
  736. *
  737. * @parm PAVISTREAM FAR * | ppavi | Pointer to the return location
  738. * for the new stream interface pointer.
  739. *
  740. * @parm DWORD | fccType | Specifies a four-character code
  741. * indicating the type of stream to be opened.
  742. * Zero indicates that any stream can be opened. The following
  743. * definitions apply to the data commonly
  744. * found in AVI streams:
  745. *
  746. * @flag streamtypeAUDIO | Indicates an audio stream.
  747. * @flag streamtypeMIDI | Indicates a MIDI stream.
  748. * @flag streamtypeTEXT | Indicates a text stream.
  749. * @flag streamtypeVIDEO | Indicates a video stream.
  750. *
  751. * @parm LONG | lParam | Specifies an integer indicating which stream
  752. * of the type defined by <p fccType> should actually be accessed.
  753. *
  754. * @comm Balance each call to <f AVIFileGetStream> with a call to
  755. * <f AVIStreamRelease> using the stream handle returned.
  756. *
  757. * @rdesc Returns zero if successful; otherwise it returns an error code.
  758. * Possible error codes include:
  759. *
  760. * @flag AVIERR_NODATA | There is no stream in the file corresponding
  761. * to the values passed in for <p fccType> and <p lParam>.
  762. * @flag AVIERR_MEMORY | Not enough memory.
  763. *
  764. * @xref <f AVIStreamRelease>
  765. *
  766. *************************************************************************/
  767. STDAPI AVIFileGetStream (PAVIFILE pfile, PAVISTREAM FAR * ppavi, DWORD fccType, LONG lParam)
  768. {
  769. return pfile->GetStream(ppavi, fccType, lParam);
  770. }
  771. #if 0
  772. // !!! This would be used to save changes, if AVIFileRelease didn't do that.
  773. STDAPI AVIFileSave (PAVIFILE pfile,
  774. LPCTSTR szFile,
  775. AVISAVEOPTIONS FAR *lpOptions,
  776. AVISAVECALLBACK lpfnCallback,
  777. PAVIFILEHANDLER pfh)
  778. {
  779. if (pfile->FileSave == NULL)
  780. return -1;
  781. return pfile->FileSave(pfile, szFile, lpOptions, lpfnCallback);
  782. }
  783. #endif
  784. /**************************************************************************
  785. * @doc EXTERNAL AVIFileCreateStream
  786. *
  787. * @api LONG | AVIFileCreateStream | Creates a new stream in an existing file,
  788. * and returns a stream interface pointer for it.
  789. *
  790. * @parm PAVIFILE | pfile | Specifies a handle to an open AVI file.
  791. *
  792. * @parm PAVISTREAM FAR * | ppavi | Specifies a pointer used to return the new
  793. * stream interface pointer.
  794. *
  795. * @parm AVISTREAMINFO FAR * | psi | Specifies a pointer to a structure
  796. * containing information about the new stream. This structure
  797. * contains the type of the new stream and its sample rate.
  798. *
  799. * @comm Balance each call to <f AVIFileCreateStream> with a call to
  800. * <f AVIStreamRelease> using the returned stream handle.
  801. *
  802. * This function fails with a return value of AVIERR_READONLY unless
  803. * the file was opened with write permission.
  804. *
  805. * After creating the stream, call <f AVIStreamSetFormat>
  806. * before using <f AVIStreamWrite> to write to the stream.
  807. *
  808. * @rdesc Returns zero if successful; otherwise it returns an error code.
  809. *
  810. * @xref <f AVIStreamRelease> <f AVIFileGetStream> <f AVIStreamSetFormat>
  811. *
  812. *************************************************************************/
  813. STDAPI
  814. #ifdef _WIN32
  815. AVIFileCreateStreamW
  816. #else
  817. AVIFileCreateStream
  818. #endif
  819. (PAVIFILE pfile,
  820. PAVISTREAM FAR *ppavi,
  821. AVISTREAMINFOW FAR *psi)
  822. {
  823. *ppavi = NULL;
  824. return pfile->CreateStream(ppavi, psi);
  825. }
  826. #ifdef _WIN32
  827. /*
  828. * Ansi thunk for AVIFileCreateStream
  829. */
  830. STDAPI AVIFileCreateStreamA (PAVIFILE pfile,
  831. PAVISTREAM FAR *ppavi,
  832. AVISTREAMINFOA FAR *psi)
  833. {
  834. *ppavi = NULL;
  835. AVISTREAMINFOW siW;
  836. #ifdef UNICODE
  837. // Copy the AVISTREAMINFOA structure to the unicode equivalent. We
  838. // rely on the fact - policed - that the szName element is the last
  839. // field in the structure.
  840. memcpy(&siW, psi, FIELD_OFFSET(AVISTREAMINFOA, szName));
  841. Assert((FIELD_OFFSET(AVISTREAMINFOA, szName) + sizeof(psi->szName)) == sizeof(*psi));
  842. #else
  843. memcpy(&siW, psi, sizeof(*psi)-sizeof(psi->szName));
  844. #endif
  845. // convert the name
  846. MultiByteToWideChar(CP_ACP, 0, psi->szName, NUMELMS(psi->szName),
  847. siW.szName, NUMELMS(siW.szName));
  848. return pfile->CreateStream(ppavi, &siW);
  849. // no need to copy anything back ??
  850. }
  851. #endif
  852. /**************************************************************************
  853. * @doc INTERNAL AVIFileAddStream
  854. *
  855. * @api LONG | AVIFileAddStream | Adds an existing stream into
  856. * an existing file, and returns a stream interface pointer for it.
  857. *
  858. * @parm PAVIFILE | pfile | Specifies a handle to an open AVI file.
  859. *
  860. * @parm PAVISTREAM | pavi | Specifies a stream interface pointer
  861. * for the stream being added.
  862. *
  863. * @parm PAVISTREAM FAR * | ppaviNew | Pointer to a buffer used
  864. * to return the new stream interface pointer.
  865. *
  866. * @comm Balance each call to <f AVIFileAddStream> with a call to
  867. * <f AVIStreamRelease> using the returned stream handle.
  868. *
  869. * This call fails with a return value of AVIERR_READONLY unless
  870. * the file was opened with write permission.
  871. *
  872. * @devnote This function still doesn't really work. Perhaps it should just
  873. * be a helper function that gets data from the stream and calls
  874. * AVIFileCreateStream, then copies the data from one stream to another.
  875. *
  876. * @rdesc Returns zero if successful; otherwise it returns an error code.
  877. *
  878. * @xref AVIStreamRelease AVIFileGetStream AVIFileCreateStream
  879. *
  880. *************************************************************************/
  881. #if 0
  882. STDAPI AVIFileAddStream (PAVIFILE pfile,
  883. PAVISTREAM pavi,
  884. PAVISTREAM FAR * ppaviNew)
  885. {
  886. // if (pfile->FileAddStream == NULL)
  887. // return -1;
  888. return pfile->AddStream(pavi, ppaviNew);
  889. }
  890. #endif
  891. /**************************************************************************
  892. * @doc EXTERNAL AVIFileWriteData
  893. *
  894. * @api LONG | AVIFileWriteData | Writes some additional data to the file.
  895. *
  896. * @parm PAVIFILE | pfile | Specifies a handle to an open AVI file.
  897. *
  898. * @parm DWORD | ckid | Specifies a four-character code identifying the data.
  899. *
  900. * @parm LPVOID | lpData | Specifies a pointer to the data to write.
  901. *
  902. * @parm LONG | cbData | Specifies the size of the memory block
  903. * referenced by <p lpData>.
  904. *
  905. * @comm This function fails with a return value of AVIERR_READONLY unless
  906. * the file was opened with write permission.
  907. *
  908. * Use <f AVIStreamWriteData> instead of this function to write
  909. * data that applies to an individual stream.
  910. *
  911. * @devnote !!! Somewhere, we should specify some types.
  912. * !!! Should the data block contain the ckid and cksize?
  913. *
  914. * @rdesc Returns zero if successful; otherwise it returns an error code.
  915. *
  916. * @xref <f AVIStreamWriteData> <f AVIFileReadData>
  917. *
  918. *************************************************************************/
  919. STDAPI AVIFileWriteData (PAVIFILE pfile,
  920. DWORD ckid,
  921. LPVOID lpData,
  922. LONG cbData)
  923. {
  924. // if (pfile->FileWriteData == NULL)
  925. // return -1;
  926. return pfile->WriteData(ckid, lpData, cbData);
  927. }
  928. /**************************************************************************
  929. * @doc EXTERNAL AVIFileReadData
  930. *
  931. * @api LONG | AVIFileReadData | Reads optional header data from the file.
  932. *
  933. * @parm PAVIFILE | pfile | Specifies a handle to an open AVI file.
  934. *
  935. * @parm DWORD | ckid | Specifies a four-character code identifying the data.
  936. *
  937. * @parm LPVOID | lpData | Specifies a pointer to a buffer used to return
  938. * the data read.
  939. *
  940. * @parm LONG FAR * | lpcbData | Specifies a pointer to a location indicating
  941. * the size of the memory block referred to by <p lpData>. If
  942. * the read is successful, the value is changed to indicate the
  943. * amount of data read.
  944. *
  945. * @devnote !!! Somewhere, we should specify some types.
  946. * !!! Should the data block contain the ckid and cksize?
  947. *
  948. * @comm Do not use this function to read video and audio data. Use it
  949. * only to read additional information such as author
  950. * information or copyright information that applies to the file
  951. * as a whole. Information that applies to a single stream should
  952. * be read using <f AVIStreamReadData>.
  953. *
  954. * @rdesc Returns zero if successful; otherwise it returns an error code.
  955. * The return value AVIERR_NODATA indicates that data with the
  956. * requested chunk ID does not exist.
  957. *
  958. * @xref <f AVIStreamReadData> <f AVIFileWriteData>
  959. *
  960. *************************************************************************/
  961. STDAPI AVIFileReadData (PAVIFILE pfile,
  962. DWORD ckid,
  963. LPVOID lpData,
  964. LONG FAR * lpcbData)
  965. {
  966. return pfile->ReadData(ckid, lpData, lpcbData);
  967. }
  968. /**************************************************************************
  969. * @doc EXTERNAL AVIFileEndRecord
  970. *
  971. * @api LONG | AVIFileEndRecord | Marks the end of a record, if writing out
  972. * a strictly interleaved file.
  973. *
  974. * @parm PAVIFILE | pfile | Specifies a handle to a currently open AVI file.
  975. *
  976. * @comm <f AVIFileSave> uses this function when writing files that are
  977. * have audio interleaved every frame. In general, applications
  978. * should not need to use this function.
  979. *
  980. * @rdesc Returns zero if successful; otherwise it returns an error code.
  981. *
  982. * @xref <f AVIFileSave> <f AVIStreamWrite>
  983. *
  984. *************************************************************************/
  985. STDAPI AVIFileEndRecord (PAVIFILE pfile)
  986. {
  987. // if (pfile->FileEndRecord == NULL)
  988. // return -1;
  989. return pfile->EndRecord();
  990. }
  991. /**************************************************************************
  992. * @doc EXTERNAL AVIStreamAddRef
  993. *
  994. * @api LONG | AVIStreamAddRef | Increases the reference count of an AVI stream.
  995. *
  996. * @parm PAVISTREAM | pavi | Specifies a handle to an open AVI stream.
  997. *
  998. * @comm Balance each call to <f AVIStreamAddRef> with a call to
  999. * <f AVIStreamRelease>.
  1000. *
  1001. * @rdesc Returns the current reference count of the stream. This value
  1002. * should only be used for debugging purposes.
  1003. *
  1004. * @xref <f AVIStreamRelease>
  1005. *
  1006. *************************************************************************/
  1007. STDAPI_(ULONG) AVIStreamAddRef (PAVISTREAM pavi)
  1008. {
  1009. return pavi->AddRef();
  1010. }
  1011. /**************************************************************************
  1012. * @doc EXTERNAL AVIStreamRelease
  1013. *
  1014. * @api LONG | AVIStreamRelease | Reduces the reference count of an AVI stream
  1015. * interface handle by one, and closes the stream if the count reaches
  1016. * zero.
  1017. *
  1018. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1019. *
  1020. * @comm Balance each call to <f AVIStreamAddRef> or <f AVIFileGetStream>
  1021. * with a call to <f AVIStreamRelease>.
  1022. *
  1023. * @rdesc Returns the current reference count of the stream. This value
  1024. * should only be used for debugging purposes.
  1025. *
  1026. * @xref <f AVIFileGetStream> <f AVIStreamAddRef>
  1027. *
  1028. *************************************************************************/
  1029. STDAPI_(ULONG) AVIStreamRelease (PAVISTREAM pavi)
  1030. {
  1031. return pavi->Release();
  1032. }
  1033. /**************************************************************************
  1034. * @doc EXTERNAL AVIStreamInfo
  1035. *
  1036. * @api LONG | AVIStreamInfo | Obtains stream header information.
  1037. *
  1038. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1039. *
  1040. * @parm AVISTREAMINFO FAR * | psi | Specifies a pointer to a structure
  1041. * used to return stream information.
  1042. *
  1043. * @parm LONG | lSize | Specifies the size of the structure used for
  1044. * <p psi>.
  1045. *
  1046. * @rdesc Returns zero if successful; otherwise it returns an error code.
  1047. *
  1048. *************************************************************************/
  1049. STDAPI AVIStreamInfoW (PAVISTREAM pavi, AVISTREAMINFOW FAR * psi, LONG lSize)
  1050. {
  1051. _fmemset(psi, 0, (int)lSize);
  1052. return pavi->Info(psi, lSize);
  1053. }
  1054. #ifdef _WIN32
  1055. //Ansi thunk for above function
  1056. STDAPI AVIStreamInfoA(
  1057. PAVISTREAM pavi,
  1058. LPAVISTREAMINFOA psi,
  1059. LONG lSize
  1060. )
  1061. {
  1062. HRESULT hr;
  1063. AVISTREAMINFOW sW;
  1064. hr = AVIStreamInfoW(pavi, &sW, sizeof(sW));
  1065. // is the size big enough
  1066. if (lSize < sizeof(AVISTREAMINFOA)) {
  1067. return ResultFromScode(AVIERR_BADSIZE);
  1068. }
  1069. // copy non-char-related fields
  1070. psi->fccType = sW.fccType;
  1071. psi->fccHandler = sW.fccHandler;
  1072. psi->dwFlags = sW.dwFlags;
  1073. psi->dwCaps = sW.dwCaps;
  1074. psi->wPriority = sW.wPriority;
  1075. psi->wLanguage = sW.wLanguage;
  1076. psi->dwScale = sW.dwScale;
  1077. psi->dwRate = sW.dwRate;
  1078. psi->dwStart = sW.dwStart;
  1079. psi->dwLength = sW.dwLength;
  1080. psi->dwInitialFrames = sW.dwInitialFrames;
  1081. psi->dwSuggestedBufferSize = sW.dwSuggestedBufferSize;
  1082. psi->dwQuality = sW.dwQuality;
  1083. psi->dwSampleSize = sW.dwSampleSize;
  1084. psi->rcFrame = sW.rcFrame;
  1085. psi->dwEditCount = sW.dwEditCount;
  1086. psi->dwFormatChangeCount = sW.dwFormatChangeCount;
  1087. // convert the name
  1088. WideCharToMultiByte(CP_ACP, 0, sW.szName, -1,
  1089. psi->szName, NUMELMS(psi->szName), NULL, NULL);
  1090. return hr;
  1091. }
  1092. #endif
  1093. /**************************************************************************
  1094. * @doc EXTERNAL AVIStreamFindSample
  1095. *
  1096. * @api LONG | AVIStreamFindSample | Returns the position of
  1097. * a key frames or non-empty frame relative to the specified position.
  1098. *
  1099. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1100. *
  1101. * @parm LONG | lPos | Specifies the starting position
  1102. * for the search.
  1103. *
  1104. * @parm LONG | lFlags | The following flags are defined:
  1105. *
  1106. * @flag FIND_KEY | Finds a key frame.
  1107. * @flag FIND_ANY | Finds a non-empty sample.
  1108. * @flag FIND_FORMAT | Finds a format change.
  1109. *
  1110. * @flag FIND_NEXT | Finds nearest sample, frame, or format change
  1111. * searching forward. The current sample is
  1112. * included in the search. Use this flag with the
  1113. * FIND_ANY, FIND_KEY, or FIND_FORMAT flag.
  1114. *
  1115. * @flag FIND_PREV | Finds nearest sample, frame, or format change
  1116. * searching backwards. The current sample is
  1117. * included in the search. Use this flag with the
  1118. * FIND_ANY, FIND_KEY, or FIND_FORMAT flag.
  1119. *
  1120. *
  1121. * @comm The FIND_KEY, FIND_ANY, and FIND_FORMAT flags are mutually exclusive.
  1122. * The FIND_NEXT and FIND_PREV flags are also mutually exclusive.
  1123. * For example:
  1124. *
  1125. * @ex FIND_PREV|FIND_KEY Returns the first key sample prior to or at
  1126. * <p lPos>.
  1127. *
  1128. * FIND_PREV|FIND_ANY Returns the first non-empty sample prior to
  1129. * or at <p lPos>.
  1130. *
  1131. * FIND_NEXT|FIND_KEY Returns the first key sample after <p lPos>,
  1132. * or -1 if a key sample does not follow <p lPos>.
  1133. *
  1134. * FIND_NEXT|FIND_ANY Returns the first non-empty sample after <p lPos>,
  1135. * or -1 if a sample does not exist after <p lPos>.
  1136. *
  1137. * FIND_NEXT|FIND_FORMAT Returns the first format change after or
  1138. * at <p lPos>, or -1 if the stream does not
  1139. * have format changes.
  1140. *
  1141. * FIND_PREV|FIND_FORMAT Returns the first format change prior to
  1142. * or at <p lPos>. If the stream does not
  1143. * have format changes, it returns the first sample
  1144. *
  1145. * @rdesc Returns the position found. In many boundary cases, this
  1146. * function will return -1; see the example above for details.
  1147. *
  1148. *************************************************************************/
  1149. STDAPI_(LONG) AVIStreamFindSample(PAVISTREAM pavi, LONG lPos, LONG lFlags)
  1150. {
  1151. // Default to Find Previous Key Frame
  1152. if ((lFlags & FIND_TYPE) == 0)
  1153. lFlags |= FIND_KEY;
  1154. if ((lFlags & FIND_DIR) == 0)
  1155. lFlags |= FIND_PREV;
  1156. return pavi->FindSample(lPos, lFlags);
  1157. }
  1158. /**************************************************************************
  1159. * @doc EXTERNAL AVIStreamReadFormat
  1160. *
  1161. * @api LONG | AVIStreamReadFormat | Reads the stream format data.
  1162. *
  1163. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1164. *
  1165. * @parm LONG | lPos | Specifies the position in the stream
  1166. * used to obtain the format data.
  1167. *
  1168. * @parm LPVOID | lpFormat | Specifies a pointer to a buffer
  1169. * used to return the format data.
  1170. *
  1171. * @parm LONG FAR * | lpcbFormat | Specifies a pointer to a
  1172. * location indicating the size of the memory block
  1173. * referred to by <p lpFormat>. On return, the value is
  1174. * changed to indicate the amount of data read. If
  1175. * <p lpFormat> is NULL, this parameter can be used
  1176. * to obtain the amount of memory needed to return the format.
  1177. *
  1178. * @comm This function will return part of the format even if the buffer
  1179. * provided is not large enough to hold the entire format. In this case
  1180. * the return value will be AVIERR_BUFFERTOOSMALL, and the location
  1181. * referenced by <p lpcbFormat> will be filled in with the size
  1182. * of the entire format.
  1183. *
  1184. * This is useful because it allows you to use a buffer the
  1185. * size of a <t BITMAPINFOHEADER> structure and
  1186. * retrieve just the common part of the video format if you are not
  1187. * interested in extended format information or palette information.
  1188. *
  1189. * @rdesc Returns zero if successful, otherwise it returns an error code.
  1190. *
  1191. *************************************************************************/
  1192. STDAPI AVIStreamReadFormat (PAVISTREAM pavi, LONG lPos,
  1193. LPVOID lpFormat, LONG FAR *lpcbFormat)
  1194. {
  1195. // if (pavi->StreamReadFormat == NULL)
  1196. // return -1;
  1197. return pavi->ReadFormat(lPos, lpFormat, lpcbFormat);
  1198. }
  1199. /**************************************************************************
  1200. * @doc EXTERNAL AVIStreamSetFormat
  1201. *
  1202. * @api LONG | AVIStreamSetFormat | Sets the format of a stream at the
  1203. * specified position.
  1204. *
  1205. * @parm PAVISTREAM | pavi | Specifies a handle to open stream.
  1206. *
  1207. * @parm LONG | lPos | Specifies the position in the stream to
  1208. * receive the format.
  1209. *
  1210. * @parm LPVOID | lpFormat | Specifies a pointer to a structure
  1211. * containing the new format.
  1212. *
  1213. * @parm LONG | cbFormat | Specifies the size of the block of memory
  1214. * referred to by <p lpFormat> in bytes.
  1215. *
  1216. * @comm After creating a new stream with <f AVIFileCreateStream>,
  1217. * call this function to set the stream's format.
  1218. *
  1219. * The handler for writing AVI files does not, in general, accept
  1220. * format changes. Aside from setting the initial format for a
  1221. * stream, only changes in the palette of a video stream are allowed
  1222. * in an AVI file. The palette change must be after
  1223. * any frames already written to the AVI file. Other handlers may
  1224. * impose different restrictions.
  1225. *
  1226. * @rdesc Returns zero if successful, otherwise it returns an error code.
  1227. *
  1228. * @xref <f AVIFileCreateStream> <f AVIStreamReadFormat>
  1229. *
  1230. *************************************************************************/
  1231. STDAPI AVIStreamSetFormat (PAVISTREAM pavi, LONG lPos,
  1232. LPVOID lpFormat, LONG cbFormat)
  1233. {
  1234. // if (pavi->StreamSetFormat == NULL)
  1235. // return -1;
  1236. return pavi->SetFormat(lPos, lpFormat, cbFormat);
  1237. }
  1238. /**************************************************************************
  1239. * @doc EXTERNAL AVIStreamReadData
  1240. *
  1241. * @api LONG | AVIStreamReadData | Reads optional header data from a stream.
  1242. *
  1243. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1244. *
  1245. * @parm DWORD | ckid | Specifies a four-character code identifying the data.
  1246. *
  1247. * @parm LPVOID | lpData | Specifies a pointer to used to return
  1248. * the data read.
  1249. *
  1250. * @parm LONG FAR * | lpcbData | Points to a location which
  1251. * specifies the buffer size used for <p lpData>.
  1252. * If the read is successful, AVIFile changes this value
  1253. * to indicate the amount of data written into the buffer for
  1254. * <p lpData>.
  1255. *
  1256. * @comm This function only retrieves header information
  1257. * from the stream. To read the actual multimedia content of the
  1258. * stream, use <f AVIStreamRead>.
  1259. *
  1260. * @devnote !!! Somewhere, we should specify some types.
  1261. * !!! Should the data block contain the ckid and cksize?
  1262. *
  1263. * @rdesc Returns zero if successful; otherwise it returns an error code.
  1264. * The return value AVIERR_NODATA indicates the system could not
  1265. * find any data with the specified chunk ID.
  1266. *
  1267. * @xref <f AVIFileReadData> <f AVIStreamWriteData> <f AVIStreamWrite>
  1268. *
  1269. *************************************************************************/
  1270. STDAPI AVIStreamReadData (PAVISTREAM pavi, DWORD ckid, LPVOID lpData, LONG FAR *lpcbData)
  1271. {
  1272. // if (pavi->StreamReadData == NULL)
  1273. // return -1;
  1274. return pavi->ReadData(ckid, lpData, lpcbData);
  1275. }
  1276. /**************************************************************************
  1277. * @doc EXTERNAL AVIStreamWriteData
  1278. *
  1279. * @api LONG | AVIStreamWriteData | Writes optional data to the stream.
  1280. *
  1281. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1282. *
  1283. * @parm DWORD | ckid | Specifies a four-character code identifying the data.
  1284. *
  1285. * @parm LPVOID | lpData | Specifies a pointer to a buffer containing
  1286. * the data to write.
  1287. *
  1288. * @parm LONG | cbData | Indicates the number of bytes of data to be copied
  1289. * from <p lpData> into the stream.
  1290. *
  1291. * @comm This function only writes header information to the stream.
  1292. * To write the actual multimedia content of the stream, use
  1293. * <f AVIStreamWrite>. Use <f AVIFileWriteData> to write
  1294. * data that applies to an entire file.
  1295. *
  1296. * This call fails with a return value of AVIERR_READONLY unless
  1297. * the file was opened with write permission.
  1298. *
  1299. * @devnote !!! Somewhere, we should specify some types.
  1300. * !!! Should the data block contain the ckid and cksize?
  1301. *
  1302. * @rdesc Returns zero if successful; otherwise it returns an error code.
  1303. *
  1304. * @xref <f AVIFileWriteData> <f AVIStreamReadData> <f AVIStreamWrite>
  1305. *
  1306. *************************************************************************/
  1307. STDAPI AVIStreamWriteData (PAVISTREAM pavi, DWORD ckid, LPVOID lpData, LONG cbData)
  1308. {
  1309. return pavi->WriteData(ckid, lpData, cbData);
  1310. }
  1311. /**************************************************************************
  1312. * @doc EXTERNAL AVIStreamRead
  1313. *
  1314. * @api LONG | AVIStreamRead | Reads audio or video data from a stream.
  1315. *
  1316. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1317. *
  1318. * @parm LONG | lStart | Specifies the starting sample to read.
  1319. *
  1320. * @parm LONG | lSamples | Specifies the number of samples to read.
  1321. *
  1322. * @parm LPVOID | lpBuffer | Specifies a pointer to a buffer used to
  1323. * return the data.
  1324. *
  1325. * @parm LONG | cbBuffer | Specifies the size of buffer pointed to by <p lpBuffer>.
  1326. *
  1327. * @parm LONG FAR * | plBytes | Specifies a pointer to the location
  1328. * used to return number of bytes of data written into the
  1329. * buffer for <p lpBuffer>. <p plBytes> can be NULL.
  1330. *
  1331. * @parm LONG FAR * | plSamples | Specifies a pointer to the location
  1332. * used to return the number of samples written into the buffer for
  1333. * for <p lpBuffer>. <p plSamples> can be NULL.
  1334. *
  1335. * @comm If <p lpBuffer> is NULL, this function does not read
  1336. * any data; it returns information about the size of data
  1337. * that would be read.
  1338. *
  1339. * See <f AVIStreamLength> for a discussion of how sample numbers
  1340. * correspond to the data you want to read.
  1341. *
  1342. * @rdesc Returns zero if successful, or an error code. Use <p plBytes>
  1343. * and <p plSamples> to find out how much was actually read.
  1344. *
  1345. * Possible errors include:
  1346. *
  1347. * @flag AVIERR_BUFFERTOOSMALL | The buffer size <p cbBuffer> was
  1348. * too small to read in even a single sample of data.
  1349. *
  1350. * @flag AVIERR_MEMORY | There was not enough memory for some
  1351. * reason to complete the read operation.
  1352. *
  1353. * @flag AVIERR_FILEREAD | A disk error occurred while reading the
  1354. * file.
  1355. *
  1356. * @xref <f AVIFileGetStream> <f AVIStreamFindSample> <f AVIStreamWrite>
  1357. *
  1358. *************************************************************************/
  1359. STDAPI AVIStreamRead (PAVISTREAM pavi,
  1360. LONG lStart, LONG lSamples,
  1361. LPVOID lpBuffer, LONG cbBuffer,
  1362. LONG FAR * plBytes, LONG FAR * plSamples)
  1363. {
  1364. // if (pavi->StreamRead == NULL)
  1365. // return -1;
  1366. return pavi->Read(lStart, lSamples, lpBuffer, cbBuffer, plBytes, plSamples);
  1367. }
  1368. /**************************************************************************
  1369. * @doc EXTERNAL AVIStreamWrite
  1370. *
  1371. * @api LONG | AVIStreamWrite | Writes data to a stream.
  1372. *
  1373. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1374. *
  1375. * @parm LONG | lStart | Specifies the starting sample to write.
  1376. *
  1377. * @parm LONG | lSamples | Specifies the number of samples to write.
  1378. *
  1379. * @parm LPVOID | lpBuffer | Specifies a pointer to buffer
  1380. * containing the data to write.
  1381. *
  1382. * @parm LONG | cbBuffer | Specifies the size of buffer used by <p lpBuffer>.
  1383. *
  1384. * @parm DWORD | dwFlags | Specifies any flags associated with this data.
  1385. * The following flags are defined:
  1386. *
  1387. * @flag AVIIF_KEYFRAME | Indicates this data does not rely on preceding
  1388. * data in the file.
  1389. *
  1390. * @parm LONG FAR * | plSampWritten | Specifies a pointer to a location
  1391. * used to return the number of samples written. This can be set
  1392. * to NULL.
  1393. *
  1394. * @parm LONG FAR * | plBytesWritten | Specifies a pointer to a location
  1395. * used to return the number of bytes written. This can be set
  1396. * to NULL.
  1397. *
  1398. * @comm The default AVI file handler only supports writing to the end
  1399. * of a stream. The WAVE file handler supports writing anywhere.
  1400. *
  1401. * This function overwrites existing data, rather than inserting
  1402. * new data.
  1403. *
  1404. * See <f AVIStreamLength> for a discussion of how sample numbers
  1405. * correspond to the data you want to read.
  1406. *
  1407. * @rdesc Returns zero if successful; otherwise it returns an error code.
  1408. *
  1409. * @xref <f AVIFileGetStream> <f AVIFileCreateStream> <f AVIStreamRead>
  1410. *
  1411. *************************************************************************/
  1412. STDAPI AVIStreamWrite (PAVISTREAM pavi,
  1413. LONG lStart, LONG lSamples,
  1414. LPVOID lpBuffer, LONG cbBuffer,
  1415. DWORD dwFlags,
  1416. LONG FAR *plSampWritten,
  1417. LONG FAR *plBytesWritten)
  1418. {
  1419. // if (pavi->StreamWrite == NULL)
  1420. // return -1;
  1421. return pavi->Write(lStart, lSamples, lpBuffer, cbBuffer,
  1422. dwFlags, plSampWritten, plBytesWritten);
  1423. }
  1424. /**************************************************************************
  1425. * @doc INTERNAL AVIStreamDelete
  1426. *
  1427. * @api LONG | AVIStreamDelete | Deletes data from a stream.
  1428. *
  1429. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1430. *
  1431. * @parm LONG | lStart | Specifies the starting sample to delete.
  1432. *
  1433. * @parm LONG | lSamples | Specifies the number of samples to delete.
  1434. *
  1435. * @devnote This isn't implemented by anybody yet. Should it be? Wave files,
  1436. * for instance, would have to copy lots of data around....
  1437. *
  1438. * @rdesc Returns zero if successful; otherwise it returns an error code.
  1439. *
  1440. * @xref
  1441. *
  1442. *************************************************************************/
  1443. STDAPI AVIStreamDelete (PAVISTREAM pavi, LONG lStart, LONG lSamples)
  1444. {
  1445. // if (pavi->StreamDelete == NULL)
  1446. // return -1;
  1447. return pavi->Delete(lStart, lSamples);
  1448. }
  1449. #if 0
  1450. // !!! should this exist?
  1451. STDAPI AVIStreamClone (PAVISTREAM pavi, PAVISTREAM FAR *ppaviNew)
  1452. {
  1453. // if (pavi->StreamClone == NULL)
  1454. // return -1;
  1455. return pavi->Clone(ppaviNew);
  1456. }
  1457. #endif
  1458. /**************************************************************************
  1459. * @doc EXTERNAL AVIStreamStart
  1460. *
  1461. * @api LONG | AVIStreamStart | Returns the starting sample of the stream.
  1462. *
  1463. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1464. *
  1465. * @rdesc Returns the starting sample number for the stream, or -1 on error.
  1466. *
  1467. * @comm See <f AVIStreamLength> for a discussion of how sample numbers
  1468. * correspond to the data you want to read.
  1469. *
  1470. * @xref <f AVIStreamSampleToTime> <f AVIStreamLength>
  1471. *
  1472. *************************************************************************/
  1473. STDAPI_(LONG) AVIStreamStart (PAVISTREAM pavi)
  1474. {
  1475. AVISTREAMINFOW avistream;
  1476. pavi->Info(&avistream, sizeof(avistream));
  1477. return (LONG) avistream.dwStart;
  1478. }
  1479. /**************************************************************************
  1480. * @doc EXTERNAL AVIStreamLength
  1481. *
  1482. * @api LONG | AVIStreamLength | Returns the length of the stream in samples.
  1483. *
  1484. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1485. *
  1486. * @devnote Currently, this doesn't call a handler function at all.
  1487. *
  1488. * @rdesc Returns the stream's length in samples, or -1 on error.
  1489. *
  1490. * @comm Values in samples can be converted to milliseconds using
  1491. * the <f AVIStreamSampleToTime> function.
  1492. *
  1493. * For video streams, each sample generally corresponds to a
  1494. * frame of video. There may, however, be sample numbers for
  1495. * which no video data is actually present: If <f AVIStreamRead>
  1496. * is called at those positions, it will return a data length
  1497. * of zero bytes. You can use <f AVIStreamFindSample> with the
  1498. * FIND_ANY flag to find sample numbers which actually have data.
  1499. *
  1500. * For audio streams, each sample corresponds to one "block"
  1501. * of data. Note the conflicting terminology here: if you're
  1502. * working with 22KHz ADPCM data, each block of audio data is
  1503. * 256 bytes, corresponding to about 500 "audio samples" which
  1504. * will be presented to the speaker each 22000th of a second.
  1505. * From the point of view of the AVIFile APIs, however, each 256-byte
  1506. * block is a single sample, because they cannot be subdivided.
  1507. *
  1508. * Note that the stream's starting position may not be zero; see
  1509. * <f AVIStreamStart>. Valid positions within a stream range from
  1510. * start to start+length; there is no actual data present at position
  1511. * start+length, but that corresponds to a time after the last data
  1512. * has been rendered.
  1513. *
  1514. * @xref <f AVIStreamInfo>
  1515. *
  1516. *************************************************************************/
  1517. STDAPI_(LONG) AVIStreamLength (PAVISTREAM pavi)
  1518. {
  1519. AVISTREAMINFOW avistream;
  1520. HRESULT hr;
  1521. hr = pavi->Info(&avistream, sizeof(avistream));
  1522. if (hr != NOERROR) {
  1523. DPF("Error in AVIStreamLength!\n");
  1524. return 1;
  1525. }
  1526. return (LONG) avistream.dwLength;
  1527. }
  1528. /**************************************************************************
  1529. * @doc EXTERNAL AVIStreamTimeToSample
  1530. *
  1531. * @api LONG | AVIStreamTimeToSample | Converts from milliseconds to samples.
  1532. *
  1533. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1534. *
  1535. * @parm LONG | lTime | Specifies the time in milliseconds.
  1536. *
  1537. * @devnote Currently, this doesn't call a handler function at all.
  1538. *
  1539. * @comm Samples typically correspond to audio samples or video frames.
  1540. * Other stream types might support different formats than these.
  1541. * @rdesc Returns the converted time, or -1 on error.
  1542. *
  1543. * @xref AVIStreamSampleToTime
  1544. *
  1545. *************************************************************************/
  1546. STDAPI_(LONG) AVIStreamTimeToSample (PAVISTREAM pavi, LONG lTime)
  1547. {
  1548. AVISTREAMINFOW avistream;
  1549. HRESULT hr;
  1550. LONG lSample;
  1551. // Invalid time
  1552. if (lTime < 0)
  1553. return -1;
  1554. hr = pavi->Info(&avistream, sizeof(avistream));
  1555. if (hr != NOERROR || avistream.dwScale == 0 || avistream.dwRate == 0) {
  1556. DPF("Error in AVIStreamTimeToSample!\n");
  1557. return lTime;
  1558. }
  1559. // This is likely to overflow if we're not careful for long AVIs
  1560. // so keep the 1000 inside the brackets.
  1561. if (avistream.dwRate / avistream.dwScale < 1000)
  1562. lSample = muldivrd32(lTime, avistream.dwRate, avistream.dwScale * 1000);
  1563. else
  1564. lSample = muldivru32(lTime, avistream.dwRate, avistream.dwScale * 1000);
  1565. lSample = min(max(lSample, (LONG) avistream.dwStart),
  1566. (LONG) (avistream.dwStart + avistream.dwLength));
  1567. return lSample;
  1568. }
  1569. /**************************************************************************
  1570. * @doc EXTERNAL AVIStreamSampleToTime
  1571. *
  1572. * @api LONG | AVIStreamSampleToTime | Converts from samples to milliseconds.
  1573. * Samples can correspond to blocks of audio samples, video frames, or other format
  1574. * depending on the stream type.
  1575. *
  1576. * @parm PAVISTREAM | pavi | Specifies a handle to an open stream.
  1577. *
  1578. * @parm LONG | lSample | Specifies the position information.
  1579. *
  1580. * @rdesc Returns the converted time, or -1 on error.
  1581. *
  1582. * @xref <f AVIStreamTimeToSample>
  1583. *
  1584. *************************************************************************/
  1585. STDAPI_(LONG) AVIStreamSampleToTime (PAVISTREAM pavi, LONG lSample)
  1586. {
  1587. AVISTREAMINFOW avistream;
  1588. HRESULT hr;
  1589. hr = pavi->Info(&avistream, sizeof(avistream));
  1590. if (hr != NOERROR || avistream.dwRate == 0 || avistream.dwScale == 0) {
  1591. DPF("Error in AVIStreamSampleToTime!\n");
  1592. return lSample;
  1593. }
  1594. lSample = min(max(lSample, (LONG) avistream.dwStart),
  1595. (LONG) (avistream.dwStart + avistream.dwLength));
  1596. // lSample * 1000 would overflow too easily
  1597. if (avistream.dwRate / avistream.dwScale < 1000)
  1598. return muldivrd32(lSample, avistream.dwScale * 1000, avistream.dwRate);
  1599. else
  1600. return muldivru32(lSample, avistream.dwScale * 1000, avistream.dwRate);
  1601. }
  1602. /**************************************************************************
  1603. * @doc EXTERNAL AVIStreamOpenFromFile
  1604. *
  1605. * @api LONG | AVIStreamOpenFromFile | This function provides a convenient
  1606. * way to open a single stream from a file.
  1607. *
  1608. * @parm PAVISTREAM FAR * | ppavi | Specifies a pointer to the location
  1609. * used to return the new stream handle.
  1610. *
  1611. * @parm LPCTSTR | szFile | Specifies a zero-terminated string containing
  1612. * the name of the file to open.
  1613. *
  1614. * @parm DWORD | fccType | Specifies a four-character code
  1615. * indicating the type of stream to be opened.
  1616. * Zero indicates that any stream can be opened. The following
  1617. * definitions apply to the data commonly
  1618. * found in AVI streams:
  1619. *
  1620. * @flag streamtypeAUDIO | Indicates an audio stream.
  1621. * @flag streamtypeMIDI | Indicates a MIDI stream.
  1622. * @flag streamtypeTEXT | Indicates a text stream.
  1623. * @flag streamtypeVIDEO | Indicates a video stream.
  1624. *
  1625. * @parm LONG | lParam | Indicates which stream of the type specified in
  1626. * <p fccType> should actually be accessed.
  1627. *
  1628. * @parm UINT | mode | Specifies the mode to use when opening the file.
  1629. * This function can only open existing streams so the OF_CREATE
  1630. * mode flag cannot be used. See
  1631. * <f OpenFile> for more information about the available flags.
  1632. *
  1633. * @parm CLSID FAR * | pclsidHandler | Specifies a pointer to a class ID
  1634. * identifying the handler you want to use. If NULL, the system
  1635. * chooses one from the registration database based on the file
  1636. * extension or the file's RIFF type.
  1637. *
  1638. * @comm Balance each call to <f AVIStreamOpenFromFile> with a
  1639. * call to <f AVIStreamRelease> using the stream handle returned.
  1640. *
  1641. * This function calls <f AVIFileOpen>, <f AVIFileGetStream>, and
  1642. * <f AVIFileRelease>.
  1643. *
  1644. * @rdesc Returns zero if successful; otherwise it returns an error code.
  1645. *
  1646. * @xref <f AVIFileOpen> <f AVIFileGetStream>
  1647. *
  1648. *************************************************************************/
  1649. STDAPI AVIStreamOpenFromFileW(PAVISTREAM FAR *ppavi,
  1650. LPCWSTR szFile,
  1651. DWORD fccType, LONG lParam,
  1652. UINT mode, CLSID FAR *pclsidHandler)
  1653. {
  1654. PAVIFILE pfile;
  1655. HRESULT hr;
  1656. hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
  1657. if (!FAILED(GetScode(hr))) {
  1658. hr = AVIFileGetStream(pfile, ppavi, fccType, lParam);
  1659. AVIFileRelease(pfile); // the stream still has a reference to the file
  1660. }
  1661. return hr;
  1662. }
  1663. #ifdef _WIN32
  1664. // Ansi thunk
  1665. STDAPI AVIStreamOpenFromFileA(PAVISTREAM FAR *ppavi,
  1666. LPCSTR szFile,
  1667. DWORD fccType, LONG lParam,
  1668. UINT mode, CLSID FAR *pclsidHandler)
  1669. {
  1670. PAVIFILE pfile;
  1671. HRESULT hr;
  1672. hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
  1673. if (!FAILED(GetScode(hr))) {
  1674. hr = AVIFileGetStream(pfile, ppavi, fccType, lParam);
  1675. AVIFileRelease(pfile); // the stream still has a reference to the file
  1676. }
  1677. return hr;
  1678. }
  1679. #endif
  1680. /**************************************************************************
  1681. * @doc EXTERNAL AVIStreamCreate
  1682. *
  1683. * @api LONG | AVIStreamCreate | Creates a stream not associated with any
  1684. * file.
  1685. *
  1686. * @parm PAVISTREAM FAR * | ppavi | Pointer to a location to return the
  1687. * new stream handle.
  1688. *
  1689. * @parm LONG | lParam1 | Specifies stream-handler specific information.
  1690. *
  1691. * @parm LONG | lParam2 | Specifies stream-handler specific information.
  1692. *
  1693. * @parm CLSID FAR * | pclsidHandler | Pointer to the class ID used
  1694. * for the stream.
  1695. *
  1696. * @comm Balance each call to <f AVIStreamCreate> with a
  1697. * call to <f AVIStreamRelease>.
  1698. *
  1699. * You should not need to call this function; functions like
  1700. * <f CreateEditableStream> and <f AVIMakeCompressedStream>
  1701. * use it internally.
  1702. *
  1703. * @rdesc Returns zero if successful; otherwise returns an error code.
  1704. *
  1705. * @xref <f AVIFileOpen> <f AVIFileGetStream>
  1706. *
  1707. *************************************************************************/
  1708. STDAPI AVIStreamCreate (PAVISTREAM FAR *ppavi, LONG lParam1, LONG lParam2,
  1709. CLSID FAR *pclsidHandler)
  1710. {
  1711. CLSID clsid;
  1712. HRESULT hr;
  1713. if (!iInit) {
  1714. return ResultFromScode(E_UNEXPECTED);
  1715. }
  1716. if (pclsidHandler)
  1717. clsid = *pclsidHandler;
  1718. else {
  1719. return ResultFromScode(REGDB_E_CLASSNOTREG);
  1720. }
  1721. if (FAILED(GetScode(hr = CoCreateInstance((REFCLSID) clsid,
  1722. NULL, CLSCTX_INPROC,
  1723. (REFIID) IID_IAVIStream,
  1724. (void FAR* FAR*)ppavi))))
  1725. return hr;
  1726. if (FAILED(GetScode(hr = (*ppavi)->Create(lParam1, lParam2)))) {
  1727. (*ppavi)->Release();
  1728. // AVIStreamExit();
  1729. }
  1730. return AVIERR_OK;
  1731. }
  1732. /**************************************************************************
  1733. * @doc EXTERNAL AVIStreamBeginStreaming
  1734. *
  1735. * @api LONG | AVIStreamBeginStreaming | Specifies the parameters for
  1736. * streaming and lets a stream handler prepare for streaming.
  1737. *
  1738. * @parm PAVISTREAM | pavi | Specifies a pointer to a stream.
  1739. *
  1740. * @parm LONG | lStart | Specifies the starting point for streaming.
  1741. *
  1742. * @parm LONG | lEnd | Specifies the ending point for streaming.
  1743. *
  1744. * @parm LONG | lRate | Specifies the speed at which the file will be
  1745. * read relative to its natural speed. Specify 1000 for the normal speed.
  1746. *
  1747. * @comm Many stream implementations ignore this function.
  1748. *
  1749. * @rdesc Returns zero if successful; otherwise returns an error code.
  1750. *
  1751. * @xref <f AVIStreamEndStreaming>
  1752. *
  1753. *************************************************************************/
  1754. STDAPI AVIStreamBeginStreaming(PAVISTREAM pavi,
  1755. LONG lStart,
  1756. LONG lEnd,
  1757. LONG lRate)
  1758. {
  1759. IAVIStreaming FAR * pi;
  1760. HRESULT hr;
  1761. if (FAILED(GetScode(pavi->QueryInterface(IID_IAVIStreaming,
  1762. (void FAR* FAR*) &pi))))
  1763. return AVIERR_OK;
  1764. hr = pi->Begin(lStart, lEnd, lRate);
  1765. pi->Release();
  1766. return hr;
  1767. }
  1768. /**************************************************************************
  1769. * @doc EXTERNAL AVIStreamEndStreaming
  1770. *
  1771. * @api LONG | AVIStreamEndStreaming | Ends streaming.
  1772. *
  1773. * @parm PAVISTREAM | pavi | Specifies a pointer to a stream.
  1774. *
  1775. * @comm Many stream implementations ignore this function.
  1776. *
  1777. * @rdesc Returns zero if successful; otherwise it returns an error code.
  1778. *
  1779. * @xref AVIStreamBeginStreaming
  1780. *
  1781. *************************************************************************/
  1782. STDAPI AVIStreamEndStreaming(PAVISTREAM pavi)
  1783. {
  1784. IAVIStreaming FAR * pi;
  1785. HRESULT hr;
  1786. if (FAILED(GetScode(pavi->QueryInterface(IID_IAVIStreaming, (LPVOID FAR *) &pi))))
  1787. return AVIERR_OK;
  1788. hr = pi->End();
  1789. pi->Release();
  1790. return hr;
  1791. }
  1792. #if 0
  1793. /*******************************************************************
  1794. * @doc INTERNAL AVIStreamHasChanged
  1795. *
  1796. * @api LONG | AVIStreamHasChanged | This function forces an update
  1797. * of the strem information for the specified stream.
  1798. *
  1799. * @parm PAVISTREAM | pavi | Interface pointer for an AVI stream instance.
  1800. *
  1801. * @rdesc Returns AVIERR_OK on success.
  1802. *
  1803. ****************************************************************/
  1804. STDAPI AVIStreamHasChanged(PAVISTREAM pavi)
  1805. {
  1806. pavi->lFrame = -4224; // bogus value
  1807. AVIStreamInfo(pavi, &pavi->avistream, sizeof(pavi->avistream));
  1808. // !!! Only need to do this if format changes?
  1809. AVIReleaseCachedData(pavi);
  1810. return AVIERR_OK;
  1811. }
  1812. #endif
  1813. #ifdef _WIN32
  1814. static SZCODE aszRegCompressors[] = TEXT("AVIFile\\Compressors\\%.4hs");
  1815. #else
  1816. static SZCODE aszRegCompressors[] = TEXT("AVIFile\\Compressors\\%.4ls");
  1817. #endif
  1818. /*******************************************************************
  1819. * @doc EXTERNAL AVIMakeCompressedStream
  1820. *
  1821. * @api HRESULT | AVIMakeCompressedStream | Returns a pointer to a
  1822. * compressed stream created from an uncompressed stream.
  1823. * The uncompressed stream is compressed using
  1824. * the compression options specified.
  1825. *
  1826. * @parm PAVISTREAM FAR * | ppsCompressed | Specifies a pointer to
  1827. * the location used to return the compressed stream pointer.
  1828. *
  1829. * @parm PAVISTREAM | psSource | Specifies a pointer to the stream to be compressed.
  1830. *
  1831. * @parm AVICOMPRESSOPTIONS FAR * | lpOptions | Specifies a pointer to a
  1832. * structure indicating the type compression to use and the options
  1833. * to apply.
  1834. *
  1835. * @parm CLSID FAR * | pclsidHandler | Specifies a pointer to a
  1836. * class ID used to create the stream.
  1837. *
  1838. * @comm This supports both audio and video compression. Applications
  1839. * can use the created stream for reading or writing.
  1840. *
  1841. * For video compression, either specify a handler to use or specify
  1842. * the format for the compressed data.
  1843. *
  1844. * For audio compression, you can only specify a format for the compressed
  1845. * data.
  1846. *
  1847. * @rdesc Returns AVIERR_OK on success, or an error code.
  1848. * Possible errors include:
  1849. *
  1850. * @flag AVIERR_NOCOMPRESSOR | No suitable compressor can be found.
  1851. *
  1852. * @flag AVIERR_MEMORY | There was not enough memory to complete the operation.
  1853. *
  1854. * @flag AVIERR_UNSUPPORTED | Compression is not supported for this type
  1855. * of data. This error may be returned if you try to compress
  1856. * data that is not audio or video.
  1857. *
  1858. *
  1859. *
  1860. ****************************************************************/
  1861. STDAPI AVIMakeCompressedStream(
  1862. PAVISTREAM FAR * ppsCompressed,
  1863. PAVISTREAM psSource,
  1864. AVICOMPRESSOPTIONS FAR * lpOptions,
  1865. CLSID FAR *pclsidHandler)
  1866. {
  1867. CLSID clsid;
  1868. TCHAR achKey[100];
  1869. TCHAR achClass[100];
  1870. LONG lcbClass;
  1871. AVISTREAMINFO strhdr;
  1872. HRESULT hr;
  1873. *ppsCompressed = NULL;
  1874. if (pclsidHandler) {
  1875. clsid = *pclsidHandler;
  1876. } else {
  1877. if (FAILED(GetScode(hr = AVIStreamInfo(psSource,
  1878. &strhdr,
  1879. sizeof(strhdr)))))
  1880. return hr;
  1881. // Look up the stream type in the registration database to find
  1882. // the appropriate compressor....
  1883. wsprintf(achKey, aszRegCompressors, (LPSTR) &strhdr.fccType);
  1884. lcbClass = sizeof(achClass);
  1885. RegQueryValue(HKEY_CLASSES_ROOT, achKey, achClass, &lcbClass);
  1886. if (!GUIDFromString(achClass, &clsid))
  1887. return ResultFromScode(AVIERR_UNSUPPORTED);
  1888. }
  1889. if (FAILED(GetScode(hr = CoCreateInstance((REFCLSID) clsid,
  1890. NULL, CLSCTX_INPROC,
  1891. (REFIID) IID_IAVIStream,
  1892. (void FAR* FAR*)ppsCompressed))))
  1893. return hr; // !!! PropagateHResult?
  1894. if (FAILED(GetScode(hr = (*ppsCompressed)->Create((LPARAM) psSource,
  1895. (LPARAM) lpOptions)))) {
  1896. (*ppsCompressed)->Release();
  1897. *ppsCompressed = NULL;
  1898. return hr;
  1899. }
  1900. return AVIERR_OK;
  1901. }
  1902. typedef struct {
  1903. TCHAR achClsid[64];
  1904. TCHAR achExtString[128];
  1905. } TEMPFILTER, FAR * LPTEMPFILTER;
  1906. SZCODE aszAnotherExtension[] = TEXT(";*.%s");
  1907. /***************************************************************************
  1908. *
  1909. * @doc INTERNAL MCIAVI
  1910. *
  1911. * @api LONG | atol | local version of atol
  1912. *
  1913. ***************************************************************************/
  1914. static LONG NEAR PASCAL atol(TCHAR FAR *sz)
  1915. {
  1916. LONG l = 0;
  1917. while (*sz)
  1918. l = l*10 + *sz++ - TEXT('0');
  1919. return l;
  1920. }
  1921. // lstrcat lines will compile wrong with optimizations
  1922. // compiler! - Have less bugs!
  1923. #ifndef _WIN32
  1924. #pragma optimize("", off)
  1925. #endif
  1926. /*******************************************************************
  1927. * @doc EXTERNAL AVIBuildFilter
  1928. *
  1929. * @api HRESULT | AVIBuildFilter | Builds a filter specification for passing
  1930. * to <f GetOpenFileName> or <f GetSaveFileName>.
  1931. *
  1932. * @parm LPTSTR | lpszFilter | Pointer to buffer where the filter string
  1933. * should be returned.
  1934. *
  1935. * @parm LONG | cbFilter | Size of buffer pointed to by <p lpszFilter>.
  1936. *
  1937. * @parm BOOL | fSaving | Indicates whether the filter should include only
  1938. * formats that can be written, or all formats that can be read.
  1939. *
  1940. * @rdesc Returns AVIERR_OK on success.
  1941. *
  1942. * @comm This function does not check if the DLLs referenced
  1943. * in the registration database actually exist.
  1944. *
  1945. ****************************************************************/
  1946. STDAPI AVIBuildFilter(LPTSTR lpszFilter, LONG cbFilter, BOOL fSaving)
  1947. {
  1948. #define MAXFILTERS 256
  1949. LPTEMPFILTER lpf;
  1950. int i;
  1951. int cf = 0;
  1952. HKEY hkey;
  1953. LONG lRet;
  1954. DWORD dwSubKey;
  1955. TCHAR ach[128];
  1956. TCHAR ach2[128];
  1957. TCHAR achExt[10];
  1958. LONG cb;
  1959. TCHAR achAllFiles[40];
  1960. int cbAllFiles;
  1961. // This string has a NULL in it, so remember its length for real....
  1962. cbAllFiles = LoadString(ghMod,
  1963. IDS_ALLFILES,
  1964. achAllFiles,
  1965. sizeof(achAllFiles)/sizeof(TCHAR));
  1966. for (i = 0; i < cbAllFiles; i++)
  1967. if (achAllFiles[i] == TEXT('@'))
  1968. achAllFiles[i] = TEXT('\0');
  1969. // Allocate a largish amount of memory (98304 until the constants change)
  1970. lpf = (LPTEMPFILTER) GlobalAllocPtr(GHND, sizeof(TEMPFILTER) * MAXFILTERS);
  1971. if (!lpf) {
  1972. return ResultFromScode(AVIERR_MEMORY);
  1973. }
  1974. lRet = RegOpenKey(HKEY_CLASSES_ROOT, aszRegExt, &hkey);
  1975. if (lRet != ERROR_SUCCESS) {
  1976. GlobalFreePtr(lpf);
  1977. return ResultFromScode(AVIERR_ERROR);
  1978. }
  1979. // Make sure that AVI files come first in the list....
  1980. // !!! Should use StringFromClsid here!
  1981. lstrcpy(lpf[1].achClsid, TEXT("{00020000-0000-0000-C000-000000000046}"));
  1982. cf = 1;
  1983. //
  1984. // First, scan through the Extensions list looking for all of the
  1985. // handlers that are installed
  1986. //
  1987. for (dwSubKey = 0; ; dwSubKey++) {
  1988. lRet = RegEnumKey(hkey, dwSubKey, achExt, sizeof(achExt)/sizeof(achExt[0]));
  1989. if (lRet != ERROR_SUCCESS) {
  1990. break;
  1991. }
  1992. cb = sizeof(ach);
  1993. lRet = RegQueryValue(hkey, achExt, ach, &cb);
  1994. if (lRet != ERROR_SUCCESS) {
  1995. break;
  1996. }
  1997. //
  1998. // See if we've seen this handler before
  1999. //
  2000. for (i = 1; i <= cf; i++) {
  2001. if (lstrcmp(ach, lpf[i].achClsid) == 0) {
  2002. break;
  2003. }
  2004. }
  2005. //
  2006. // If not, add it to our list of handlers
  2007. //
  2008. if (i == cf + 1) {
  2009. if (cf == MAXFILTERS) {
  2010. DPF("Too many filters!\n");
  2011. continue;
  2012. }
  2013. lstrcpy(lpf[i].achClsid, ach);
  2014. cb = sizeof(ach);
  2015. wsprintf(ach2, TEXT("%s\\AVIFile"), (LPTSTR) ach);
  2016. lRet = RegQueryValue(hkey, ach2, ach, &cb);
  2017. if (ERROR_SUCCESS == lRet) {
  2018. lRet = atol(ach);
  2019. if (fSaving) {
  2020. if (!(lRet & AVIFILEHANDLER_CANWRITE))
  2021. continue;
  2022. } else {
  2023. if (!(lRet & AVIFILEHANDLER_CANREAD))
  2024. continue;
  2025. }
  2026. }
  2027. cf++;
  2028. }
  2029. wsprintf(ach, aszAnotherExtension, (LPTSTR) achExt);
  2030. lstrcat(lpf[i].achExtString, lpf[i].achExtString[0] ?
  2031. ach : ach + 1);
  2032. lstrcat(lpf[0].achExtString, lpf[0].achExtString[0] ?
  2033. ach : ach + 1);
  2034. }
  2035. RegCloseKey(hkey);
  2036. lRet = RegOpenKey(HKEY_CLASSES_ROOT, aszRegClsid, &hkey);
  2037. if (lRet != ERROR_SUCCESS) {
  2038. GlobalFreePtr(lpf);
  2039. return ResultFromScode(AVIERR_ERROR);
  2040. }
  2041. //
  2042. // Now, scan through our list of handlers and build up the
  2043. // filter to use....
  2044. //
  2045. for (i = 0; i <= cf; i++) {
  2046. if (i == 0) {
  2047. cb = wsprintf(lpszFilter, TEXT("All multimedia files")) + 1; // !!!
  2048. } else {
  2049. cb = sizeof(ach);
  2050. lRet = RegQueryValue(hkey, lpf[i].achClsid, ach, &cb);
  2051. if (ERROR_SUCCESS != lRet) {
  2052. continue; // iterate if we fail to read the data
  2053. }
  2054. if (cbFilter < (LONG)(lstrlen(lpf[i].achExtString) +
  2055. (LONG)lstrlen(ach) + 10)) {
  2056. break; // !!!
  2057. }
  2058. cb = wsprintf(lpszFilter, TEXT("%s"), // "%s (%s)", Todd doesn't like this
  2059. (LPTSTR) ach, (LPTSTR) lpf[i].achExtString) + 1;
  2060. }
  2061. cbFilter -= cb;
  2062. lpszFilter += cb;
  2063. #ifdef UNICODE
  2064. lstrcpynW(
  2065. #else
  2066. _fstrncpy(
  2067. #endif
  2068. lpszFilter, lpf[i].achExtString, (int) cbFilter);
  2069. cbFilter -= lstrlen(lpf[i].achExtString) + 1;
  2070. lpszFilter += lstrlen(lpf[i].achExtString) + 1;
  2071. if (cbFilter <= 0) {
  2072. GlobalFreePtr(lpf);
  2073. RegCloseKey(hkey);
  2074. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  2075. }
  2076. }
  2077. if (cbFilter > cbAllFiles) {
  2078. _fmemcpy(lpszFilter, achAllFiles, cbAllFiles*sizeof(TCHAR));
  2079. cbFilter -= cbAllFiles;
  2080. lpszFilter += cbAllFiles;
  2081. }
  2082. RegCloseKey(hkey);
  2083. *lpszFilter++ = TEXT('\0');
  2084. --cbFilter; // This line is bogus
  2085. GlobalFreePtr(lpf);
  2086. return AVIERR_OK;
  2087. }
  2088. #ifndef _WIN32
  2089. #pragma optimize("", on)
  2090. #endif
  2091. #ifdef UNICODE
  2092. // Ansi thunk for AVIBuildFilter
  2093. STDAPI AVIBuildFilterA(LPSTR lpszFilter, LONG cbFilter, BOOL fSaving)
  2094. {
  2095. // get the UNICODE filter block
  2096. LPWSTR lpW, lpWSave;
  2097. HRESULT hr;
  2098. int sz;
  2099. int cbCount,cbMFilter=0;
  2100. lpWSave = lpW = (LPWSTR)(LocalAlloc(LPTR, cbFilter * sizeof(WCHAR)));
  2101. hr = AVIBuildFilterW(lpW, cbFilter, fSaving);
  2102. if (FAILED(hr)) {
  2103. LocalFree((HANDLE)lpW);
  2104. return hr;
  2105. }
  2106. // now translate each null-term unicode string in the double-null block
  2107. LPSTR pFilter = lpszFilter;
  2108. while( (sz = lstrlen(lpW)) > 0) {
  2109. // add on space for NULL
  2110. sz++;
  2111. //#ifdef DBCS
  2112. //The maximum number of DBCS Multibyte string bytes is not equal
  2113. // to the number of Widechar string charcters.
  2114. cbCount = WideCharToMultiByte(CP_ACP, 0, lpW, -1,
  2115. pFilter, cbFilter-cbMFilter-1, NULL, NULL);
  2116. cbMFilter += cbCount;
  2117. pFilter += cbCount;
  2118. lpW += sz;
  2119. if( cbMFilter >= cbFilter-1 ) break;
  2120. //#else
  2121. // wcstombs(pFilter, lpW, sz);
  2122. // lpW += sz;
  2123. // pFilter += sz;
  2124. //#endif
  2125. }
  2126. // add extra terminating null
  2127. *pFilter = '\0';
  2128. LocalFree((HANDLE)lpWSave);
  2129. return hr;
  2130. }
  2131. #else
  2132. #ifdef _WIN32
  2133. STDAPI AVIBuildFilterW(LPWSTR lpszFilter, LONG cbFilter, BOOL fSaving)
  2134. {
  2135. return E_FAIL;
  2136. }
  2137. #endif
  2138. #endif
  2139. /*****************************************************************************
  2140. *
  2141. * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  2142. *
  2143. * The messages will be send to COM1: like any debug message. To
  2144. * enable debug output, add the following to WIN.INI :
  2145. *
  2146. * [debug]
  2147. * ICSAMPLE=1
  2148. *
  2149. ****************************************************************************/
  2150. #ifdef DEBUG
  2151. //
  2152. // I wish languages would make up their mind about defines!!!!!
  2153. //
  2154. #ifndef WINDLL
  2155. #define WINDLL
  2156. #define _WINDLL
  2157. #define __WINDLL
  2158. #endif
  2159. #include <stdarg.h>
  2160. #define MODNAME "AVIFILE"
  2161. static int iDebug = -1;
  2162. void cdecl dpf(LPSTR szFormat, va_list va)
  2163. {
  2164. #ifdef _WIN32
  2165. char ach[512];
  2166. #else
  2167. char ach[128];
  2168. #endif
  2169. UINT n=0;
  2170. if (szFormat[0] == '!')
  2171. ach[0]=0, szFormat++;
  2172. else {
  2173. #ifdef _WIN32
  2174. n = wsprintfA(ach, MODNAME": (tid %x) ", GetCurrentThreadId());
  2175. #else
  2176. lstrcpyA(ach, MODNAME ": ");
  2177. n = lstrlenA(ach);
  2178. #endif
  2179. }
  2180. wvsprintfA(ach+n,szFormat,va);
  2181. OutputDebugStringA(ach);
  2182. }
  2183. void cdecl dprintf0(LPSTR szFormat, ...)
  2184. {
  2185. va_list va;
  2186. va_start(va, szFormat);
  2187. dpf(szFormat, va);
  2188. va_end(va);
  2189. }
  2190. void cdecl dprintf(LPSTR szFormat, ...)
  2191. {
  2192. if (iDebug == -1)
  2193. iDebug = GetProfileIntA("Debug", MODNAME, 0);
  2194. if (iDebug < 1)
  2195. return;
  2196. va_list va;
  2197. va_start(va, szFormat);
  2198. dpf(szFormat, va);
  2199. va_end(va);
  2200. }
  2201. void cdecl dprintf2(LPSTR szFormat, ...)
  2202. {
  2203. if (iDebug == -1)
  2204. iDebug = GetProfileIntA("Debug", MODNAME, 0);
  2205. if (iDebug < 2)
  2206. return;
  2207. va_list va;
  2208. va_start(va, szFormat);
  2209. dpf(szFormat, va);
  2210. va_end(va);
  2211. }
  2212. void cdecl dprintf3(LPSTR szFormat, ...)
  2213. {
  2214. if (iDebug == -1)
  2215. iDebug = GetProfileIntA("Debug", MODNAME, 0);
  2216. if (iDebug < 3)
  2217. return;
  2218. va_list va;
  2219. va_start(va, szFormat);
  2220. dpf(szFormat, va);
  2221. va_end(va);
  2222. }
  2223. #endif
  2224. #ifdef DEBUG
  2225. /* _Assert(szExpr, szFile, iLine)
  2226. *
  2227. * If <fExpr> is TRUE, then do nothing. If <fExpr> is FALSE, then display
  2228. * an "assertion failed" message box allowing the user to abort the program,
  2229. * enter the debugger (the "Retry" button), or igore the error.
  2230. *
  2231. * <szFile> is the name of the source file; <iLine> is the line number
  2232. * containing the _Assert() call.
  2233. */
  2234. void FAR PASCAL
  2235. _Assert(char *szExp, char *szFile, int iLine)
  2236. {
  2237. static char ach[300]; // debug output (avoid stack overflow)
  2238. int id;
  2239. void FAR PASCAL DebugBreak(void);
  2240. /* display error message */
  2241. if (szExp)
  2242. wsprintfA(ach, "(%s)\nFile %s, line %d", (LPSTR)szExp, (LPSTR)szFile, iLine);
  2243. else
  2244. wsprintfA(ach, "File %s, line %d", (LPSTR) szFile, iLine);
  2245. MessageBeep(MB_ICONHAND);
  2246. id = MessageBoxA(NULL, ach, "Assertion Failed", MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE);
  2247. /* abort, debug, or ignore */
  2248. switch (id)
  2249. {
  2250. case IDABORT:
  2251. FatalAppExit(0, TEXT("Good Bye"));
  2252. break;
  2253. case IDRETRY:
  2254. /* break into the debugger */
  2255. DebugBreak();
  2256. break;
  2257. case IDIGNORE:
  2258. /* ignore the assertion failure */
  2259. break;
  2260. }
  2261. }
  2262. #endif