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