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