1 /* 2 * Copyright 1999 Marcus Meissner 3 * Copyright 2002-2003 Michael Günnewig 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <stdarg.h> 21 22 #define COBJMACROS 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "winnls.h" 27 #include "wingdi.h" 28 #include "winuser.h" 29 #include "winreg.h" 30 #include "winerror.h" 31 32 #include "ole2.h" 33 #include "shellapi.h" 34 #include "shlobj.h" 35 #include "vfw.h" 36 #include "msacm.h" 37 38 #include "avifile_private.h" 39 40 #include "wine/debug.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(avifile); 43 44 45 /*********************************************************************** 46 * for AVIBuildFilterW -- uses fixed size table 47 */ 48 #define MAX_FILTERS 30 /* 30 => 7kB */ 49 50 typedef struct _AVIFilter { 51 WCHAR szClsid[40]; 52 WCHAR szExtensions[MAX_FILTERS * 7]; 53 } AVIFilter; 54 55 /*********************************************************************** 56 * for AVISaveOptions 57 */ 58 static struct { 59 UINT uFlags; 60 INT nStreams; 61 PAVISTREAM *ppavis; 62 LPAVICOMPRESSOPTIONS *ppOptions; 63 INT nCurrent; 64 } SaveOpts; 65 66 /*********************************************************************** 67 * copied from dlls/ole32/compobj.c 68 */ 69 static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id) 70 { 71 BYTE const *s; 72 BYTE *p; 73 INT i; 74 BYTE table[256]; 75 76 if (!idstr) { 77 memset(id, 0, sizeof(CLSID)); 78 return S_OK; 79 } 80 81 /* validate the CLSID string */ 82 if (lstrlenA(idstr) != 38) 83 return CO_E_CLASSSTRING; 84 85 s = (BYTE const*)idstr; 86 if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || 87 (s[24]!='-') || (s[37]!='}')) 88 return CO_E_CLASSSTRING; 89 90 for (i = 1; i < 37; i++) { 91 if ((i == 9) || (i == 14) || (i == 19) || (i == 24)) 92 continue; 93 if (!(((s[i] >= '0') && (s[i] <= '9')) || 94 ((s[i] >= 'a') && (s[i] <= 'f')) || 95 ((s[i] >= 'A') && (s[i] <= 'F'))) 96 ) 97 return CO_E_CLASSSTRING; 98 } 99 100 TRACE("%s -> %p\n", s, id); 101 102 /* quick lookup table */ 103 memset(table, 0, 256); 104 105 for (i = 0; i < 10; i++) 106 table['0' + i] = i; 107 108 for (i = 0; i < 6; i++) { 109 table['A' + i] = i+10; 110 table['a' + i] = i+10; 111 } 112 113 /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ 114 p = (BYTE *) id; 115 116 s++; /* skip leading brace */ 117 for (i = 0; i < 4; i++) { 118 p[3 - i] = table[*s]<<4 | table[*(s+1)]; 119 s += 2; 120 } 121 p += 4; 122 s++; /* skip - */ 123 124 for (i = 0; i < 2; i++) { 125 p[1-i] = table[*s]<<4 | table[*(s+1)]; 126 s += 2; 127 } 128 p += 2; 129 s++; /* skip - */ 130 131 for (i = 0; i < 2; i++) { 132 p[1-i] = table[*s]<<4 | table[*(s+1)]; 133 s += 2; 134 } 135 p += 2; 136 s++; /* skip - */ 137 138 /* these are just sequential bytes */ 139 for (i = 0; i < 2; i++) { 140 *p++ = table[*s]<<4 | table[*(s+1)]; 141 s += 2; 142 } 143 s++; /* skip - */ 144 145 for (i = 0; i < 6; i++) { 146 *p++ = table[*s]<<4 | table[*(s+1)]; 147 s += 2; 148 } 149 150 return S_OK; 151 } 152 153 static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid) 154 { 155 CHAR szRegKey[25]; 156 CHAR szValue[100]; 157 LPWSTR szExt = wcsrchr(szFile, '.'); 158 LONG len = ARRAY_SIZE(szValue); 159 160 if (szExt == NULL) 161 return FALSE; 162 163 szExt++; 164 165 wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt); 166 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS) 167 return FALSE; 168 169 return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK); 170 } 171 172 /*********************************************************************** 173 * AVIFileInit (AVIFIL32.@) 174 */ 175 void WINAPI AVIFileInit(void) { 176 OleInitialize(NULL); 177 } 178 179 /*********************************************************************** 180 * AVIFileExit (AVIFIL32.@) 181 */ 182 void WINAPI AVIFileExit(void) { 183 /* need to free ole32.dll if we are the last exit call */ 184 /* OleUninitialize() */ 185 FIXME("(): stub!\n"); 186 } 187 188 /*********************************************************************** 189 * AVIFileOpen (AVIFIL32.@) 190 * AVIFileOpenA (AVIFIL32.@) 191 */ 192 HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode, 193 LPCLSID lpHandler) 194 { 195 LPWSTR wszFile = NULL; 196 HRESULT hr; 197 int len; 198 199 TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode, 200 debugstr_guid(lpHandler)); 201 202 /* check parameters */ 203 if (ppfile == NULL || szFile == NULL) 204 return AVIERR_BADPARAM; 205 206 /* convert ASCII string to Unicode and call unicode function */ 207 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0); 208 if (len <= 0) 209 return AVIERR_BADPARAM; 210 211 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 212 if (wszFile == NULL) 213 return AVIERR_MEMORY; 214 215 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len); 216 217 hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler); 218 219 HeapFree(GetProcessHeap(), 0, wszFile); 220 221 return hr; 222 } 223 224 /*********************************************************************** 225 * AVIFileOpenW (AVIFIL32.@) 226 */ 227 HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode, 228 LPCLSID lpHandler) 229 { 230 IPersistFile *ppersist = NULL; 231 CLSID clsidHandler; 232 HRESULT hr; 233 234 TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode, 235 debugstr_guid(lpHandler)); 236 237 /* check parameters */ 238 if (ppfile == NULL || szFile == NULL) 239 return AVIERR_BADPARAM; 240 241 *ppfile = NULL; 242 243 /* if no handler then try guessing it by extension */ 244 if (lpHandler == NULL) { 245 if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler)) 246 clsidHandler = CLSID_AVIFile; 247 } else 248 clsidHandler = *lpHandler; 249 250 /* create instance of handler */ 251 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile); 252 if (FAILED(hr) || *ppfile == NULL) 253 return hr; 254 255 /* ask for IPersistFile interface for loading/creating the file */ 256 hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist); 257 if (FAILED(hr) || ppersist == NULL) { 258 IAVIFile_Release(*ppfile); 259 *ppfile = NULL; 260 return hr; 261 } 262 263 hr = IPersistFile_Load(ppersist, szFile, uMode); 264 IPersistFile_Release(ppersist); 265 if (FAILED(hr)) { 266 IAVIFile_Release(*ppfile); 267 *ppfile = NULL; 268 } 269 270 return hr; 271 } 272 273 /*********************************************************************** 274 * AVIFileAddRef (AVIFIL32.@) 275 */ 276 ULONG WINAPI AVIFileAddRef(PAVIFILE pfile) 277 { 278 TRACE("(%p)\n", pfile); 279 280 if (pfile == NULL) { 281 ERR(": bad handle passed!\n"); 282 return 0; 283 } 284 285 return IAVIFile_AddRef(pfile); 286 } 287 288 /*********************************************************************** 289 * AVIFileRelease (AVIFIL32.@) 290 */ 291 ULONG WINAPI AVIFileRelease(PAVIFILE pfile) 292 { 293 TRACE("(%p)\n", pfile); 294 295 if (pfile == NULL) { 296 ERR(": bad handle passed!\n"); 297 return 0; 298 } 299 300 return IAVIFile_Release(pfile); 301 } 302 303 /*********************************************************************** 304 * AVIFileInfo (AVIFIL32.@) 305 * AVIFileInfoA (AVIFIL32.@) 306 */ 307 HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size) 308 { 309 AVIFILEINFOW afiw; 310 HRESULT hres; 311 312 TRACE("(%p,%p,%d)\n", pfile, afi, size); 313 314 if (pfile == NULL) 315 return AVIERR_BADHANDLE; 316 if ((DWORD)size < sizeof(AVIFILEINFOA)) 317 return AVIERR_BADSIZE; 318 319 hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw)); 320 321 memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType)); 322 WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType, 323 sizeof(afi->szFileType), NULL, NULL); 324 afi->szFileType[sizeof(afi->szFileType) - 1] = 0; 325 326 return hres; 327 } 328 329 /*********************************************************************** 330 * AVIFileInfoW (AVIFIL32.@) 331 */ 332 HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size) 333 { 334 TRACE("(%p,%p,%d)\n", pfile, afiw, size); 335 336 if (pfile == NULL) 337 return AVIERR_BADHANDLE; 338 339 return IAVIFile_Info(pfile, afiw, size); 340 } 341 342 /*********************************************************************** 343 * AVIFileGetStream (AVIFIL32.@) 344 */ 345 HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis, 346 DWORD fccType, LONG lParam) 347 { 348 TRACE("(%p,%p,'%4.4s',%d)\n", pfile, avis, (char*)&fccType, lParam); 349 350 if (pfile == NULL) 351 return AVIERR_BADHANDLE; 352 353 return IAVIFile_GetStream(pfile, avis, fccType, lParam); 354 } 355 356 /*********************************************************************** 357 * AVIFileCreateStream (AVIFIL32.@) 358 * AVIFileCreateStreamA (AVIFIL32.@) 359 */ 360 HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi, 361 LPAVISTREAMINFOA psi) 362 { 363 AVISTREAMINFOW psiw; 364 365 TRACE("(%p,%p,%p)\n", pfile, ppavi, psi); 366 367 if (pfile == NULL) 368 return AVIERR_BADHANDLE; 369 370 /* Only the szName at the end is different */ 371 memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName)); 372 MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName, 373 ARRAY_SIZE(psiw.szName)); 374 375 return IAVIFile_CreateStream(pfile, ppavi, &psiw); 376 } 377 378 /*********************************************************************** 379 * AVIFileCreateStreamW (AVIFIL32.@) 380 */ 381 HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis, 382 LPAVISTREAMINFOW asi) 383 { 384 TRACE("(%p,%p,%p)\n", pfile, avis, asi); 385 386 if (pfile == NULL) 387 return AVIERR_BADHANDLE; 388 389 return IAVIFile_CreateStream(pfile, avis, asi); 390 } 391 392 /*********************************************************************** 393 * AVIFileWriteData (AVIFIL32.@) 394 */ 395 HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size) 396 { 397 TRACE("(%p,'%4.4s',%p,%d)\n", pfile, (char*)&fcc, lp, size); 398 399 if (pfile == NULL) 400 return AVIERR_BADHANDLE; 401 402 return IAVIFile_WriteData(pfile, fcc, lp, size); 403 } 404 405 /*********************************************************************** 406 * AVIFileReadData (AVIFIL32.@) 407 */ 408 HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size) 409 { 410 TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size); 411 412 if (pfile == NULL) 413 return AVIERR_BADHANDLE; 414 415 return IAVIFile_ReadData(pfile, fcc, lp, size); 416 } 417 418 /*********************************************************************** 419 * AVIFileEndRecord (AVIFIL32.@) 420 */ 421 HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile) 422 { 423 TRACE("(%p)\n", pfile); 424 425 if (pfile == NULL) 426 return AVIERR_BADHANDLE; 427 428 return IAVIFile_EndRecord(pfile); 429 } 430 431 /*********************************************************************** 432 * AVIStreamAddRef (AVIFIL32.@) 433 */ 434 ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream) 435 { 436 TRACE("(%p)\n", pstream); 437 438 if (pstream == NULL) { 439 ERR(": bad handle passed!\n"); 440 return 0; 441 } 442 443 return IAVIStream_AddRef(pstream); 444 } 445 446 /*********************************************************************** 447 * AVIStreamRelease (AVIFIL32.@) 448 */ 449 ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream) 450 { 451 TRACE("(%p)\n", pstream); 452 453 if (pstream == NULL) { 454 ERR(": bad handle passed!\n"); 455 return 0; 456 } 457 458 return IAVIStream_Release(pstream); 459 } 460 461 /*********************************************************************** 462 * AVIStreamCreate (AVIFIL32.@) 463 */ 464 HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2, 465 LPCLSID pclsidHandler) 466 { 467 HRESULT hr; 468 469 TRACE("(%p,0x%08X,0x%08X,%s)\n", ppavi, lParam1, lParam2, 470 debugstr_guid(pclsidHandler)); 471 472 if (ppavi == NULL) 473 return AVIERR_BADPARAM; 474 475 *ppavi = NULL; 476 if (pclsidHandler == NULL) 477 return AVIERR_UNSUPPORTED; 478 479 hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi); 480 if (FAILED(hr) || *ppavi == NULL) 481 return hr; 482 483 hr = IAVIStream_Create(*ppavi, lParam1, lParam2); 484 if (FAILED(hr)) { 485 IAVIStream_Release(*ppavi); 486 *ppavi = NULL; 487 } 488 489 return hr; 490 } 491 492 /*********************************************************************** 493 * AVIStreamInfo (AVIFIL32.@) 494 * AVIStreamInfoA (AVIFIL32.@) 495 */ 496 HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi, 497 LONG size) 498 { 499 AVISTREAMINFOW asiw; 500 HRESULT hres; 501 502 TRACE("(%p,%p,%d)\n", pstream, asi, size); 503 504 if (pstream == NULL) 505 return AVIERR_BADHANDLE; 506 if ((DWORD)size < sizeof(AVISTREAMINFOA)) 507 return AVIERR_BADSIZE; 508 509 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw)); 510 511 memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName)); 512 WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName, 513 sizeof(asi->szName), NULL, NULL); 514 asi->szName[sizeof(asi->szName) - 1] = 0; 515 516 return hres; 517 } 518 519 /*********************************************************************** 520 * AVIStreamInfoW (AVIFIL32.@) 521 */ 522 HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi, 523 LONG size) 524 { 525 TRACE("(%p,%p,%d)\n", pstream, asi, size); 526 527 if (pstream == NULL) 528 return AVIERR_BADHANDLE; 529 530 return IAVIStream_Info(pstream, asi, size); 531 } 532 533 /*********************************************************************** 534 * AVIStreamFindSample (AVIFIL32.@) 535 */ 536 LONG WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, LONG flags) 537 { 538 TRACE("(%p,%d,0x%X)\n", pstream, pos, flags); 539 540 if (pstream == NULL) 541 return -1; 542 543 return IAVIStream_FindSample(pstream, pos, flags); 544 } 545 546 /*********************************************************************** 547 * AVIStreamReadFormat (AVIFIL32.@) 548 */ 549 HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos, 550 LPVOID format, LPLONG formatsize) 551 { 552 TRACE("(%p,%d,%p,%p)\n", pstream, pos, format, formatsize); 553 554 if (pstream == NULL) 555 return AVIERR_BADHANDLE; 556 557 return IAVIStream_ReadFormat(pstream, pos, format, formatsize); 558 } 559 560 /*********************************************************************** 561 * AVIStreamSetFormat (AVIFIL32.@) 562 */ 563 HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos, 564 LPVOID format, LONG formatsize) 565 { 566 TRACE("(%p,%d,%p,%d)\n", pstream, pos, format, formatsize); 567 568 if (pstream == NULL) 569 return AVIERR_BADHANDLE; 570 571 return IAVIStream_SetFormat(pstream, pos, format, formatsize); 572 } 573 574 /*********************************************************************** 575 * AVIStreamRead (AVIFIL32.@) 576 */ 577 HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples, 578 LPVOID buffer, LONG buffersize, 579 LPLONG bytesread, LPLONG samplesread) 580 { 581 TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", pstream, start, samples, buffer, 582 buffersize, bytesread, samplesread); 583 584 if (pstream == NULL) 585 return AVIERR_BADHANDLE; 586 587 return IAVIStream_Read(pstream, start, samples, buffer, buffersize, 588 bytesread, samplesread); 589 } 590 591 /*********************************************************************** 592 * AVIStreamWrite (AVIFIL32.@) 593 */ 594 HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples, 595 LPVOID buffer, LONG buffersize, DWORD flags, 596 LPLONG sampwritten, LPLONG byteswritten) 597 { 598 TRACE("(%p,%d,%d,%p,%d,0x%X,%p,%p)\n", pstream, start, samples, buffer, 599 buffersize, flags, sampwritten, byteswritten); 600 601 if (pstream == NULL) 602 return AVIERR_BADHANDLE; 603 604 return IAVIStream_Write(pstream, start, samples, buffer, buffersize, 605 flags, sampwritten, byteswritten); 606 } 607 608 /*********************************************************************** 609 * AVIStreamReadData (AVIFIL32.@) 610 */ 611 HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp, 612 LPLONG lpread) 613 { 614 TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread); 615 616 if (pstream == NULL) 617 return AVIERR_BADHANDLE; 618 619 return IAVIStream_ReadData(pstream, fcc, lp, lpread); 620 } 621 622 /*********************************************************************** 623 * AVIStreamWriteData (AVIFIL32.@) 624 */ 625 HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp, 626 LONG size) 627 { 628 TRACE("(%p,'%4.4s',%p,%d)\n", pstream, (char*)&fcc, lp, size); 629 630 if (pstream == NULL) 631 return AVIERR_BADHANDLE; 632 633 return IAVIStream_WriteData(pstream, fcc, lp, size); 634 } 635 636 /*********************************************************************** 637 * AVIStreamGetFrameOpen (AVIFIL32.@) 638 */ 639 PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream, 640 LPBITMAPINFOHEADER lpbiWanted) 641 { 642 PGETFRAME pg = NULL; 643 644 TRACE("(%p,%p)\n", pstream, lpbiWanted); 645 646 if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) || 647 pg == NULL) { 648 pg = AVIFILE_CreateGetFrame(pstream); 649 if (pg == NULL) 650 return NULL; 651 } 652 653 if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) { 654 IGetFrame_Release(pg); 655 return NULL; 656 } 657 658 return pg; 659 } 660 661 /*********************************************************************** 662 * AVIStreamGetFrame (AVIFIL32.@) 663 */ 664 LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos) 665 { 666 TRACE("(%p,%d)\n", pg, pos); 667 668 if (pg == NULL) 669 return NULL; 670 671 return IGetFrame_GetFrame(pg, pos); 672 } 673 674 /*********************************************************************** 675 * AVIStreamGetFrameClose (AVIFIL32.@) 676 */ 677 HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg) 678 { 679 TRACE("(%p)\n", pg); 680 681 if (pg != NULL) 682 return IGetFrame_Release(pg); 683 return 0; 684 } 685 686 /*********************************************************************** 687 * AVIMakeCompressedStream (AVIFIL32.@) 688 */ 689 HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed, 690 PAVISTREAM psSource, 691 LPAVICOMPRESSOPTIONS aco, 692 LPCLSID pclsidHandler) 693 { 694 AVISTREAMINFOW asiw; 695 CHAR szRegKey[25]; 696 CHAR szValue[100]; 697 CLSID clsidHandler; 698 HRESULT hr; 699 LONG size = sizeof(szValue); 700 701 TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco, 702 debugstr_guid(pclsidHandler)); 703 704 if (ppsCompressed == NULL) 705 return AVIERR_BADPARAM; 706 if (psSource == NULL) 707 return AVIERR_BADHANDLE; 708 709 *ppsCompressed = NULL; 710 711 /* if no handler given get default ones based on streamtype */ 712 if (pclsidHandler == NULL) { 713 hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw)); 714 if (FAILED(hr)) 715 return hr; 716 717 wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType); 718 if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS) 719 return AVIERR_UNSUPPORTED; 720 if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK) 721 return AVIERR_UNSUPPORTED; 722 } else 723 clsidHandler = *pclsidHandler; 724 725 hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed); 726 if (FAILED(hr) || *ppsCompressed == NULL) 727 return hr; 728 729 hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco); 730 if (FAILED(hr)) { 731 IAVIStream_Release(*ppsCompressed); 732 *ppsCompressed = NULL; 733 } 734 735 return hr; 736 } 737 738 /*********************************************************************** 739 * AVIMakeFileFromStreams (AVIFIL32.@) 740 */ 741 HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams, 742 PAVISTREAM *ppStreams) 743 { 744 TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams); 745 746 if (nStreams < 0 || ppfile == NULL || ppStreams == NULL) 747 return AVIERR_BADPARAM; 748 749 *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams); 750 if (*ppfile == NULL) 751 return AVIERR_MEMORY; 752 753 return AVIERR_OK; 754 } 755 756 /*********************************************************************** 757 * AVIStreamOpenFromFile (AVIFIL32.@) 758 * AVIStreamOpenFromFileA (AVIFIL32.@) 759 */ 760 HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile, 761 DWORD fccType, LONG lParam, 762 UINT mode, LPCLSID pclsidHandler) 763 { 764 PAVIFILE pfile = NULL; 765 HRESULT hr; 766 767 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_a(szFile), 768 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler)); 769 770 if (ppavi == NULL || szFile == NULL) 771 return AVIERR_BADPARAM; 772 773 *ppavi = NULL; 774 775 hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler); 776 if (FAILED(hr) || pfile == NULL) 777 return hr; 778 779 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam); 780 IAVIFile_Release(pfile); 781 782 return hr; 783 } 784 785 /*********************************************************************** 786 * AVIStreamOpenFromFileW (AVIFIL32.@) 787 */ 788 HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile, 789 DWORD fccType, LONG lParam, 790 UINT mode, LPCLSID pclsidHandler) 791 { 792 PAVIFILE pfile = NULL; 793 HRESULT hr; 794 795 TRACE("(%p,%s,'%4.4s',%d,0x%X,%s)\n", ppavi, debugstr_w(szFile), 796 (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler)); 797 798 if (ppavi == NULL || szFile == NULL) 799 return AVIERR_BADPARAM; 800 801 *ppavi = NULL; 802 803 hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler); 804 if (FAILED(hr) || pfile == NULL) 805 return hr; 806 807 hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam); 808 IAVIFile_Release(pfile); 809 810 return hr; 811 } 812 813 /*********************************************************************** 814 * AVIStreamBeginStreaming (AVIFIL32.@) 815 */ 816 LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate) 817 { 818 IAVIStreaming* pstream = NULL; 819 HRESULT hr; 820 821 TRACE("(%p,%d,%d,%d)\n", pavi, lStart, lEnd, lRate); 822 823 if (pavi == NULL) 824 return AVIERR_BADHANDLE; 825 826 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream); 827 if (SUCCEEDED(hr) && pstream != NULL) { 828 hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate); 829 IAVIStreaming_Release(pstream); 830 } else 831 hr = AVIERR_OK; 832 833 return hr; 834 } 835 836 /*********************************************************************** 837 * AVIStreamEndStreaming (AVIFIL32.@) 838 */ 839 LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi) 840 { 841 IAVIStreaming* pstream = NULL; 842 HRESULT hr; 843 844 TRACE("(%p)\n", pavi); 845 846 hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream); 847 if (SUCCEEDED(hr) && pstream != NULL) { 848 IAVIStreaming_End(pstream); 849 IAVIStreaming_Release(pstream); 850 } 851 852 return AVIERR_OK; 853 } 854 855 /*********************************************************************** 856 * AVIStreamStart (AVIFIL32.@) 857 */ 858 LONG WINAPI AVIStreamStart(PAVISTREAM pstream) 859 { 860 AVISTREAMINFOW asiw; 861 862 TRACE("(%p)\n", pstream); 863 864 if (pstream == NULL) 865 return 0; 866 867 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) 868 return 0; 869 870 return asiw.dwStart; 871 } 872 873 /*********************************************************************** 874 * AVIStreamLength (AVIFIL32.@) 875 */ 876 LONG WINAPI AVIStreamLength(PAVISTREAM pstream) 877 { 878 AVISTREAMINFOW asiw; 879 880 TRACE("(%p)\n", pstream); 881 882 if (pstream == NULL) 883 return 0; 884 885 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) 886 return 0; 887 888 return asiw.dwLength; 889 } 890 891 /*********************************************************************** 892 * AVIStreamSampleToTime (AVIFIL32.@) 893 */ 894 LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample) 895 { 896 AVISTREAMINFOW asiw; 897 LONG time; 898 899 TRACE("(%p,%d)\n", pstream, lSample); 900 901 if (pstream == NULL) 902 return -1; 903 904 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) 905 return -1; 906 if (asiw.dwRate == 0) 907 return -1; 908 909 /* limit to stream bounds */ 910 if (lSample < asiw.dwStart) 911 lSample = asiw.dwStart; 912 if (lSample > asiw.dwStart + asiw.dwLength) 913 lSample = asiw.dwStart + asiw.dwLength; 914 915 if (asiw.dwRate / asiw.dwScale < 1000) 916 time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate); 917 else 918 time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate); 919 920 TRACE(" -> %d\n",time); 921 return time; 922 } 923 924 /*********************************************************************** 925 * AVIStreamTimeToSample (AVIFIL32.@) 926 */ 927 LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime) 928 { 929 AVISTREAMINFOW asiw; 930 ULONG sample; 931 932 TRACE("(%p,%d)\n", pstream, lTime); 933 934 if (pstream == NULL || lTime < 0) 935 return -1; 936 937 if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw)))) 938 return -1; 939 if (asiw.dwScale == 0) 940 return -1; 941 942 if (asiw.dwRate / asiw.dwScale < 1000) 943 sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000))); 944 else 945 sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000)); 946 947 /* limit to stream bounds */ 948 if (sample < asiw.dwStart) 949 sample = asiw.dwStart; 950 if (sample > asiw.dwStart + asiw.dwLength) 951 sample = asiw.dwStart + asiw.dwLength; 952 953 TRACE(" -> %d\n", sample); 954 return sample; 955 } 956 957 /*********************************************************************** 958 * AVIBuildFilter (AVIFIL32.@) 959 * AVIBuildFilterA (AVIFIL32.@) 960 */ 961 HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving) 962 { 963 LPWSTR wszFilter; 964 HRESULT hr; 965 966 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving); 967 968 /* check parameters */ 969 if (szFilter == NULL) 970 return AVIERR_BADPARAM; 971 if (cbFilter < 2) 972 return AVIERR_BADSIZE; 973 974 szFilter[0] = 0; 975 szFilter[1] = 0; 976 977 wszFilter = HeapAlloc(GetProcessHeap(), 0, cbFilter * sizeof(WCHAR)); 978 if (wszFilter == NULL) 979 return AVIERR_MEMORY; 980 981 hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving); 982 if (SUCCEEDED(hr)) { 983 WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter, 984 szFilter, cbFilter, NULL, NULL); 985 } 986 987 HeapFree(GetProcessHeap(), 0, wszFilter); 988 989 return hr; 990 } 991 992 /*********************************************************************** 993 * AVIBuildFilterW (AVIFIL32.@) 994 */ 995 HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving) 996 { 997 static const WCHAR all_files[] = { '*','.','*',0,0 }; 998 static const WCHAR szClsid[] = {'C','L','S','I','D',0}; 999 static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0}; 1000 static const WCHAR szAVIFileExtensions[] = 1001 {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0}; 1002 1003 AVIFilter *lp; 1004 WCHAR szAllFiles[40]; 1005 WCHAR szFileExt[10]; 1006 WCHAR szValue[128]; 1007 HKEY hKey; 1008 DWORD n, i; 1009 LONG size; 1010 DWORD count = 0; 1011 1012 TRACE("(%p,%d,%d)\n", szFilter, cbFilter, fSaving); 1013 1014 /* check parameters */ 1015 if (szFilter == NULL) 1016 return AVIERR_BADPARAM; 1017 if (cbFilter < 2) 1018 return AVIERR_BADSIZE; 1019 1020 lp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_FILTERS * sizeof(AVIFilter)); 1021 if (lp == NULL) 1022 return AVIERR_MEMORY; 1023 1024 /* 1025 * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect 1026 * extensions and CLSIDs 1027 * 2. iterate over collected CLSIDs and copy its description and its 1028 * extensions to szFilter if it fits 1029 * 1030 * First filter is named "All multimedia files" and its filter is a 1031 * collection of all possible extensions except "*.*". 1032 */ 1033 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != ERROR_SUCCESS) { 1034 HeapFree(GetProcessHeap(), 0, lp); 1035 return AVIERR_ERROR; 1036 } 1037 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, ARRAY_SIZE(szFileExt)) == ERROR_SUCCESS;n++) { 1038 WCHAR clsidW[40]; 1039 1040 /* get CLSID to extension */ 1041 size = sizeof(clsidW); 1042 if (RegQueryValueW(hKey, szFileExt, clsidW, &size) != ERROR_SUCCESS) 1043 break; 1044 1045 /* search if the CLSID is already known */ 1046 for (i = 1; i <= count; i++) { 1047 if (lstrcmpW(lp[i].szClsid, clsidW) == 0) 1048 break; /* a new one */ 1049 } 1050 1051 if (i == count + 1) { 1052 /* it's a new CLSID */ 1053 1054 /* FIXME: How do we get info's about read/write capabilities? */ 1055 1056 if (count >= MAX_FILTERS) { 1057 /* try to inform user of our full fixed size table */ 1058 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS); 1059 break; 1060 } 1061 1062 lstrcpyW(lp[i].szClsid, clsidW); 1063 1064 count++; 1065 } 1066 1067 /* append extension to the filter */ 1068 wsprintfW(szValue, szExtensionFmt, szFileExt); 1069 if (lp[i].szExtensions[0] == 0) 1070 lstrcatW(lp[i].szExtensions, szValue + 1); 1071 else 1072 lstrcatW(lp[i].szExtensions, szValue); 1073 1074 /* also append to the "all multimedia"-filter */ 1075 if (lp[0].szExtensions[0] == 0) 1076 lstrcatW(lp[0].szExtensions, szValue + 1); 1077 else 1078 lstrcatW(lp[0].szExtensions, szValue); 1079 } 1080 RegCloseKey(hKey); 1081 1082 /* 2. get descriptions for the CLSIDs and fill out szFilter */ 1083 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != ERROR_SUCCESS) { 1084 HeapFree(GetProcessHeap(), 0, lp); 1085 return AVIERR_ERROR; 1086 } 1087 for (n = 0; n <= count; n++) { 1088 /* first the description */ 1089 if (n != 0) { 1090 size = sizeof(szValue); 1091 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == ERROR_SUCCESS) { 1092 size = lstrlenW(szValue); 1093 lstrcpynW(szFilter, szValue, cbFilter); 1094 } 1095 } else 1096 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter); 1097 1098 /* check for enough space */ 1099 size++; 1100 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) { 1101 szFilter[0] = 0; 1102 szFilter[1] = 0; 1103 HeapFree(GetProcessHeap(), 0, lp); 1104 RegCloseKey(hKey); 1105 return AVIERR_BUFFERTOOSMALL; 1106 } 1107 cbFilter -= size; 1108 szFilter += size; 1109 1110 /* and then the filter */ 1111 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter); 1112 size = lstrlenW(lp[n].szExtensions) + 1; 1113 cbFilter -= size; 1114 szFilter += size; 1115 } 1116 1117 RegCloseKey(hKey); 1118 HeapFree(GetProcessHeap(), 0, lp); 1119 1120 /* add "All files" "*.*" filter if enough space left */ 1121 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES, szAllFiles, 1122 ARRAY_SIZE(szAllFiles) - ARRAY_SIZE(all_files)) + 1; 1123 memcpy( szAllFiles + size, all_files, sizeof(all_files) ); 1124 size += ARRAY_SIZE(all_files); 1125 1126 if (cbFilter > size) { 1127 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0])); 1128 return AVIERR_OK; 1129 } else { 1130 szFilter[0] = 0; 1131 return AVIERR_BUFFERTOOSMALL; 1132 } 1133 } 1134 1135 static BOOL AVISaveOptionsFmtChoose(HWND hWnd) 1136 { 1137 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent]; 1138 AVISTREAMINFOW sInfo; 1139 1140 TRACE("(%p)\n", hWnd); 1141 1142 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) { 1143 ERR(": bad state!\n"); 1144 return FALSE; 1145 } 1146 1147 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], 1148 &sInfo, sizeof(sInfo)))) { 1149 ERR(": AVIStreamInfoW failed!\n"); 1150 return FALSE; 1151 } 1152 1153 if (sInfo.fccType == streamtypeVIDEO) { 1154 COMPVARS cv; 1155 BOOL ret; 1156 1157 memset(&cv, 0, sizeof(cv)); 1158 1159 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) { 1160 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS)); 1161 pOptions->fccType = streamtypeVIDEO; 1162 pOptions->fccHandler = comptypeDIB; 1163 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT; 1164 } 1165 1166 cv.cbSize = sizeof(cv); 1167 cv.dwFlags = ICMF_COMPVARS_VALID; 1168 /*cv.fccType = pOptions->fccType; */ 1169 cv.fccHandler = pOptions->fccHandler; 1170 cv.lQ = pOptions->dwQuality; 1171 cv.lpState = pOptions->lpParms; 1172 cv.cbState = pOptions->cbParms; 1173 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES) 1174 cv.lKey = pOptions->dwKeyFrameEvery; 1175 else 1176 cv.lKey = 0; 1177 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE) 1178 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */ 1179 else 1180 cv.lDataRate = 0; 1181 1182 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL, 1183 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL); 1184 1185 if (ret) { 1186 pOptions->fccHandler = cv.fccHandler; 1187 pOptions->lpParms = cv.lpState; 1188 pOptions->cbParms = cv.cbState; 1189 pOptions->dwQuality = cv.lQ; 1190 if (cv.lKey != 0) { 1191 pOptions->dwKeyFrameEvery = cv.lKey; 1192 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES; 1193 } else 1194 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES; 1195 if (cv.lDataRate != 0) { 1196 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */ 1197 pOptions->dwFlags |= AVICOMPRESSF_DATARATE; 1198 } else 1199 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE; 1200 pOptions->dwFlags |= AVICOMPRESSF_VALID; 1201 } 1202 ICCompressorFree(&cv); 1203 1204 return ret; 1205 } else if (sInfo.fccType == streamtypeAUDIO) { 1206 ACMFORMATCHOOSEW afmtc; 1207 MMRESULT ret; 1208 LONG size; 1209 1210 /* FIXME: check ACM version -- Which version is needed? */ 1211 1212 memset(&afmtc, 0, sizeof(afmtc)); 1213 afmtc.cbStruct = sizeof(afmtc); 1214 afmtc.fdwStyle = 0; 1215 afmtc.hwndOwner = hWnd; 1216 1217 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size); 1218 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) { 1219 pOptions->lpFormat = HeapAlloc(GetProcessHeap(), 0, size); 1220 if (!pOptions->lpFormat) return FALSE; 1221 pOptions->cbFormat = size; 1222 } else if (pOptions->cbFormat < (DWORD)size) { 1223 void *new_buffer = HeapReAlloc(GetProcessHeap(), 0, pOptions->lpFormat, size); 1224 if (!new_buffer) return FALSE; 1225 pOptions->lpFormat = new_buffer; 1226 pOptions->cbFormat = size; 1227 } 1228 afmtc.pwfx = pOptions->lpFormat; 1229 afmtc.cbwfx = pOptions->cbFormat; 1230 1231 size = 0; 1232 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent], 1233 sInfo.dwStart, &size); 1234 if (size < (LONG)sizeof(PCMWAVEFORMAT)) 1235 size = sizeof(PCMWAVEFORMAT); 1236 afmtc.pwfxEnum = HeapAlloc(GetProcessHeap(), 0, size); 1237 if (afmtc.pwfxEnum != NULL) { 1238 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent], 1239 sInfo.dwStart, afmtc.pwfxEnum, &size); 1240 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT; 1241 } 1242 1243 ret = acmFormatChooseW(&afmtc); 1244 if (ret == S_OK) 1245 pOptions->dwFlags |= AVICOMPRESSF_VALID; 1246 1247 HeapFree(GetProcessHeap(), 0, afmtc.pwfxEnum); 1248 return ret == S_OK; 1249 } else { 1250 ERR(": unknown streamtype 0x%08X\n", sInfo.fccType); 1251 return FALSE; 1252 } 1253 } 1254 1255 static void AVISaveOptionsUpdate(HWND hWnd) 1256 { 1257 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0}; 1258 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0}; 1259 1260 WCHAR szFormat[128]; 1261 AVISTREAMINFOW sInfo; 1262 LPVOID lpFormat; 1263 LONG size; 1264 1265 TRACE("(%p)\n", hWnd); 1266 1267 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0); 1268 if (SaveOpts.nCurrent < 0) 1269 return; 1270 1271 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo)))) 1272 return; 1273 1274 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size); 1275 if (size > 0) { 1276 szFormat[0] = 0; 1277 1278 /* read format to build format description string */ 1279 lpFormat = HeapAlloc(GetProcessHeap(), 0, size); 1280 if (lpFormat != NULL) { 1281 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) { 1282 if (sInfo.fccType == streamtypeVIDEO) { 1283 LPBITMAPINFOHEADER lpbi = lpFormat; 1284 ICINFO icinfo; 1285 1286 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth, 1287 lpbi->biHeight, lpbi->biBitCount); 1288 1289 if (lpbi->biCompression != BI_RGB) { 1290 HIC hic; 1291 1292 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat, 1293 NULL, ICMODE_DECOMPRESS); 1294 if (hic != NULL) { 1295 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK) 1296 lstrcatW(szFormat, icinfo.szDescription); 1297 ICClose(hic); 1298 } 1299 } else { 1300 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED, 1301 icinfo.szDescription, 1302 ARRAY_SIZE(icinfo.szDescription)); 1303 lstrcatW(szFormat, icinfo.szDescription); 1304 } 1305 } else if (sInfo.fccType == streamtypeAUDIO) { 1306 ACMFORMATTAGDETAILSW aftd; 1307 ACMFORMATDETAILSW afd; 1308 1309 memset(&aftd, 0, sizeof(aftd)); 1310 memset(&afd, 0, sizeof(afd)); 1311 1312 aftd.cbStruct = sizeof(aftd); 1313 aftd.dwFormatTag = afd.dwFormatTag = 1314 ((PWAVEFORMATEX)lpFormat)->wFormatTag; 1315 aftd.cbFormatSize = afd.cbwfx = size; 1316 1317 afd.cbStruct = sizeof(afd); 1318 afd.pwfx = lpFormat; 1319 1320 if (acmFormatTagDetailsW(NULL, &aftd, 1321 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) { 1322 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK) 1323 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag); 1324 } 1325 } 1326 } 1327 HeapFree(GetProcessHeap(), 0, lpFormat); 1328 } 1329 1330 /* set text for format description */ 1331 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat); 1332 1333 /* Disable option button for unsupported streamtypes */ 1334 if (sInfo.fccType == streamtypeVIDEO || 1335 sInfo.fccType == streamtypeAUDIO) 1336 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE); 1337 else 1338 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE); 1339 } 1340 1341 } 1342 1343 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg, 1344 WPARAM wParam, LPARAM lParam) 1345 { 1346 DWORD dwInterleave; 1347 BOOL bIsInterleaved; 1348 INT n; 1349 1350 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/ 1351 1352 switch (uMsg) { 1353 case WM_INITDIALOG: 1354 SaveOpts.nCurrent = 0; 1355 if (SaveOpts.nStreams == 1) { 1356 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd)); 1357 return TRUE; 1358 } 1359 1360 /* add streams */ 1361 for (n = 0; n < SaveOpts.nStreams; n++) { 1362 AVISTREAMINFOW sInfo; 1363 1364 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo)); 1365 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING, 1366 0L, (LPARAM)sInfo.szName); 1367 } 1368 1369 /* select first stream */ 1370 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0); 1371 SendMessageW(hWnd, WM_COMMAND, MAKELONG(IDC_STREAM, CBN_SELCHANGE), (LPARAM)hWnd); 1372 1373 /* initialize interleave */ 1374 if (SaveOpts.ppOptions[0] != NULL && 1375 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) { 1376 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE); 1377 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery; 1378 } else { 1379 bIsInterleaved = TRUE; 1380 dwInterleave = 0; 1381 } 1382 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved); 1383 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE); 1384 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved); 1385 break; 1386 case WM_COMMAND: 1387 switch (LOWORD(wParam)) { 1388 case IDOK: 1389 /* get data from controls and save them */ 1390 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0); 1391 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE); 1392 for (n = 0; n < SaveOpts.nStreams; n++) { 1393 if (SaveOpts.ppOptions[n] != NULL) { 1394 if (bIsInterleaved) { 1395 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE; 1396 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave; 1397 } else 1398 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE; 1399 } 1400 } 1401 /* fall through */ 1402 case IDCANCEL: 1403 EndDialog(hWnd, LOWORD(wParam) == IDOK); 1404 break; 1405 case IDC_INTERLEAVE: 1406 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), 1407 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE)); 1408 break; 1409 case IDC_STREAM: 1410 if (HIWORD(wParam) == CBN_SELCHANGE) { 1411 /* update control elements */ 1412 AVISaveOptionsUpdate(hWnd); 1413 } 1414 break; 1415 case IDC_OPTIONS: 1416 AVISaveOptionsFmtChoose(hWnd); 1417 break; 1418 }; 1419 return TRUE; 1420 }; 1421 1422 return FALSE; 1423 } 1424 1425 /*********************************************************************** 1426 * AVISaveOptions (AVIFIL32.@) 1427 */ 1428 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams, 1429 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions) 1430 { 1431 LPAVICOMPRESSOPTIONS pSavedOptions = NULL; 1432 INT ret, n; 1433 1434 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams, 1435 ppavi, ppOptions); 1436 1437 /* check parameters */ 1438 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL) 1439 return AVIERR_BADPARAM; 1440 1441 /* save options in case the user presses cancel */ 1442 if (nStreams > 1) { 1443 pSavedOptions = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(AVICOMPRESSOPTIONS)); 1444 if (pSavedOptions == NULL) 1445 return FALSE; 1446 1447 for (n = 0; n < nStreams; n++) { 1448 if (ppOptions[n] != NULL) 1449 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS)); 1450 } 1451 } 1452 1453 SaveOpts.uFlags = uFlags; 1454 SaveOpts.nStreams = nStreams; 1455 SaveOpts.ppavis = ppavi; 1456 SaveOpts.ppOptions = ppOptions; 1457 1458 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS), 1459 hWnd, AVISaveOptionsDlgProc); 1460 1461 if (ret == -1) 1462 ret = FALSE; 1463 1464 /* restore options when user pressed cancel */ 1465 if (pSavedOptions != NULL) { 1466 if (ret == FALSE) { 1467 for (n = 0; n < nStreams; n++) { 1468 if (ppOptions[n] != NULL) 1469 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS)); 1470 } 1471 } 1472 HeapFree(GetProcessHeap(), 0, pSavedOptions); 1473 } 1474 1475 return ret; 1476 } 1477 1478 /*********************************************************************** 1479 * AVISaveOptionsFree (AVIFIL32.@) 1480 */ 1481 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions) 1482 { 1483 TRACE("(%d,%p)\n", nStreams, ppOptions); 1484 1485 if (nStreams < 0 || ppOptions == NULL) 1486 return AVIERR_BADPARAM; 1487 1488 for (nStreams--; nStreams >= 0; nStreams--) { 1489 if (ppOptions[nStreams] != NULL) { 1490 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID; 1491 1492 if (ppOptions[nStreams]->lpParms != NULL) { 1493 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpParms); 1494 ppOptions[nStreams]->lpParms = NULL; 1495 ppOptions[nStreams]->cbParms = 0; 1496 } 1497 if (ppOptions[nStreams]->lpFormat != NULL) { 1498 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpFormat); 1499 ppOptions[nStreams]->lpFormat = NULL; 1500 ppOptions[nStreams]->cbFormat = 0; 1501 } 1502 } 1503 } 1504 1505 return AVIERR_OK; 1506 } 1507 1508 /*********************************************************************** 1509 * AVISaveVA (AVIFIL32.@) 1510 */ 1511 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler, 1512 AVISAVECALLBACK lpfnCallback, int nStream, 1513 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions) 1514 { 1515 LPWSTR wszFile = NULL; 1516 HRESULT hr; 1517 int len; 1518 1519 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler, 1520 lpfnCallback, nStream, ppavi, plpOptions); 1521 1522 if (szFile == NULL || ppavi == NULL || plpOptions == NULL) 1523 return AVIERR_BADPARAM; 1524 1525 /* convert ASCII string to Unicode and call Unicode function */ 1526 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0); 1527 if (len <= 0) 1528 return AVIERR_BADPARAM; 1529 1530 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1531 if (wszFile == NULL) 1532 return AVIERR_MEMORY; 1533 1534 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len); 1535 1536 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback, 1537 nStream, ppavi, plpOptions); 1538 1539 HeapFree(GetProcessHeap(), 0, wszFile); 1540 1541 return hr; 1542 } 1543 1544 /*********************************************************************** 1545 * AVIFILE_AVISaveDefaultCallback (internal) 1546 */ 1547 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress) 1548 { 1549 TRACE("(%d)\n", progress); 1550 1551 return FALSE; 1552 } 1553 1554 /*********************************************************************** 1555 * AVISaveVW (AVIFIL32.@) 1556 */ 1557 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler, 1558 AVISAVECALLBACK lpfnCallback, int nStreams, 1559 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions) 1560 { 1561 LONG lStart[MAX_AVISTREAMS]; 1562 PAVISTREAM pOutStreams[MAX_AVISTREAMS]; 1563 PAVISTREAM pInStreams[MAX_AVISTREAMS]; 1564 AVIFILEINFOW fInfo; 1565 AVISTREAMINFOW sInfo; 1566 1567 PAVIFILE pfile = NULL; /* the output AVI file */ 1568 LONG lFirstVideo = -1; 1569 int curStream; 1570 1571 /* for interleaving ... */ 1572 DWORD dwInterleave = 0; /* interleave rate */ 1573 DWORD dwFileInitialFrames; 1574 LONG lFileLength; 1575 LONG lSampleInc; 1576 1577 /* for reading/writing the data ... */ 1578 LPVOID lpBuffer = NULL; 1579 LONG cbBuffer; /* real size of lpBuffer */ 1580 LONG lBufferSize; /* needed bytes for format(s), etc. */ 1581 LONG lReadBytes; 1582 LONG lReadSamples; 1583 HRESULT hres; 1584 1585 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler, 1586 lpfnCallback, nStreams, ppavi, plpOptions); 1587 1588 if (szFile == NULL || ppavi == NULL || plpOptions == NULL) 1589 return AVIERR_BADPARAM; 1590 if (nStreams >= MAX_AVISTREAMS) { 1591 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS); 1592 return AVIERR_INTERNAL; 1593 } 1594 1595 if (lpfnCallback == NULL) 1596 lpfnCallback = AVIFILE_AVISaveDefaultCallback; 1597 1598 /* clear local variable(s) */ 1599 for (curStream = 0; curStream < nStreams; curStream++) { 1600 pInStreams[curStream] = NULL; 1601 pOutStreams[curStream] = NULL; 1602 } 1603 1604 /* open output AVI file (create it if it doesn't exist) */ 1605 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE, 1606 pclsidHandler); 1607 if (FAILED(hres)) 1608 return hres; 1609 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */ 1610 1611 /* initialize our data structures part 1 */ 1612 for (curStream = 0; curStream < nStreams; curStream++) { 1613 PAVISTREAM pCurStream = ppavi[curStream]; 1614 1615 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo)); 1616 if (FAILED(hres)) 1617 goto error; 1618 1619 /* search first video stream and check for interleaving */ 1620 if (sInfo.fccType == streamtypeVIDEO) { 1621 /* remember first video stream -- needed for interleaving */ 1622 if (lFirstVideo < 0) 1623 lFirstVideo = curStream; 1624 } else if (!dwInterleave) { 1625 /* check if any non-video stream wants to be interleaved */ 1626 WARN("options.flags=0x%X options.dwInterleave=%u\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery); 1627 if (plpOptions[curStream] != NULL && 1628 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE) 1629 dwInterleave = plpOptions[curStream]->dwInterleaveEvery; 1630 } 1631 1632 /* create de-/compressed stream interface if needed */ 1633 pInStreams[curStream] = NULL; 1634 if (plpOptions[curStream] != NULL) { 1635 if (plpOptions[curStream]->fccHandler || 1636 plpOptions[curStream]->lpFormat != NULL) { 1637 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery; 1638 1639 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES) 1640 plpOptions[curStream]->dwKeyFrameEvery = 1; 1641 1642 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream, 1643 plpOptions[curStream], NULL); 1644 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave; 1645 if (FAILED(hres) || pInStreams[curStream] == NULL) { 1646 pInStreams[curStream] = NULL; 1647 goto error; 1648 } 1649 1650 /* test stream interface and update stream-info */ 1651 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); 1652 if (FAILED(hres)) 1653 goto error; 1654 } 1655 } 1656 1657 /* now handle streams which will only be copied */ 1658 if (pInStreams[curStream] == NULL) { 1659 pCurStream = pInStreams[curStream] = ppavi[curStream]; 1660 AVIStreamAddRef(pCurStream); 1661 } else 1662 pCurStream = pInStreams[curStream]; 1663 1664 lStart[curStream] = sInfo.dwStart; 1665 } /* for all streams */ 1666 1667 /* check that first video stream is the first stream */ 1668 if (lFirstVideo > 0) { 1669 PAVISTREAM pTmp = pInStreams[lFirstVideo]; 1670 LONG lTmp = lStart[lFirstVideo]; 1671 1672 pInStreams[lFirstVideo] = pInStreams[0]; 1673 pInStreams[0] = pTmp; 1674 lStart[lFirstVideo] = lStart[0]; 1675 lStart[0] = lTmp; 1676 lFirstVideo = 0; 1677 } 1678 1679 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/ 1680 cbBuffer = 0x00010000; 1681 lpBuffer = HeapAlloc(GetProcessHeap(), 0, cbBuffer); 1682 if (lpBuffer == NULL) { 1683 hres = AVIERR_MEMORY; 1684 goto error; 1685 } 1686 1687 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo)); 1688 lFileLength = sInfo.dwLength; 1689 dwFileInitialFrames = 0; 1690 if (lFirstVideo >= 0) { 1691 /* check for correct version of the format 1692 * -- need at least BITMAPINFOHEADER or newer 1693 */ 1694 lSampleInc = 1; 1695 lBufferSize = cbBuffer; 1696 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize); 1697 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER)) 1698 hres = AVIERR_INTERNAL; 1699 if (FAILED(hres)) 1700 goto error; 1701 } else /* use one second blocks for interleaving if no video present */ 1702 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000); 1703 1704 /* create output streams */ 1705 for (curStream = 0; curStream < nStreams; curStream++) { 1706 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); 1707 1708 sInfo.dwInitialFrames = 0; 1709 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) { 1710 /* 750 ms initial frames for non-video streams */ 1711 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750); 1712 } 1713 1714 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo); 1715 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) { 1716 /* copy initial format for this stream */ 1717 lBufferSize = cbBuffer; 1718 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, 1719 lpBuffer, &lBufferSize); 1720 if (FAILED(hres)) 1721 goto error; 1722 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize); 1723 if (FAILED(hres)) 1724 goto error; 1725 1726 /* try to copy stream handler data */ 1727 lBufferSize = cbBuffer; 1728 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA, 1729 lpBuffer, &lBufferSize); 1730 if (SUCCEEDED(hres) && lBufferSize > 0) { 1731 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA, 1732 lpBuffer, lBufferSize); 1733 if (FAILED(hres)) 1734 goto error; 1735 } 1736 1737 if (dwFileInitialFrames < sInfo.dwInitialFrames) 1738 dwFileInitialFrames = sInfo.dwInitialFrames; 1739 lReadBytes = 1740 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream], 1741 sInfo.dwLength); 1742 if (lFileLength < lReadBytes) 1743 lFileLength = lReadBytes; 1744 } else { 1745 /* creation of de-/compression stream interface failed */ 1746 WARN("creation of (de-)compression stream failed for stream %d\n",curStream); 1747 AVIStreamRelease(pInStreams[curStream]); 1748 if (curStream + 1 >= nStreams) { 1749 /* move the others one up */ 1750 PAVISTREAM *ppas = &pInStreams[curStream]; 1751 int n = nStreams - (curStream + 1); 1752 1753 do { 1754 *ppas = pInStreams[curStream + 1]; 1755 } while (--n); 1756 } 1757 nStreams--; 1758 curStream--; 1759 } 1760 } /* create output streams for all input streams */ 1761 1762 /* have we still something to write, or lost everything? */ 1763 if (nStreams <= 0) 1764 goto error; 1765 1766 if (dwInterleave) { 1767 LONG lCurFrame = -dwFileInitialFrames; 1768 1769 /* interleaved file */ 1770 if (dwInterleave == 1) 1771 AVIFileEndRecord(pfile); 1772 1773 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) { 1774 for (curStream = 0; curStream < nStreams; curStream++) { 1775 LONG lLastSample; 1776 1777 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo)); 1778 if (FAILED(hres)) 1779 goto error; 1780 1781 /* initial frames phase at the end for this stream? */ 1782 if (-(LONG)sInfo.dwInitialFrames > lCurFrame) 1783 continue; 1784 1785 if ((lFileLength - lSampleInc) <= lCurFrame) { 1786 lLastSample = AVIStreamLength(pInStreams[curStream]); 1787 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]); 1788 } else { 1789 if (curStream != 0) { 1790 lFirstVideo = 1791 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0], 1792 (sInfo.fccType == streamtypeVIDEO ? 1793 (LONG)dwInterleave : lSampleInc) + 1794 sInfo.dwInitialFrames + lCurFrame); 1795 } else 1796 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame); 1797 1798 lLastSample = AVIStreamEnd(pInStreams[curStream]); 1799 if (lLastSample <= lFirstVideo) 1800 lFirstVideo = lLastSample; 1801 } 1802 1803 /* copy needed samples now */ 1804 WARN("copy from stream %d samples %d to %d...\n",curStream, 1805 lStart[curStream],lFirstVideo); 1806 while (lFirstVideo > lStart[curStream]) { 1807 DWORD flags = 0; 1808 1809 /* copy format in case it can change */ 1810 lBufferSize = cbBuffer; 1811 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream], 1812 lpBuffer, &lBufferSize); 1813 if (FAILED(hres)) 1814 goto error; 1815 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream], 1816 lpBuffer, lBufferSize); 1817 1818 /* try to read data until we got it, or error */ 1819 do { 1820 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream], 1821 lFirstVideo - lStart[curStream], lpBuffer, 1822 cbBuffer, &lReadBytes, &lReadSamples); 1823 } while ((hres == AVIERR_BUFFERTOOSMALL) && 1824 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); 1825 if (lpBuffer == NULL) 1826 hres = AVIERR_MEMORY; 1827 if (FAILED(hres)) 1828 goto error; 1829 1830 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart)) 1831 flags = AVIIF_KEYFRAME; 1832 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, 1833 lpBuffer, lReadBytes, flags, NULL, NULL); 1834 if (FAILED(hres)) 1835 goto error; 1836 1837 lStart[curStream] += lReadSamples; 1838 } 1839 lStart[curStream] = lFirstVideo; 1840 } /* stream by stream */ 1841 1842 /* need to close this block? */ 1843 if (dwInterleave == 1) { 1844 hres = AVIFileEndRecord(pfile); 1845 if (FAILED(hres)) 1846 break; 1847 } 1848 1849 /* show progress */ 1850 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100, 1851 dwFileInitialFrames + lFileLength))) { 1852 hres = AVIERR_USERABORT; 1853 break; 1854 } 1855 } /* copy frame by frame */ 1856 } else { 1857 /* non-interleaved file */ 1858 1859 for (curStream = 0; curStream < nStreams; curStream++) { 1860 /* show progress */ 1861 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) { 1862 hres = AVIERR_USERABORT; 1863 goto error; 1864 } 1865 1866 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); 1867 1868 if (sInfo.dwSampleSize != 0) { 1869 /* sample-based data like audio */ 1870 while (sInfo.dwStart < sInfo.dwLength) { 1871 LONG lSamples = cbBuffer / sInfo.dwSampleSize; 1872 1873 /* copy format in case it can change */ 1874 lBufferSize = cbBuffer; 1875 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, 1876 lpBuffer, &lBufferSize); 1877 if (FAILED(hres)) 1878 goto error; 1879 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart, 1880 lpBuffer, lBufferSize); 1881 1882 /* limit to stream boundaries */ 1883 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart)) 1884 lSamples = sInfo.dwLength - sInfo.dwStart; 1885 1886 /* now try to read until we get it, or an error occurs */ 1887 do { 1888 lReadBytes = cbBuffer; 1889 lReadSamples = 0; 1890 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples, 1891 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples); 1892 } while ((hres == AVIERR_BUFFERTOOSMALL) && 1893 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); 1894 if (lpBuffer == NULL) 1895 hres = AVIERR_MEMORY; 1896 if (FAILED(hres)) 1897 goto error; 1898 if (lReadSamples != 0) { 1899 sInfo.dwStart += lReadSamples; 1900 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, 1901 lpBuffer, lReadBytes, 0, NULL , NULL); 1902 if (FAILED(hres)) 1903 goto error; 1904 1905 /* show progress */ 1906 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+ 1907 MulDiv(curStream, 100, nStreams))) { 1908 hres = AVIERR_USERABORT; 1909 goto error; 1910 } 1911 } else { 1912 if ((sInfo.dwLength - sInfo.dwStart) != 1) { 1913 hres = AVIERR_FILEREAD; 1914 goto error; 1915 } 1916 } 1917 } 1918 } else { 1919 /* block-based data like video */ 1920 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) { 1921 DWORD flags = 0; 1922 1923 /* copy format in case it can change */ 1924 lBufferSize = cbBuffer; 1925 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, 1926 lpBuffer, &lBufferSize); 1927 if (FAILED(hres)) 1928 goto error; 1929 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart, 1930 lpBuffer, lBufferSize); 1931 1932 /* try to read block and resize buffer if necessary */ 1933 do { 1934 lReadSamples = 0; 1935 lReadBytes = cbBuffer; 1936 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1, 1937 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples); 1938 } while ((hres == AVIERR_BUFFERTOOSMALL) && 1939 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); 1940 if (lpBuffer == NULL) 1941 hres = AVIERR_MEMORY; 1942 if (FAILED(hres)) 1943 goto error; 1944 if (lReadSamples != 1) { 1945 hres = AVIERR_FILEREAD; 1946 goto error; 1947 } 1948 1949 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart)) 1950 flags = AVIIF_KEYFRAME; 1951 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, 1952 lpBuffer, lReadBytes, flags, NULL, NULL); 1953 if (FAILED(hres)) 1954 goto error; 1955 1956 /* show progress */ 1957 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+ 1958 MulDiv(curStream, 100, nStreams))) { 1959 hres = AVIERR_USERABORT; 1960 goto error; 1961 } 1962 } /* copy all blocks */ 1963 } 1964 } /* copy data stream by stream */ 1965 } 1966 1967 error: 1968 HeapFree(GetProcessHeap(), 0, lpBuffer); 1969 if (pfile != NULL) { 1970 for (curStream = 0; curStream < nStreams; curStream++) { 1971 if (pOutStreams[curStream] != NULL) 1972 AVIStreamRelease(pOutStreams[curStream]); 1973 if (pInStreams[curStream] != NULL) 1974 AVIStreamRelease(pInStreams[curStream]); 1975 } 1976 1977 AVIFileRelease(pfile); 1978 } 1979 1980 return hres; 1981 } 1982 1983 /*********************************************************************** 1984 * EditStreamClone (AVIFIL32.@) 1985 */ 1986 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult) 1987 { 1988 PAVIEDITSTREAM pEdit = NULL; 1989 HRESULT hr; 1990 1991 TRACE("(%p,%p)\n", pStream, ppResult); 1992 1993 if (pStream == NULL) 1994 return AVIERR_BADHANDLE; 1995 if (ppResult == NULL) 1996 return AVIERR_BADPARAM; 1997 1998 *ppResult = NULL; 1999 2000 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2001 if (SUCCEEDED(hr) && pEdit != NULL) { 2002 hr = IAVIEditStream_Clone(pEdit, ppResult); 2003 2004 IAVIEditStream_Release(pEdit); 2005 } else 2006 hr = AVIERR_UNSUPPORTED; 2007 2008 return hr; 2009 } 2010 2011 /*********************************************************************** 2012 * EditStreamCopy (AVIFIL32.@) 2013 */ 2014 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart, 2015 LONG *plLength, PAVISTREAM *ppResult) 2016 { 2017 PAVIEDITSTREAM pEdit = NULL; 2018 HRESULT hr; 2019 2020 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult); 2021 2022 if (pStream == NULL) 2023 return AVIERR_BADHANDLE; 2024 if (plStart == NULL || plLength == NULL || ppResult == NULL) 2025 return AVIERR_BADPARAM; 2026 2027 *ppResult = NULL; 2028 2029 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2030 if (SUCCEEDED(hr) && pEdit != NULL) { 2031 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult); 2032 2033 IAVIEditStream_Release(pEdit); 2034 } else 2035 hr = AVIERR_UNSUPPORTED; 2036 2037 return hr; 2038 } 2039 2040 /*********************************************************************** 2041 * EditStreamCut (AVIFIL32.@) 2042 */ 2043 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart, 2044 LONG *plLength, PAVISTREAM *ppResult) 2045 { 2046 PAVIEDITSTREAM pEdit = NULL; 2047 HRESULT hr; 2048 2049 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult); 2050 2051 if (ppResult != NULL) 2052 *ppResult = NULL; 2053 if (pStream == NULL) 2054 return AVIERR_BADHANDLE; 2055 if (plStart == NULL || plLength == NULL) 2056 return AVIERR_BADPARAM; 2057 2058 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2059 if (SUCCEEDED(hr) && pEdit != NULL) { 2060 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult); 2061 2062 IAVIEditStream_Release(pEdit); 2063 } else 2064 hr = AVIERR_UNSUPPORTED; 2065 2066 return hr; 2067 } 2068 2069 /*********************************************************************** 2070 * EditStreamPaste (AVIFIL32.@) 2071 */ 2072 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength, 2073 PAVISTREAM pSource, LONG lStart, LONG lEnd) 2074 { 2075 PAVIEDITSTREAM pEdit = NULL; 2076 HRESULT hr; 2077 2078 TRACE("(%p,%p,%p,%p,%d,%d)\n", pDest, plStart, plLength, 2079 pSource, lStart, lEnd); 2080 2081 if (pDest == NULL || pSource == NULL) 2082 return AVIERR_BADHANDLE; 2083 if (plStart == NULL || plLength == NULL || lStart < 0) 2084 return AVIERR_BADPARAM; 2085 2086 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2087 if (SUCCEEDED(hr) && pEdit != NULL) { 2088 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd); 2089 2090 IAVIEditStream_Release(pEdit); 2091 } else 2092 hr = AVIERR_UNSUPPORTED; 2093 2094 return hr; 2095 } 2096 2097 /*********************************************************************** 2098 * EditStreamSetInfoA (AVIFIL32.@) 2099 */ 2100 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi, 2101 LONG size) 2102 { 2103 AVISTREAMINFOW asiw; 2104 2105 TRACE("(%p,%p,%d)\n", pstream, asi, size); 2106 2107 if (size >= 0 && size < sizeof(AVISTREAMINFOA)) 2108 return AVIERR_BADSIZE; 2109 2110 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName)); 2111 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1, asiw.szName, ARRAY_SIZE(asiw.szName)); 2112 2113 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw)); 2114 } 2115 2116 /*********************************************************************** 2117 * EditStreamSetInfoW (AVIFIL32.@) 2118 */ 2119 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi, 2120 LONG size) 2121 { 2122 PAVIEDITSTREAM pEdit = NULL; 2123 HRESULT hr; 2124 2125 TRACE("(%p,%p,%d)\n", pstream, asi, size); 2126 2127 if (size >= 0 && size < sizeof(AVISTREAMINFOA)) 2128 return AVIERR_BADSIZE; 2129 2130 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2131 if (SUCCEEDED(hr) && pEdit != NULL) { 2132 hr = IAVIEditStream_SetInfo(pEdit, asi, size); 2133 2134 IAVIEditStream_Release(pEdit); 2135 } else 2136 hr = AVIERR_UNSUPPORTED; 2137 2138 return hr; 2139 } 2140 2141 /*********************************************************************** 2142 * EditStreamSetNameA (AVIFIL32.@) 2143 */ 2144 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName) 2145 { 2146 AVISTREAMINFOA asia; 2147 HRESULT hres; 2148 2149 TRACE("(%p,%s)\n", pstream, debugstr_a(szName)); 2150 2151 if (pstream == NULL) 2152 return AVIERR_BADHANDLE; 2153 if (szName == NULL) 2154 return AVIERR_BADPARAM; 2155 2156 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia)); 2157 if (FAILED(hres)) 2158 return hres; 2159 2160 memset(asia.szName, 0, sizeof(asia.szName)); 2161 lstrcpynA(asia.szName, szName, ARRAY_SIZE(asia.szName)); 2162 2163 return EditStreamSetInfoA(pstream, &asia, sizeof(asia)); 2164 } 2165 2166 /*********************************************************************** 2167 * EditStreamSetNameW (AVIFIL32.@) 2168 */ 2169 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName) 2170 { 2171 AVISTREAMINFOW asiw; 2172 HRESULT hres; 2173 2174 TRACE("(%p,%s)\n", pstream, debugstr_w(szName)); 2175 2176 if (pstream == NULL) 2177 return AVIERR_BADHANDLE; 2178 if (szName == NULL) 2179 return AVIERR_BADPARAM; 2180 2181 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw)); 2182 if (FAILED(hres)) 2183 return hres; 2184 2185 memset(asiw.szName, 0, sizeof(asiw.szName)); 2186 lstrcpynW(asiw.szName, szName, ARRAY_SIZE(asiw.szName)); 2187 2188 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw)); 2189 } 2190 2191 /*********************************************************************** 2192 * AVIClearClipboard (AVIFIL32.@) 2193 */ 2194 HRESULT WINAPI AVIClearClipboard(void) 2195 { 2196 TRACE("()\n"); 2197 2198 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */ 2199 } 2200 2201 /*********************************************************************** 2202 * AVIGetFromClipboard (AVIFIL32.@) 2203 */ 2204 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile) 2205 { 2206 FIXME("(%p), stub!\n", ppfile); 2207 2208 *ppfile = NULL; 2209 2210 return AVIERR_UNSUPPORTED; 2211 } 2212 2213 /*********************************************************************** 2214 * AVIMakeStreamFromClipboard (AVIFIL32.@) 2215 */ 2216 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal, 2217 PAVISTREAM * ppstream) 2218 { 2219 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream); 2220 2221 if (ppstream == NULL) 2222 return AVIERR_BADHANDLE; 2223 2224 return AVIERR_UNSUPPORTED; 2225 } 2226 2227 /*********************************************************************** 2228 * AVIPutFileOnClipboard (AVIFIL32.@) 2229 */ 2230 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile) 2231 { 2232 FIXME("(%p), stub!\n", pfile); 2233 2234 if (pfile == NULL) 2235 return AVIERR_BADHANDLE; 2236 2237 return AVIERR_UNSUPPORTED; 2238 } 2239 2240 HRESULT WINAPIV AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback, 2241 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...) 2242 { 2243 __ms_va_list vl; 2244 int i; 2245 HRESULT ret; 2246 PAVISTREAM *streams; 2247 LPAVICOMPRESSOPTIONS *options; 2248 2249 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler, lpfnCallback, 2250 nStreams, pavi, lpOptions); 2251 2252 if (nStreams <= 0) return AVIERR_BADPARAM; 2253 2254 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams)); 2255 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options)); 2256 if (!streams || !options) 2257 { 2258 ret = AVIERR_MEMORY; 2259 goto error; 2260 } 2261 2262 streams[0] = pavi; 2263 options[0] = lpOptions; 2264 2265 __ms_va_start(vl, lpOptions); 2266 for (i = 1; i < nStreams; i++) 2267 { 2268 streams[i] = va_arg(vl, PAVISTREAM); 2269 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS); 2270 } 2271 __ms_va_end(vl); 2272 2273 for (i = 0; i < nStreams; i++) 2274 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]); 2275 2276 ret = AVISaveVA(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options); 2277 error: 2278 HeapFree(GetProcessHeap(), 0, streams); 2279 HeapFree(GetProcessHeap(), 0, options); 2280 return ret; 2281 } 2282 2283 HRESULT WINAPIV AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback, 2284 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...) 2285 { 2286 __ms_va_list vl; 2287 int i; 2288 HRESULT ret; 2289 PAVISTREAM *streams; 2290 LPAVICOMPRESSOPTIONS *options; 2291 2292 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler, lpfnCallback, 2293 nStreams, pavi, lpOptions); 2294 2295 if (nStreams <= 0) return AVIERR_BADPARAM; 2296 2297 streams = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*streams)); 2298 options = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(*options)); 2299 if (!streams || !options) 2300 { 2301 ret = AVIERR_MEMORY; 2302 goto error; 2303 } 2304 2305 streams[0] = pavi; 2306 options[0] = lpOptions; 2307 2308 __ms_va_start(vl, lpOptions); 2309 for (i = 1; i < nStreams; i++) 2310 { 2311 streams[i] = va_arg(vl, PAVISTREAM); 2312 options[i] = va_arg(vl, PAVICOMPRESSOPTIONS); 2313 } 2314 __ms_va_end(vl); 2315 2316 for (i = 0; i < nStreams; i++) 2317 TRACE("Pair[%d] - Stream = %p, Options = %p\n", i, streams[i], options[i]); 2318 2319 ret = AVISaveVW(szFile, pclsidHandler, lpfnCallback, nStreams, streams, options); 2320 error: 2321 HeapFree(GetProcessHeap(), 0, streams); 2322 HeapFree(GetProcessHeap(), 0, options); 2323 return ret; 2324 } 2325