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