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 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 CLSID's 1027 * 2. iterate over collected CLSID's 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) != S_OK) { 1034 HeapFree(GetProcessHeap(), 0, lp); 1035 return AVIERR_ERROR; 1036 } 1037 for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)/sizeof(szFileExt[0])) == S_OK;n++) { 1038 /* get CLSID to extension */ 1039 size = sizeof(szValue); 1040 if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK) 1041 break; 1042 1043 /* search if the CLSID is already known */ 1044 for (i = 1; i <= count; i++) { 1045 if (lstrcmpW(lp[i].szClsid, szValue) == 0) 1046 break; /* a new one */ 1047 } 1048 1049 if (i == count + 1) { 1050 /* it's a new CLSID */ 1051 1052 /* FIXME: How do we get info's about read/write capabilities? */ 1053 1054 if (count >= MAX_FILTERS) { 1055 /* try to inform user of our full fixed size table */ 1056 ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS); 1057 break; 1058 } 1059 1060 lstrcpyW(lp[i].szClsid, szValue); 1061 1062 count++; 1063 } 1064 1065 /* append extension to the filter */ 1066 wsprintfW(szValue, szExtensionFmt, szFileExt); 1067 if (lp[i].szExtensions[0] == 0) 1068 lstrcatW(lp[i].szExtensions, szValue + 1); 1069 else 1070 lstrcatW(lp[i].szExtensions, szValue); 1071 1072 /* also append to the "all multimedia"-filter */ 1073 if (lp[0].szExtensions[0] == 0) 1074 lstrcatW(lp[0].szExtensions, szValue + 1); 1075 else 1076 lstrcatW(lp[0].szExtensions, szValue); 1077 } 1078 RegCloseKey(hKey); 1079 1080 /* 2. get descriptions for the CLSIDs and fill out szFilter */ 1081 if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) { 1082 HeapFree(GetProcessHeap(), 0, lp); 1083 return AVIERR_ERROR; 1084 } 1085 for (n = 0; n <= count; n++) { 1086 /* first the description */ 1087 if (n != 0) { 1088 size = sizeof(szValue); 1089 if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) { 1090 size = lstrlenW(szValue); 1091 lstrcpynW(szFilter, szValue, cbFilter); 1092 } 1093 } else 1094 size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter); 1095 1096 /* check for enough space */ 1097 size++; 1098 if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) { 1099 szFilter[0] = 0; 1100 szFilter[1] = 0; 1101 HeapFree(GetProcessHeap(), 0, lp); 1102 RegCloseKey(hKey); 1103 return AVIERR_BUFFERTOOSMALL; 1104 } 1105 cbFilter -= size; 1106 szFilter += size; 1107 1108 /* and then the filter */ 1109 lstrcpynW(szFilter, lp[n].szExtensions, cbFilter); 1110 size = lstrlenW(lp[n].szExtensions) + 1; 1111 cbFilter -= size; 1112 szFilter += size; 1113 } 1114 1115 RegCloseKey(hKey); 1116 HeapFree(GetProcessHeap(), 0, lp); 1117 1118 /* add "All files" "*.*" filter if enough space left */ 1119 size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES, 1120 szAllFiles, sizeof(szAllFiles)/sizeof(szAllFiles[0])) + 1; 1121 if (cbFilter > size) { 1122 int i; 1123 1124 /* replace '@' with \000 to separate description of filter */ 1125 for (i = 0; i < size && szAllFiles[i] != 0; i++) { 1126 if (szAllFiles[i] == '@') { 1127 szAllFiles[i] = 0; 1128 break; 1129 } 1130 } 1131 1132 memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0])); 1133 szFilter += size; 1134 szFilter[0] = 0; 1135 1136 return AVIERR_OK; 1137 } else { 1138 szFilter[0] = 0; 1139 return AVIERR_BUFFERTOOSMALL; 1140 } 1141 } 1142 1143 static BOOL AVISaveOptionsFmtChoose(HWND hWnd) 1144 { 1145 LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent]; 1146 AVISTREAMINFOW sInfo; 1147 1148 TRACE("(%p)\n", hWnd); 1149 1150 if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) { 1151 ERR(": bad state!\n"); 1152 return FALSE; 1153 } 1154 1155 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], 1156 &sInfo, sizeof(sInfo)))) { 1157 ERR(": AVIStreamInfoW failed!\n"); 1158 return FALSE; 1159 } 1160 1161 if (sInfo.fccType == streamtypeVIDEO) { 1162 COMPVARS cv; 1163 BOOL ret; 1164 1165 memset(&cv, 0, sizeof(cv)); 1166 1167 if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) { 1168 memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS)); 1169 pOptions->fccType = streamtypeVIDEO; 1170 pOptions->fccHandler = comptypeDIB; 1171 pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT; 1172 } 1173 1174 cv.cbSize = sizeof(cv); 1175 cv.dwFlags = ICMF_COMPVARS_VALID; 1176 /*cv.fccType = pOptions->fccType; */ 1177 cv.fccHandler = pOptions->fccHandler; 1178 cv.lQ = pOptions->dwQuality; 1179 cv.lpState = pOptions->lpParms; 1180 cv.cbState = pOptions->cbParms; 1181 if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES) 1182 cv.lKey = pOptions->dwKeyFrameEvery; 1183 else 1184 cv.lKey = 0; 1185 if (pOptions->dwFlags & AVICOMPRESSF_DATARATE) 1186 cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */ 1187 else 1188 cv.lDataRate = 0; 1189 1190 ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL, 1191 SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL); 1192 1193 if (ret) { 1194 pOptions->fccHandler = cv.fccHandler; 1195 pOptions->lpParms = cv.lpState; 1196 pOptions->cbParms = cv.cbState; 1197 pOptions->dwQuality = cv.lQ; 1198 if (cv.lKey != 0) { 1199 pOptions->dwKeyFrameEvery = cv.lKey; 1200 pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES; 1201 } else 1202 pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES; 1203 if (cv.lDataRate != 0) { 1204 pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */ 1205 pOptions->dwFlags |= AVICOMPRESSF_DATARATE; 1206 } else 1207 pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE; 1208 pOptions->dwFlags |= AVICOMPRESSF_VALID; 1209 } 1210 ICCompressorFree(&cv); 1211 1212 return ret; 1213 } else if (sInfo.fccType == streamtypeAUDIO) { 1214 ACMFORMATCHOOSEW afmtc; 1215 MMRESULT ret; 1216 LONG size; 1217 1218 /* FIXME: check ACM version -- Which version is needed? */ 1219 1220 memset(&afmtc, 0, sizeof(afmtc)); 1221 afmtc.cbStruct = sizeof(afmtc); 1222 afmtc.fdwStyle = 0; 1223 afmtc.hwndOwner = hWnd; 1224 1225 acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size); 1226 if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) { 1227 pOptions->lpFormat = HeapAlloc(GetProcessHeap(), 0, size); 1228 if (!pOptions->lpFormat) return FALSE; 1229 pOptions->cbFormat = size; 1230 } else if (pOptions->cbFormat < (DWORD)size) { 1231 void *new_buffer = HeapReAlloc(GetProcessHeap(), 0, pOptions->lpFormat, size); 1232 if (!new_buffer) return FALSE; 1233 pOptions->lpFormat = new_buffer; 1234 pOptions->cbFormat = size; 1235 } 1236 afmtc.pwfx = pOptions->lpFormat; 1237 afmtc.cbwfx = pOptions->cbFormat; 1238 1239 size = 0; 1240 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent], 1241 sInfo.dwStart, &size); 1242 if (size < (LONG)sizeof(PCMWAVEFORMAT)) 1243 size = sizeof(PCMWAVEFORMAT); 1244 afmtc.pwfxEnum = HeapAlloc(GetProcessHeap(), 0, size); 1245 if (afmtc.pwfxEnum != NULL) { 1246 AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent], 1247 sInfo.dwStart, afmtc.pwfxEnum, &size); 1248 afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT; 1249 } 1250 1251 ret = acmFormatChooseW(&afmtc); 1252 if (ret == S_OK) 1253 pOptions->dwFlags |= AVICOMPRESSF_VALID; 1254 1255 HeapFree(GetProcessHeap(), 0, afmtc.pwfxEnum); 1256 return (ret == S_OK ? TRUE : FALSE); 1257 } else { 1258 ERR(": unknown streamtype 0x%08X\n", sInfo.fccType); 1259 return FALSE; 1260 } 1261 } 1262 1263 static void AVISaveOptionsUpdate(HWND hWnd) 1264 { 1265 static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0}; 1266 static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0}; 1267 1268 WCHAR szFormat[128]; 1269 AVISTREAMINFOW sInfo; 1270 LPVOID lpFormat; 1271 LONG size; 1272 1273 TRACE("(%p)\n", hWnd); 1274 1275 SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0); 1276 if (SaveOpts.nCurrent < 0) 1277 return; 1278 1279 if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo)))) 1280 return; 1281 1282 AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size); 1283 if (size > 0) { 1284 szFormat[0] = 0; 1285 1286 /* read format to build format description string */ 1287 lpFormat = HeapAlloc(GetProcessHeap(), 0, size); 1288 if (lpFormat != NULL) { 1289 if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) { 1290 if (sInfo.fccType == streamtypeVIDEO) { 1291 LPBITMAPINFOHEADER lpbi = lpFormat; 1292 ICINFO icinfo; 1293 1294 wsprintfW(szFormat, szVideoFmt, lpbi->biWidth, 1295 lpbi->biHeight, lpbi->biBitCount); 1296 1297 if (lpbi->biCompression != BI_RGB) { 1298 HIC hic; 1299 1300 hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat, 1301 NULL, ICMODE_DECOMPRESS); 1302 if (hic != NULL) { 1303 if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK) 1304 lstrcatW(szFormat, icinfo.szDescription); 1305 ICClose(hic); 1306 } 1307 } else { 1308 LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED, 1309 icinfo.szDescription, 1310 sizeof(icinfo.szDescription)/sizeof(icinfo.szDescription[0])); 1311 lstrcatW(szFormat, icinfo.szDescription); 1312 } 1313 } else if (sInfo.fccType == streamtypeAUDIO) { 1314 ACMFORMATTAGDETAILSW aftd; 1315 ACMFORMATDETAILSW afd; 1316 1317 memset(&aftd, 0, sizeof(aftd)); 1318 memset(&afd, 0, sizeof(afd)); 1319 1320 aftd.cbStruct = sizeof(aftd); 1321 aftd.dwFormatTag = afd.dwFormatTag = 1322 ((PWAVEFORMATEX)lpFormat)->wFormatTag; 1323 aftd.cbFormatSize = afd.cbwfx = size; 1324 1325 afd.cbStruct = sizeof(afd); 1326 afd.pwfx = lpFormat; 1327 1328 if (acmFormatTagDetailsW(NULL, &aftd, 1329 ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) { 1330 if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK) 1331 wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag); 1332 } 1333 } 1334 } 1335 HeapFree(GetProcessHeap(), 0, lpFormat); 1336 } 1337 1338 /* set text for format description */ 1339 SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat); 1340 1341 /* Disable option button for unsupported streamtypes */ 1342 if (sInfo.fccType == streamtypeVIDEO || 1343 sInfo.fccType == streamtypeAUDIO) 1344 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE); 1345 else 1346 EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE); 1347 } 1348 1349 } 1350 1351 static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg, 1352 WPARAM wParam, LPARAM lParam) 1353 { 1354 DWORD dwInterleave; 1355 BOOL bIsInterleaved; 1356 INT n; 1357 1358 /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/ 1359 1360 switch (uMsg) { 1361 case WM_INITDIALOG: 1362 SaveOpts.nCurrent = 0; 1363 if (SaveOpts.nStreams == 1) { 1364 EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd)); 1365 return TRUE; 1366 } 1367 1368 /* add streams */ 1369 for (n = 0; n < SaveOpts.nStreams; n++) { 1370 AVISTREAMINFOW sInfo; 1371 1372 AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo)); 1373 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING, 1374 0L, (LPARAM)sInfo.szName); 1375 } 1376 1377 /* select first stream */ 1378 SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0); 1379 SendMessageW(hWnd, WM_COMMAND, MAKELONG(IDC_STREAM, CBN_SELCHANGE), (LPARAM)hWnd); 1380 1381 /* initialize interleave */ 1382 if (SaveOpts.ppOptions[0] != NULL && 1383 (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) { 1384 bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE); 1385 dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery; 1386 } else { 1387 bIsInterleaved = TRUE; 1388 dwInterleave = 0; 1389 } 1390 CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved); 1391 SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE); 1392 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved); 1393 break; 1394 case WM_COMMAND: 1395 switch (LOWORD(wParam)) { 1396 case IDOK: 1397 /* get data from controls and save them */ 1398 dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0); 1399 bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE); 1400 for (n = 0; n < SaveOpts.nStreams; n++) { 1401 if (SaveOpts.ppOptions[n] != NULL) { 1402 if (bIsInterleaved) { 1403 SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE; 1404 SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave; 1405 } else 1406 SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE; 1407 } 1408 } 1409 /* fall through */ 1410 case IDCANCEL: 1411 EndDialog(hWnd, LOWORD(wParam) == IDOK); 1412 break; 1413 case IDC_INTERLEAVE: 1414 EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), 1415 IsDlgButtonChecked(hWnd, IDC_INTERLEAVE)); 1416 break; 1417 case IDC_STREAM: 1418 if (HIWORD(wParam) == CBN_SELCHANGE) { 1419 /* update control elements */ 1420 AVISaveOptionsUpdate(hWnd); 1421 } 1422 break; 1423 case IDC_OPTIONS: 1424 AVISaveOptionsFmtChoose(hWnd); 1425 break; 1426 }; 1427 return TRUE; 1428 }; 1429 1430 return FALSE; 1431 } 1432 1433 /*********************************************************************** 1434 * AVISaveOptions (AVIFIL32.@) 1435 */ 1436 BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams, 1437 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions) 1438 { 1439 LPAVICOMPRESSOPTIONS pSavedOptions = NULL; 1440 INT ret, n; 1441 1442 TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams, 1443 ppavi, ppOptions); 1444 1445 /* check parameters */ 1446 if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL) 1447 return AVIERR_BADPARAM; 1448 1449 /* save options in case the user presses cancel */ 1450 if (ppOptions != NULL && nStreams > 1) { 1451 pSavedOptions = HeapAlloc(GetProcessHeap(), 0, nStreams * sizeof(AVICOMPRESSOPTIONS)); 1452 if (pSavedOptions == NULL) 1453 return FALSE; 1454 1455 for (n = 0; n < nStreams; n++) { 1456 if (ppOptions[n] != NULL) 1457 memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS)); 1458 } 1459 } 1460 1461 SaveOpts.uFlags = uFlags; 1462 SaveOpts.nStreams = nStreams; 1463 SaveOpts.ppavis = ppavi; 1464 SaveOpts.ppOptions = ppOptions; 1465 1466 ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS), 1467 hWnd, AVISaveOptionsDlgProc); 1468 1469 if (ret == -1) 1470 ret = FALSE; 1471 1472 /* restore options when user pressed cancel */ 1473 if (pSavedOptions != NULL) { 1474 if (ret == FALSE) { 1475 for (n = 0; n < nStreams; n++) { 1476 if (ppOptions[n] != NULL) 1477 memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS)); 1478 } 1479 } 1480 HeapFree(GetProcessHeap(), 0, pSavedOptions); 1481 } 1482 1483 return ret; 1484 } 1485 1486 /*********************************************************************** 1487 * AVISaveOptionsFree (AVIFIL32.@) 1488 */ 1489 HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions) 1490 { 1491 TRACE("(%d,%p)\n", nStreams, ppOptions); 1492 1493 if (nStreams < 0 || ppOptions == NULL) 1494 return AVIERR_BADPARAM; 1495 1496 for (nStreams--; nStreams >= 0; nStreams--) { 1497 if (ppOptions[nStreams] != NULL) { 1498 ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID; 1499 1500 if (ppOptions[nStreams]->lpParms != NULL) { 1501 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpParms); 1502 ppOptions[nStreams]->lpParms = NULL; 1503 ppOptions[nStreams]->cbParms = 0; 1504 } 1505 if (ppOptions[nStreams]->lpFormat != NULL) { 1506 HeapFree(GetProcessHeap(), 0, ppOptions[nStreams]->lpFormat); 1507 ppOptions[nStreams]->lpFormat = NULL; 1508 ppOptions[nStreams]->cbFormat = 0; 1509 } 1510 } 1511 } 1512 1513 return AVIERR_OK; 1514 } 1515 1516 /*********************************************************************** 1517 * AVISaveVA (AVIFIL32.@) 1518 */ 1519 HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler, 1520 AVISAVECALLBACK lpfnCallback, int nStream, 1521 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions) 1522 { 1523 LPWSTR wszFile = NULL; 1524 HRESULT hr; 1525 int len; 1526 1527 TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler, 1528 lpfnCallback, nStream, ppavi, plpOptions); 1529 1530 if (szFile == NULL || ppavi == NULL || plpOptions == NULL) 1531 return AVIERR_BADPARAM; 1532 1533 /* convert ASCII string to Unicode and call Unicode function */ 1534 len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0); 1535 if (len <= 0) 1536 return AVIERR_BADPARAM; 1537 1538 wszFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1539 if (wszFile == NULL) 1540 return AVIERR_MEMORY; 1541 1542 MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len); 1543 1544 hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback, 1545 nStream, ppavi, plpOptions); 1546 1547 HeapFree(GetProcessHeap(), 0, wszFile); 1548 1549 return hr; 1550 } 1551 1552 /*********************************************************************** 1553 * AVIFILE_AVISaveDefaultCallback (internal) 1554 */ 1555 static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress) 1556 { 1557 TRACE("(%d)\n", progress); 1558 1559 return FALSE; 1560 } 1561 1562 /*********************************************************************** 1563 * AVISaveVW (AVIFIL32.@) 1564 */ 1565 HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler, 1566 AVISAVECALLBACK lpfnCallback, int nStreams, 1567 PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions) 1568 { 1569 LONG lStart[MAX_AVISTREAMS]; 1570 PAVISTREAM pOutStreams[MAX_AVISTREAMS]; 1571 PAVISTREAM pInStreams[MAX_AVISTREAMS]; 1572 AVIFILEINFOW fInfo; 1573 AVISTREAMINFOW sInfo; 1574 1575 PAVIFILE pfile = NULL; /* the output AVI file */ 1576 LONG lFirstVideo = -1; 1577 int curStream; 1578 1579 /* for interleaving ... */ 1580 DWORD dwInterleave = 0; /* interleave rate */ 1581 DWORD dwFileInitialFrames; 1582 LONG lFileLength; 1583 LONG lSampleInc; 1584 1585 /* for reading/writing the data ... */ 1586 LPVOID lpBuffer = NULL; 1587 LONG cbBuffer; /* real size of lpBuffer */ 1588 LONG lBufferSize; /* needed bytes for format(s), etc. */ 1589 LONG lReadBytes; 1590 LONG lReadSamples; 1591 HRESULT hres; 1592 1593 TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler, 1594 lpfnCallback, nStreams, ppavi, plpOptions); 1595 1596 if (szFile == NULL || ppavi == NULL || plpOptions == NULL) 1597 return AVIERR_BADPARAM; 1598 if (nStreams >= MAX_AVISTREAMS) { 1599 WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS); 1600 return AVIERR_INTERNAL; 1601 } 1602 1603 if (lpfnCallback == NULL) 1604 lpfnCallback = AVIFILE_AVISaveDefaultCallback; 1605 1606 /* clear local variable(s) */ 1607 for (curStream = 0; curStream < nStreams; curStream++) { 1608 pInStreams[curStream] = NULL; 1609 pOutStreams[curStream] = NULL; 1610 } 1611 1612 /* open output AVI file (create it if it doesn't exist) */ 1613 hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE, 1614 pclsidHandler); 1615 if (FAILED(hres)) 1616 return hres; 1617 AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */ 1618 1619 /* initialize our data structures part 1 */ 1620 for (curStream = 0; curStream < nStreams; curStream++) { 1621 PAVISTREAM pCurStream = ppavi[curStream]; 1622 1623 hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo)); 1624 if (FAILED(hres)) 1625 goto error; 1626 1627 /* search first video stream and check for interleaving */ 1628 if (sInfo.fccType == streamtypeVIDEO) { 1629 /* remember first video stream -- needed for interleaving */ 1630 if (lFirstVideo < 0) 1631 lFirstVideo = curStream; 1632 } else if (!dwInterleave && plpOptions != NULL) { 1633 /* check if any non-video stream wants to be interleaved */ 1634 WARN("options.flags=0x%X options.dwInterleave=%u\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery); 1635 if (plpOptions[curStream] != NULL && 1636 plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE) 1637 dwInterleave = plpOptions[curStream]->dwInterleaveEvery; 1638 } 1639 1640 /* create de-/compressed stream interface if needed */ 1641 pInStreams[curStream] = NULL; 1642 if (plpOptions != NULL && plpOptions[curStream] != NULL) { 1643 if (plpOptions[curStream]->fccHandler || 1644 plpOptions[curStream]->lpFormat != NULL) { 1645 DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery; 1646 1647 if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES) 1648 plpOptions[curStream]->dwKeyFrameEvery = 1; 1649 1650 hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream, 1651 plpOptions[curStream], NULL); 1652 plpOptions[curStream]->dwKeyFrameEvery = dwKeySave; 1653 if (FAILED(hres) || pInStreams[curStream] == NULL) { 1654 pInStreams[curStream] = NULL; 1655 goto error; 1656 } 1657 1658 /* test stream interface and update stream-info */ 1659 hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); 1660 if (FAILED(hres)) 1661 goto error; 1662 } 1663 } 1664 1665 /* now handle streams which will only be copied */ 1666 if (pInStreams[curStream] == NULL) { 1667 pCurStream = pInStreams[curStream] = ppavi[curStream]; 1668 AVIStreamAddRef(pCurStream); 1669 } else 1670 pCurStream = pInStreams[curStream]; 1671 1672 lStart[curStream] = sInfo.dwStart; 1673 } /* for all streams */ 1674 1675 /* check that first video stream is the first stream */ 1676 if (lFirstVideo > 0) { 1677 PAVISTREAM pTmp = pInStreams[lFirstVideo]; 1678 LONG lTmp = lStart[lFirstVideo]; 1679 1680 pInStreams[lFirstVideo] = pInStreams[0]; 1681 pInStreams[0] = pTmp; 1682 lStart[lFirstVideo] = lStart[0]; 1683 lStart[0] = lTmp; 1684 lFirstVideo = 0; 1685 } 1686 1687 /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/ 1688 cbBuffer = 0x00010000; 1689 lpBuffer = HeapAlloc(GetProcessHeap(), 0, cbBuffer); 1690 if (lpBuffer == NULL) { 1691 hres = AVIERR_MEMORY; 1692 goto error; 1693 } 1694 1695 AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo)); 1696 lFileLength = sInfo.dwLength; 1697 dwFileInitialFrames = 0; 1698 if (lFirstVideo >= 0) { 1699 /* check for correct version of the format 1700 * -- need at least BITMAPINFOHEADER or newer 1701 */ 1702 lSampleInc = 1; 1703 lBufferSize = cbBuffer; 1704 hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize); 1705 if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER)) 1706 hres = AVIERR_INTERNAL; 1707 if (FAILED(hres)) 1708 goto error; 1709 } else /* use one second blocks for interleaving if no video present */ 1710 lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000); 1711 1712 /* create output streams */ 1713 for (curStream = 0; curStream < nStreams; curStream++) { 1714 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); 1715 1716 sInfo.dwInitialFrames = 0; 1717 if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) { 1718 /* 750 ms initial frames for non-video streams */ 1719 sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750); 1720 } 1721 1722 hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo); 1723 if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) { 1724 /* copy initial format for this stream */ 1725 lBufferSize = cbBuffer; 1726 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, 1727 lpBuffer, &lBufferSize); 1728 if (FAILED(hres)) 1729 goto error; 1730 hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize); 1731 if (FAILED(hres)) 1732 goto error; 1733 1734 /* try to copy stream handler data */ 1735 lBufferSize = cbBuffer; 1736 hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA, 1737 lpBuffer, &lBufferSize); 1738 if (SUCCEEDED(hres) && lBufferSize > 0) { 1739 hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA, 1740 lpBuffer, lBufferSize); 1741 if (FAILED(hres)) 1742 goto error; 1743 } 1744 1745 if (dwFileInitialFrames < sInfo.dwInitialFrames) 1746 dwFileInitialFrames = sInfo.dwInitialFrames; 1747 lReadBytes = 1748 AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream], 1749 sInfo.dwLength); 1750 if (lFileLength < lReadBytes) 1751 lFileLength = lReadBytes; 1752 } else { 1753 /* creation of de-/compression stream interface failed */ 1754 WARN("creation of (de-)compression stream failed for stream %d\n",curStream); 1755 AVIStreamRelease(pInStreams[curStream]); 1756 if (curStream + 1 >= nStreams) { 1757 /* move the others one up */ 1758 PAVISTREAM *ppas = &pInStreams[curStream]; 1759 int n = nStreams - (curStream + 1); 1760 1761 do { 1762 *ppas = pInStreams[curStream + 1]; 1763 } while (--n); 1764 } 1765 nStreams--; 1766 curStream--; 1767 } 1768 } /* create output streams for all input streams */ 1769 1770 /* have we still something to write, or lost everything? */ 1771 if (nStreams <= 0) 1772 goto error; 1773 1774 if (dwInterleave) { 1775 LONG lCurFrame = -dwFileInitialFrames; 1776 1777 /* interleaved file */ 1778 if (dwInterleave == 1) 1779 AVIFileEndRecord(pfile); 1780 1781 for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) { 1782 for (curStream = 0; curStream < nStreams; curStream++) { 1783 LONG lLastSample; 1784 1785 hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo)); 1786 if (FAILED(hres)) 1787 goto error; 1788 1789 /* initial frames phase at the end for this stream? */ 1790 if (-(LONG)sInfo.dwInitialFrames > lCurFrame) 1791 continue; 1792 1793 if ((lFileLength - lSampleInc) <= lCurFrame) { 1794 lLastSample = AVIStreamLength(pInStreams[curStream]); 1795 lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]); 1796 } else { 1797 if (curStream != 0) { 1798 lFirstVideo = 1799 AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0], 1800 (sInfo.fccType == streamtypeVIDEO ? 1801 (LONG)dwInterleave : lSampleInc) + 1802 sInfo.dwInitialFrames + lCurFrame); 1803 } else 1804 lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame); 1805 1806 lLastSample = AVIStreamEnd(pInStreams[curStream]); 1807 if (lLastSample <= lFirstVideo) 1808 lFirstVideo = lLastSample; 1809 } 1810 1811 /* copy needed samples now */ 1812 WARN("copy from stream %d samples %d to %d...\n",curStream, 1813 lStart[curStream],lFirstVideo); 1814 while (lFirstVideo > lStart[curStream]) { 1815 DWORD flags = 0; 1816 1817 /* copy format in case it can change */ 1818 lBufferSize = cbBuffer; 1819 hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream], 1820 lpBuffer, &lBufferSize); 1821 if (FAILED(hres)) 1822 goto error; 1823 AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream], 1824 lpBuffer, lBufferSize); 1825 1826 /* try to read data until we got it, or error */ 1827 do { 1828 hres = AVIStreamRead(pInStreams[curStream], lStart[curStream], 1829 lFirstVideo - lStart[curStream], lpBuffer, 1830 cbBuffer, &lReadBytes, &lReadSamples); 1831 } while ((hres == AVIERR_BUFFERTOOSMALL) && 1832 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); 1833 if (lpBuffer == NULL) 1834 hres = AVIERR_MEMORY; 1835 if (FAILED(hres)) 1836 goto error; 1837 1838 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart)) 1839 flags = AVIIF_KEYFRAME; 1840 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, 1841 lpBuffer, lReadBytes, flags, NULL, NULL); 1842 if (FAILED(hres)) 1843 goto error; 1844 1845 lStart[curStream] += lReadSamples; 1846 } 1847 lStart[curStream] = lFirstVideo; 1848 } /* stream by stream */ 1849 1850 /* need to close this block? */ 1851 if (dwInterleave == 1) { 1852 hres = AVIFileEndRecord(pfile); 1853 if (FAILED(hres)) 1854 break; 1855 } 1856 1857 /* show progress */ 1858 if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100, 1859 dwFileInitialFrames + lFileLength))) { 1860 hres = AVIERR_USERABORT; 1861 break; 1862 } 1863 } /* copy frame by frame */ 1864 } else { 1865 /* non-interleaved file */ 1866 1867 for (curStream = 0; curStream < nStreams; curStream++) { 1868 /* show progress */ 1869 if (lpfnCallback(MulDiv(curStream, 100, nStreams))) { 1870 hres = AVIERR_USERABORT; 1871 goto error; 1872 } 1873 1874 AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo)); 1875 1876 if (sInfo.dwSampleSize != 0) { 1877 /* sample-based data like audio */ 1878 while (sInfo.dwStart < sInfo.dwLength) { 1879 LONG lSamples = cbBuffer / sInfo.dwSampleSize; 1880 1881 /* copy format in case it can change */ 1882 lBufferSize = cbBuffer; 1883 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, 1884 lpBuffer, &lBufferSize); 1885 if (FAILED(hres)) 1886 goto error; 1887 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart, 1888 lpBuffer, lBufferSize); 1889 1890 /* limit to stream boundaries */ 1891 if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart)) 1892 lSamples = sInfo.dwLength - sInfo.dwStart; 1893 1894 /* now try to read until we get it, or an error occurs */ 1895 do { 1896 lReadBytes = cbBuffer; 1897 lReadSamples = 0; 1898 hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples, 1899 lpBuffer,cbBuffer,&lReadBytes,&lReadSamples); 1900 } while ((hres == AVIERR_BUFFERTOOSMALL) && 1901 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); 1902 if (lpBuffer == NULL) 1903 hres = AVIERR_MEMORY; 1904 if (FAILED(hres)) 1905 goto error; 1906 if (lReadSamples != 0) { 1907 sInfo.dwStart += lReadSamples; 1908 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, 1909 lpBuffer, lReadBytes, 0, NULL , NULL); 1910 if (FAILED(hres)) 1911 goto error; 1912 1913 /* show progress */ 1914 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+ 1915 MulDiv(curStream, 100, nStreams))) { 1916 hres = AVIERR_USERABORT; 1917 goto error; 1918 } 1919 } else { 1920 if ((sInfo.dwLength - sInfo.dwStart) != 1) { 1921 hres = AVIERR_FILEREAD; 1922 goto error; 1923 } 1924 } 1925 } 1926 } else { 1927 /* block-based data like video */ 1928 for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) { 1929 DWORD flags = 0; 1930 1931 /* copy format in case it can change */ 1932 lBufferSize = cbBuffer; 1933 hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart, 1934 lpBuffer, &lBufferSize); 1935 if (FAILED(hres)) 1936 goto error; 1937 AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart, 1938 lpBuffer, lBufferSize); 1939 1940 /* try to read block and resize buffer if necessary */ 1941 do { 1942 lReadSamples = 0; 1943 lReadBytes = cbBuffer; 1944 hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1, 1945 lpBuffer, cbBuffer,&lReadBytes,&lReadSamples); 1946 } while ((hres == AVIERR_BUFFERTOOSMALL) && 1947 (lpBuffer = HeapReAlloc(GetProcessHeap(), 0, lpBuffer, cbBuffer *= 2)) != NULL); 1948 if (lpBuffer == NULL) 1949 hres = AVIERR_MEMORY; 1950 if (FAILED(hres)) 1951 goto error; 1952 if (lReadSamples != 1) { 1953 hres = AVIERR_FILEREAD; 1954 goto error; 1955 } 1956 1957 if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart)) 1958 flags = AVIIF_KEYFRAME; 1959 hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples, 1960 lpBuffer, lReadBytes, flags, NULL, NULL); 1961 if (FAILED(hres)) 1962 goto error; 1963 1964 /* show progress */ 1965 if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+ 1966 MulDiv(curStream, 100, nStreams))) { 1967 hres = AVIERR_USERABORT; 1968 goto error; 1969 } 1970 } /* copy all blocks */ 1971 } 1972 } /* copy data stream by stream */ 1973 } 1974 1975 error: 1976 HeapFree(GetProcessHeap(), 0, lpBuffer); 1977 if (pfile != NULL) { 1978 for (curStream = 0; curStream < nStreams; curStream++) { 1979 if (pOutStreams[curStream] != NULL) 1980 AVIStreamRelease(pOutStreams[curStream]); 1981 if (pInStreams[curStream] != NULL) 1982 AVIStreamRelease(pInStreams[curStream]); 1983 } 1984 1985 AVIFileRelease(pfile); 1986 } 1987 1988 return hres; 1989 } 1990 1991 /*********************************************************************** 1992 * CreateEditableStream (AVIFIL32.@) 1993 */ 1994 HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource) 1995 { 1996 IAVIEditStream *pEdit = NULL; 1997 HRESULT hr; 1998 1999 TRACE("(%p,%p)\n", ppEditable, pSource); 2000 2001 if (ppEditable == NULL) 2002 return AVIERR_BADPARAM; 2003 2004 *ppEditable = NULL; 2005 2006 if (pSource != NULL) { 2007 hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream, 2008 (LPVOID*)&pEdit); 2009 if (SUCCEEDED(hr) && pEdit != NULL) { 2010 hr = IAVIEditStream_Clone(pEdit, ppEditable); 2011 IAVIEditStream_Release(pEdit); 2012 2013 return hr; 2014 } 2015 } 2016 2017 /* need own implementation of IAVIEditStream */ 2018 pEdit = AVIFILE_CreateEditStream(pSource); 2019 if (pEdit == NULL) 2020 return AVIERR_MEMORY; 2021 2022 hr = IAVIEditStream_QueryInterface(pEdit, &IID_IAVIStream, 2023 (LPVOID*)ppEditable); 2024 IAVIEditStream_Release(pEdit); 2025 2026 return hr; 2027 } 2028 2029 /*********************************************************************** 2030 * EditStreamClone (AVIFIL32.@) 2031 */ 2032 HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult) 2033 { 2034 PAVIEDITSTREAM pEdit = NULL; 2035 HRESULT hr; 2036 2037 TRACE("(%p,%p)\n", pStream, ppResult); 2038 2039 if (pStream == NULL) 2040 return AVIERR_BADHANDLE; 2041 if (ppResult == NULL) 2042 return AVIERR_BADPARAM; 2043 2044 *ppResult = NULL; 2045 2046 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2047 if (SUCCEEDED(hr) && pEdit != NULL) { 2048 hr = IAVIEditStream_Clone(pEdit, ppResult); 2049 2050 IAVIEditStream_Release(pEdit); 2051 } else 2052 hr = AVIERR_UNSUPPORTED; 2053 2054 return hr; 2055 } 2056 2057 /*********************************************************************** 2058 * EditStreamCopy (AVIFIL32.@) 2059 */ 2060 HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart, 2061 LONG *plLength, PAVISTREAM *ppResult) 2062 { 2063 PAVIEDITSTREAM pEdit = NULL; 2064 HRESULT hr; 2065 2066 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult); 2067 2068 if (pStream == NULL) 2069 return AVIERR_BADHANDLE; 2070 if (plStart == NULL || plLength == NULL || ppResult == NULL) 2071 return AVIERR_BADPARAM; 2072 2073 *ppResult = NULL; 2074 2075 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2076 if (SUCCEEDED(hr) && pEdit != NULL) { 2077 hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult); 2078 2079 IAVIEditStream_Release(pEdit); 2080 } else 2081 hr = AVIERR_UNSUPPORTED; 2082 2083 return hr; 2084 } 2085 2086 /*********************************************************************** 2087 * EditStreamCut (AVIFIL32.@) 2088 */ 2089 HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart, 2090 LONG *plLength, PAVISTREAM *ppResult) 2091 { 2092 PAVIEDITSTREAM pEdit = NULL; 2093 HRESULT hr; 2094 2095 TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult); 2096 2097 if (ppResult != NULL) 2098 *ppResult = NULL; 2099 if (pStream == NULL) 2100 return AVIERR_BADHANDLE; 2101 if (plStart == NULL || plLength == NULL) 2102 return AVIERR_BADPARAM; 2103 2104 hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2105 if (SUCCEEDED(hr) && pEdit != NULL) { 2106 hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult); 2107 2108 IAVIEditStream_Release(pEdit); 2109 } else 2110 hr = AVIERR_UNSUPPORTED; 2111 2112 return hr; 2113 } 2114 2115 /*********************************************************************** 2116 * EditStreamPaste (AVIFIL32.@) 2117 */ 2118 HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength, 2119 PAVISTREAM pSource, LONG lStart, LONG lEnd) 2120 { 2121 PAVIEDITSTREAM pEdit = NULL; 2122 HRESULT hr; 2123 2124 TRACE("(%p,%p,%p,%p,%d,%d)\n", pDest, plStart, plLength, 2125 pSource, lStart, lEnd); 2126 2127 if (pDest == NULL || pSource == NULL) 2128 return AVIERR_BADHANDLE; 2129 if (plStart == NULL || plLength == NULL || lStart < 0) 2130 return AVIERR_BADPARAM; 2131 2132 hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2133 if (SUCCEEDED(hr) && pEdit != NULL) { 2134 hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd); 2135 2136 IAVIEditStream_Release(pEdit); 2137 } else 2138 hr = AVIERR_UNSUPPORTED; 2139 2140 return hr; 2141 } 2142 2143 /*********************************************************************** 2144 * EditStreamSetInfoA (AVIFIL32.@) 2145 */ 2146 HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi, 2147 LONG size) 2148 { 2149 AVISTREAMINFOW asiw; 2150 2151 TRACE("(%p,%p,%d)\n", pstream, asi, size); 2152 2153 if (pstream == NULL) 2154 return AVIERR_BADHANDLE; 2155 if ((DWORD)size < sizeof(AVISTREAMINFOA)) 2156 return AVIERR_BADSIZE; 2157 2158 memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName)); 2159 MultiByteToWideChar(CP_ACP, 0, asi->szName, -1, 2160 asiw.szName, sizeof(asiw.szName)/sizeof(WCHAR)); 2161 2162 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw)); 2163 } 2164 2165 /*********************************************************************** 2166 * EditStreamSetInfoW (AVIFIL32.@) 2167 */ 2168 HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi, 2169 LONG size) 2170 { 2171 PAVIEDITSTREAM pEdit = NULL; 2172 HRESULT hr; 2173 2174 TRACE("(%p,%p,%d)\n", pstream, asi, size); 2175 2176 hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit); 2177 if (SUCCEEDED(hr) && pEdit != NULL) { 2178 hr = IAVIEditStream_SetInfo(pEdit, asi, size); 2179 2180 IAVIEditStream_Release(pEdit); 2181 } else 2182 hr = AVIERR_UNSUPPORTED; 2183 2184 return hr; 2185 } 2186 2187 /*********************************************************************** 2188 * EditStreamSetNameA (AVIFIL32.@) 2189 */ 2190 HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName) 2191 { 2192 AVISTREAMINFOA asia; 2193 HRESULT hres; 2194 2195 TRACE("(%p,%s)\n", pstream, debugstr_a(szName)); 2196 2197 if (pstream == NULL) 2198 return AVIERR_BADHANDLE; 2199 if (szName == NULL) 2200 return AVIERR_BADPARAM; 2201 2202 hres = AVIStreamInfoA(pstream, &asia, sizeof(asia)); 2203 if (FAILED(hres)) 2204 return hres; 2205 2206 memset(asia.szName, 0, sizeof(asia.szName)); 2207 lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0])); 2208 2209 return EditStreamSetInfoA(pstream, &asia, sizeof(asia)); 2210 } 2211 2212 /*********************************************************************** 2213 * EditStreamSetNameW (AVIFIL32.@) 2214 */ 2215 HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName) 2216 { 2217 AVISTREAMINFOW asiw; 2218 HRESULT hres; 2219 2220 TRACE("(%p,%s)\n", pstream, debugstr_w(szName)); 2221 2222 if (pstream == NULL) 2223 return AVIERR_BADHANDLE; 2224 if (szName == NULL) 2225 return AVIERR_BADPARAM; 2226 2227 hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw)); 2228 if (FAILED(hres)) 2229 return hres; 2230 2231 memset(asiw.szName, 0, sizeof(asiw.szName)); 2232 lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0])); 2233 2234 return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw)); 2235 } 2236 2237 /*********************************************************************** 2238 * AVIClearClipboard (AVIFIL32.@) 2239 */ 2240 HRESULT WINAPI AVIClearClipboard(void) 2241 { 2242 TRACE("()\n"); 2243 2244 return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */ 2245 } 2246 2247 /*********************************************************************** 2248 * AVIGetFromClipboard (AVIFIL32.@) 2249 */ 2250 HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile) 2251 { 2252 FIXME("(%p), stub!\n", ppfile); 2253 2254 *ppfile = NULL; 2255 2256 return AVIERR_UNSUPPORTED; 2257 } 2258 2259 /*********************************************************************** 2260 * AVIMakeStreamFromClipboard (AVIFIL32.@) 2261 */ 2262 HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal, 2263 PAVISTREAM * ppstream) 2264 { 2265 FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream); 2266 2267 if (ppstream == NULL) 2268 return AVIERR_BADHANDLE; 2269 2270 return AVIERR_UNSUPPORTED; 2271 } 2272 2273 /*********************************************************************** 2274 * AVIPutFileOnClipboard (AVIFIL32.@) 2275 */ 2276 HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile) 2277 { 2278 FIXME("(%p), stub!\n", pfile); 2279 2280 if (pfile == NULL) 2281 return AVIERR_BADHANDLE; 2282 2283 return AVIERR_UNSUPPORTED; 2284 } 2285 2286 HRESULT WINAPIV AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback, 2287 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...) 2288 { 2289 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_a(szFile), pclsidHandler, lpfnCallback, 2290 nStreams, pavi, lpOptions); 2291 2292 return AVIERR_UNSUPPORTED; 2293 } 2294 2295 HRESULT WINAPIV AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback, 2296 int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...) 2297 { 2298 FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler, lpfnCallback, 2299 nStreams, pavi, lpOptions); 2300 2301 return AVIERR_UNSUPPORTED; 2302 } 2303