ReactOS  0.4.13-dev-464-g6b95727
avisplit.c
Go to the documentation of this file.
1 /*
2  * AVI Splitter Filter
3  *
4  * Copyright 2003 Robert Shearman
5  * Copyright 2004-2005 Christian Costa
6  * Copyright 2008 Maarten Lankhorst
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 /* FIXME:
23  * - Reference leaks, if they still exist
24  * - Files without an index are not handled correctly yet.
25  * - When stopping/starting, a sample is lost. This should be compensated by
26  * keeping track of previous index/position.
27  * - Debugging channels are noisy at the moment, especially with thread
28  * related messages, however this is the only correct thing to do right now,
29  * since wine doesn't correctly handle all messages yet.
30  */
31 
32 #include "quartz_private.h"
33 #include "pin.h"
34 
35 #include "uuids.h"
36 #include "vfw.h"
37 #include "aviriff.h"
38 #include "vfwmsgs.h"
39 #include "amvideo.h"
40 
41 #include "wine/unicode.h"
42 #include "wine/debug.h"
43 
44 #include <math.h>
45 #include <assert.h>
46 
47 #include "parser.h"
48 
49 #define TWOCCFromFOURCC(fcc) HIWORD(fcc)
50 
51 /* four character codes used in AVI files */
52 #define ckidINFO mmioFOURCC('I','N','F','O')
53 #define ckidREC mmioFOURCC('R','E','C',' ')
54 
56 
57 typedef struct StreamData
58 {
62 
68 
69  /* Position, in index units */
71 
72  /* Packet handling: a thread is created and waits on the packet event handle
73  * On an event acquire the sample lock, addref the sample and set it to NULL,
74  * then queue a new packet.
75  */
78 
79  /* Amount of preroll samples for this stream */
81 } StreamData;
82 
83 typedef struct AVISplitterImpl
84 {
87  LONGLONG CurrentChunkOffset; /* in media time */
91 
94 
97 
98 struct thread_args {
101 };
102 
104 {
105  return CONTAINING_RECORD(iface, AVISplitterImpl, Parser.sourceSeeking.IMediaSeeking_iface);
106 }
107 
108 /* The threading stuff cries for an explanation
109  *
110  * PullPin starts processing and calls AVISplitter_first_request
111  * AVISplitter_first_request creates a thread for each stream
112  * A stream can be audio, video, subtitles or something undefined.
113  *
114  * AVISplitter_first_request loads a single packet to each but one stream,
115  * and queues it for that last stream. This is to prevent WaitForNext to time
116  * out badly.
117  *
118  * The processing loop is entered. It calls IAsyncReader_WaitForNext in the
119  * PullPin. Every time it receives a packet, it will call AVISplitter_Sample
120  * AVISplitter_Sample will signal the relevant thread that a new sample is
121  * arrived, when that thread is ready it will read the packet and transmits
122  * it downstream with AVISplitter_Receive
123  *
124  * Threads terminate upon receiving NULL as packet or when ANY error code
125  * != S_OK occurs. This means that any error is fatal to processing.
126  */
127 
129 {
130  IPin* ppin = NULL;
131  HRESULT hr;
132 
133  TRACE("End of file reached\n");
134 
135  hr = IPin_ConnectedTo(This->Parser.ppPins[streamnumber+1], &ppin);
136  if (SUCCEEDED(hr))
137  {
138  hr = IPin_EndOfStream(ppin);
139  IPin_Release(ppin);
140  }
141  TRACE("--> %x\n", hr);
142 
143  /* Force the pullpin thread to stop */
144  return S_FALSE;
145 }
146 
147 /* Thread worker horse */
149 {
150  StreamData *stream = This->streams + streamnumber;
151  PullPin *pin = This->Parser.pInputPin;
152  IMediaSample *sample = NULL;
153  HRESULT hr;
154  ULONG ref;
155 
156  TRACE("(%p, %u)->()\n", This, streamnumber);
157 
158  hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
159  if (hr != S_OK)
160  ERR("... %08x?\n", hr);
161 
162  if (SUCCEEDED(hr))
163  {
164  LONGLONG rtSampleStart;
165  /* Add 4 for the next header, which should hopefully work */
166  LONGLONG rtSampleStop;
167 
168  stream->pos = stream->pos_next;
169  stream->index = stream->index_next;
170 
171  IMediaSample_SetDiscontinuity(sample, stream->seek);
172  stream->seek = FALSE;
173  if (stream->preroll)
174  {
175  --stream->preroll;
176  IMediaSample_SetPreroll(sample, TRUE);
177  }
178  else
179  IMediaSample_SetPreroll(sample, FALSE);
180  IMediaSample_SetSyncPoint(sample, TRUE);
181 
182  if (stream->stdindex)
183  {
184  AVISTDINDEX *index = stream->stdindex[stream->index];
185  AVISTDINDEX_ENTRY *entry = &index->aIndex[stream->pos];
186 
187  /* End of file */
188  if (stream->index >= stream->entries)
189  {
190  TRACE("END OF STREAM ON %u\n", streamnumber);
191  IMediaSample_Release(sample);
192  return S_FALSE;
193  }
194 
195  rtSampleStart = index->qwBaseOffset;
196  rtSampleStart += entry->dwOffset;
197  rtSampleStart = MEDIATIME_FROM_BYTES(rtSampleStart);
198 
199  ++stream->pos_next;
200  if (index->nEntriesInUse == stream->pos_next)
201  {
202  stream->pos_next = 0;
203  ++stream->index_next;
204  }
205 
206  rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(entry->dwSize & ~(1u << 31));
207 
208  TRACE("offset(%u) size(%u)\n", (DWORD)BYTES_FROM_MEDIATIME(rtSampleStart), (DWORD)BYTES_FROM_MEDIATIME(rtSampleStop - rtSampleStart));
209  }
210  else if (This->oldindex)
211  {
212  DWORD flags = This->oldindex->aIndex[stream->pos].dwFlags;
213  DWORD size = This->oldindex->aIndex[stream->pos].dwSize;
214 
215  /* End of file */
216  if (stream->index)
217  {
218  TRACE("END OF STREAM ON %u\n", streamnumber);
219  IMediaSample_Release(sample);
220  return S_FALSE;
221  }
222 
223  rtSampleStart = MEDIATIME_FROM_BYTES(This->offset);
224  rtSampleStart += MEDIATIME_FROM_BYTES(This->oldindex->aIndex[stream->pos].dwOffset);
225  rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(size);
226  if (flags & AVIIF_MIDPART)
227  {
228  FIXME("Only stand alone frames are currently handled correctly!\n");
229  }
230  if (flags & AVIIF_LIST)
231  {
232  FIXME("Not sure if this is handled correctly\n");
233  rtSampleStart += MEDIATIME_FROM_BYTES(sizeof(RIFFLIST));
234  rtSampleStop += MEDIATIME_FROM_BYTES(sizeof(RIFFLIST));
235  }
236  else
237  {
238  rtSampleStart += MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK));
239  rtSampleStop += MEDIATIME_FROM_BYTES(sizeof(RIFFCHUNK));
240  }
241 
242  /* Slow way of finding next index */
243  do {
244  stream->pos_next++;
245  } while (stream->pos_next * sizeof(This->oldindex->aIndex[0]) < This->oldindex->cb
246  && StreamFromFOURCC(This->oldindex->aIndex[stream->pos_next].dwChunkId) != streamnumber);
247 
248  /* End of file soon */
249  if (stream->pos_next * sizeof(This->oldindex->aIndex[0]) >= This->oldindex->cb)
250  {
251  stream->pos_next = 0;
252  ++stream->index_next;
253  }
254  }
255  else /* TODO: Generate an index automagically */
256  {
257  ERR("CAN'T PLAY WITHOUT AN INDEX! SOS! SOS! SOS!\n");
258  assert(0);
259  }
260 
261  if (rtSampleStart != rtSampleStop)
262  {
263  IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
264  hr = IAsyncReader_Request(pin->pReader, sample, streamnumber);
265 
266  if (FAILED(hr))
267  {
268  ref = IMediaSample_Release(sample);
269  assert(ref == 0);
270  }
271  }
272  else
273  {
274  stream->sample = sample;
275  IMediaSample_SetActualDataLength(sample, 0);
276  SetEvent(stream->packet_queued);
277  }
278  }
279  else
280  {
281  if (sample)
282  {
283  ERR("There should be no sample!\n");
284  ref = IMediaSample_Release(sample);
285  assert(ref == 0);
286  }
287  }
288  TRACE("--> %08x\n", hr);
289 
290  return hr;
291 }
292 
294 {
295  Parser_OutputPin *pin = unsafe_impl_Parser_OutputPin_from_IPin(This->Parser.ppPins[1+streamnumber]);
296  HRESULT hr;
297  LONGLONG start, stop, rtstart, rtstop;
298  StreamData *stream = &This->streams[streamnumber];
299 
300  start = pin->dwSamplesProcessed;
301  start *= stream->streamheader.dwScale;
302  start *= 10000000;
303  start /= stream->streamheader.dwRate;
304 
305  if (stream->streamheader.dwSampleSize)
306  {
307  ULONG len = IMediaSample_GetActualDataLength(sample);
308  ULONG size = stream->streamheader.dwSampleSize;
309 
310  pin->dwSamplesProcessed += len / size;
311  }
312  else
313  ++pin->dwSamplesProcessed;
314 
315  stop = pin->dwSamplesProcessed;
316  stop *= stream->streamheader.dwScale;
317  stop *= 10000000;
318  stop /= stream->streamheader.dwRate;
319 
320  if (IMediaSample_IsDiscontinuity(sample) == S_OK) {
321  IPin *victim;
322  EnterCriticalSection(&This->Parser.filter.csFilter);
323  pin->pin.pin.tStart = start;
324  pin->pin.pin.dRate = This->Parser.sourceSeeking.dRate;
325  hr = IPin_ConnectedTo(&pin->pin.pin.IPin_iface, &victim);
326  if (hr == S_OK)
327  {
328  hr = IPin_NewSegment(victim, start, This->Parser.sourceSeeking.llStop,
329  This->Parser.sourceSeeking.dRate);
330  if (hr != S_OK)
331  FIXME("NewSegment returns %08x\n", hr);
332  IPin_Release(victim);
333  }
334  LeaveCriticalSection(&This->Parser.filter.csFilter);
335  if (hr != S_OK)
336  return hr;
337  }
338  rtstart = (double)(start - pin->pin.pin.tStart) / pin->pin.pin.dRate;
339  rtstop = (double)(stop - pin->pin.pin.tStart) / pin->pin.pin.dRate;
340  IMediaSample_SetMediaTime(sample, &start, &stop);
341  IMediaSample_SetTime(sample, &rtstart, &rtstop);
342  IMediaSample_SetMediaTime(sample, &start, &stop);
343 
344  hr = BaseOutputPinImpl_Deliver(&pin->pin, sample);
345 
346 /* Uncomment this if you want to debug the time differences between the
347  * different streams, it is useful for that
348  *
349  FIXME("stream %u, hr: %08x, Start: %u.%03u, Stop: %u.%03u\n", streamnumber, hr,
350  (DWORD)(start / 10000000), (DWORD)((start / 10000)%1000),
351  (DWORD)(stop / 10000000), (DWORD)((stop / 10000)%1000));
352 */
353  return hr;
354 }
355 
357 {
358  struct thread_args *args = data;
359  AVISplitterImpl *This = args->This;
360  DWORD streamnumber = args->stream;
361  HRESULT hr = S_OK;
362 
363  do
364  {
365  HRESULT nexthr = S_FALSE;
366  IMediaSample *sample;
367 
368  WaitForSingleObject(This->streams[streamnumber].packet_queued, INFINITE);
369  sample = This->streams[streamnumber].sample;
370  This->streams[streamnumber].sample = NULL;
371  if (!sample)
372  break;
373 
374  nexthr = AVISplitter_next_request(This, streamnumber);
375 
376  hr = AVISplitter_Receive(This, sample, streamnumber);
377  if (hr != S_OK)
378  FIXME("Receiving error: %08x\n", hr);
379 
380  IMediaSample_Release(sample);
381  if (hr == S_OK)
382  hr = nexthr;
383  if (nexthr == S_FALSE)
384  AVISplitter_SendEndOfFile(This, streamnumber);
385  } while (hr == S_OK);
386 
387  if (hr != S_FALSE)
388  FIXME("Thread %u terminated with hr %08x!\n", streamnumber, hr);
389  else
390  TRACE("Thread %u terminated properly\n", streamnumber);
391  return hr;
392 }
393 
394 static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample * pSample, DWORD_PTR cookie)
395 {
396  AVISplitterImpl *This = iface;
397  StreamData *stream = This->streams + cookie;
398  HRESULT hr = S_OK;
399 
400  if (!IMediaSample_GetActualDataLength(pSample))
401  {
402  ERR("Received empty sample\n");
403  return S_OK;
404  }
405 
406  /* Send the sample to whatever thread is appropriate
407  * That thread should also not have a sample queued at the moment
408  */
409  /* Debugging */
410  TRACE("(%p)->(%p size: %u, %lu)\n", This, pSample, IMediaSample_GetActualDataLength(pSample), cookie);
411  assert(cookie < This->Parser.cStreams);
412  assert(!stream->sample);
413  assert(WaitForSingleObject(stream->packet_queued, 0) == WAIT_TIMEOUT);
414 
415  IMediaSample_AddRef(pSample);
416 
417  stream->sample = pSample;
418  SetEvent(stream->packet_queued);
419 
420  return hr;
421 }
422 
424 
425 /* On the first request we have to be sure that (cStreams-1) samples have
426  * already been processed, because otherwise some pins might not ever finish
427  * a Pause state change
428  */
430 {
431  AVISplitterImpl *This = iface;
432  HRESULT hr = S_OK;
433  DWORD x;
434  IMediaSample *sample = NULL;
435  BOOL have_sample = FALSE;
436 
437  TRACE("(%p)->()\n", This);
438 
439  for (x = 0; x < This->Parser.cStreams; ++x)
440  {
441  StreamData *stream = This->streams + x;
442 
443  /* Nothing should be running at this point */
444  assert(!stream->thread);
445 
446  assert(!sample);
447  /* It could be we asked the thread to terminate, and the thread
448  * already terminated before receiving the deathwish */
449  ResetEvent(stream->packet_queued);
450 
451  stream->pos_next = stream->pos;
452  stream->index_next = stream->index;
453 
454  /* This was sent after stopped->paused or stopped->playing, so set seek */
455  stream->seek = TRUE;
456 
457  /* There should be a packet queued from AVISplitter_next_request last time
458  * It needs to be done now because this is the only way to ensure that every
459  * stream will have at least 1 packet processed
460  * If this is done after the threads start it could go all awkward and we
461  * would have no guarantees that it's successful at all
462  */
463 
464  if (have_sample)
465  {
466  DWORD_PTR dwUser = ~0;
467  hr = IAsyncReader_WaitForNext(This->Parser.pInputPin->pReader, 10000, &sample, &dwUser);
468  assert(hr == S_OK);
469  assert(sample);
470 
471  AVISplitter_Sample(iface, sample, dwUser);
472  IMediaSample_Release(sample);
473  }
474 
476  TRACE("-->%08x\n", hr);
477 
478  /* Could be an EOF instead */
479  have_sample = (hr == S_OK);
480  if (hr == S_FALSE)
482 
483  if (FAILED(hr) && hr != VFW_E_NOT_CONNECTED)
484  break;
485  hr = S_OK;
486  }
487 
488  /* FIXME: Don't do this for each pin that sent an EOF */
489  for (x = 0; x < This->Parser.cStreams && SUCCEEDED(hr); ++x)
490  {
491  struct thread_args *args;
492  DWORD tid;
493 
494  if ((This->streams[x].stdindex && This->streams[x].index_next >= This->streams[x].entries) ||
495  (!This->streams[x].stdindex && This->streams[x].index_next))
496  {
497  This->streams[x].thread = NULL;
498  continue;
499  }
500 
501  args = CoTaskMemAlloc(sizeof(*args));
502  args->This = This;
503  args->stream = x;
504  This->streams[x].thread = CreateThread(NULL, 0, AVISplitter_thread_reader, args, 0, &tid);
505  TRACE("Created stream %u thread 0x%08x\n", x, tid);
506  }
507 
508  if (FAILED(hr))
509  ERR("Horsemen of the apocalypse came to bring error 0x%08x\n", hr);
510 
511  return hr;
512 }
513 
515 {
516  AVISplitterImpl *This = iface;
517  DWORD x;
518  ULONG ref;
519 
520  for (x = 0; x < This->Parser.cStreams; ++x)
521  {
522  StreamData *stream = This->streams + x;
523 
524  TRACE("Waiting for %u to terminate\n", x);
525  /* Make the thread return first */
526  SetEvent(stream->packet_queued);
527  assert(WaitForSingleObject(stream->thread, 100000) != WAIT_TIMEOUT);
528  CloseHandle(stream->thread);
529  stream->thread = NULL;
530 
531  if (stream->sample)
532  {
533  ref = IMediaSample_Release(stream->sample);
534  assert(ref == 0);
535  }
536  stream->sample = NULL;
537 
538  ResetEvent(stream->packet_queued);
539  }
540  TRACE("All threads are now terminated\n");
541 
542  return S_OK;
543 }
544 
546 {
547  if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream) && IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_Avi))
548  return S_OK;
549  return S_FALSE;
550 }
551 
553 {
555  DWORD x;
556  int rest;
557 
558  *index = NULL;
559  if (cb < sizeof(AVISTDINDEX))
560  {
561  FIXME("size %u too small\n", cb);
562  return E_INVALIDARG;
563  }
564 
566  if (!pIndex)
567  return E_OUTOFMEMORY;
568 
569  IAsyncReader_SyncRead((impl_PullPin_from_IPin(This->Parser.ppPins[0]))->pReader, qwOffset, cb, (BYTE *)pIndex);
570  rest = cb - sizeof(AVISUPERINDEX) + sizeof(RIFFCHUNK) + sizeof(pIndex->aIndex);
571 
572  TRACE("FOURCC: %s\n", debugstr_an((char *)&pIndex->fcc, 4));
573  TRACE("wLongsPerEntry: %hd\n", pIndex->wLongsPerEntry);
574  TRACE("bIndexSubType: %u\n", pIndex->bIndexSubType);
575  TRACE("bIndexType: %u\n", pIndex->bIndexType);
576  TRACE("nEntriesInUse: %u\n", pIndex->nEntriesInUse);
577  TRACE("dwChunkId: %.4s\n", (char *)&pIndex->dwChunkId);
578  TRACE("qwBaseOffset: %s\n", wine_dbgstr_longlong(pIndex->qwBaseOffset));
579  TRACE("dwReserved_3: %u\n", pIndex->dwReserved_3);
580 
581  if (pIndex->bIndexType != AVI_INDEX_OF_CHUNKS
582  || pIndex->wLongsPerEntry != 2
583  || rest < (pIndex->nEntriesInUse * sizeof(DWORD) * pIndex->wLongsPerEntry)
584  || (pIndex->bIndexSubType != AVI_INDEX_SUB_DEFAULT))
585  {
586  FIXME("Invalid index chunk encountered: %u/%u, %u/%u, %u/%u, %u/%u\n",
587  pIndex->bIndexType, AVI_INDEX_OF_CHUNKS, pIndex->wLongsPerEntry, 2,
588  rest, (DWORD)(pIndex->nEntriesInUse * sizeof(DWORD) * pIndex->wLongsPerEntry),
589  pIndex->bIndexSubType, AVI_INDEX_SUB_DEFAULT);
590  *index = NULL;
591  return E_INVALIDARG;
592  }
593 
594  for (x = 0; x < pIndex->nEntriesInUse; ++x)
595  {
596  BOOL keyframe = !(pIndex->aIndex[x].dwSize >> 31);
597  DWORDLONG offset = pIndex->qwBaseOffset + pIndex->aIndex[x].dwOffset;
598  TRACE("dwOffset: %s\n", wine_dbgstr_longlong(offset));
599  TRACE("dwSize: %u\n", (pIndex->aIndex[x].dwSize & ~(1u << 31)));
600  TRACE("Frame is a keyframe: %s\n", keyframe ? "yes" : "no");
601  }
602 
603  *index = pIndex;
604  return S_OK;
605 }
606 
608 {
609  ULONGLONG mov_pos = BYTES_FROM_MEDIATIME(This->CurrentChunkOffset) - sizeof(DWORD);
610  AVIOLDINDEX *pAviOldIndex = This->oldindex;
611  int relative = -1;
612  DWORD x;
613 
614  for (x = 0; x < pAviOldIndex->cb / sizeof(pAviOldIndex->aIndex[0]); ++x)
615  {
616  DWORD temp, temp2 = 0, offset, chunkid;
617  PullPin *pin = This->Parser.pInputPin;
618 
619  offset = pAviOldIndex->aIndex[x].dwOffset;
620  chunkid = pAviOldIndex->aIndex[x].dwChunkId;
621 
622  TRACE("dwChunkId: %.4s\n", (char *)&chunkid);
623  TRACE("dwFlags: %08x\n", pAviOldIndex->aIndex[x].dwFlags);
624  TRACE("dwOffset (%s): %08x\n", relative ? "relative" : "absolute", offset);
625  TRACE("dwSize: %08x\n", pAviOldIndex->aIndex[x].dwSize);
626 
627  /* Only scan once, or else this will take too long */
628  if (relative == -1)
629  {
630  IAsyncReader_SyncRead(pin->pReader, offset, sizeof(DWORD), (BYTE *)&temp);
631  relative = (chunkid != temp);
632 
633  if (chunkid == mmioFOURCC('7','F','x','x')
634  && ((char *)&temp)[0] == 'i' && ((char *)&temp)[1] == 'x')
635  relative = FALSE;
636 
637  if (relative)
638  {
639  if (offset + mov_pos < BYTES_FROM_MEDIATIME(This->EndOfFile))
640  IAsyncReader_SyncRead(pin->pReader, offset + mov_pos, sizeof(DWORD), (BYTE *)&temp2);
641 
642  if (chunkid == mmioFOURCC('7','F','x','x')
643  && ((char *)&temp2)[0] == 'i' && ((char *)&temp2)[1] == 'x')
644  {
645  /* Do nothing, all is great */
646  }
647  else if (temp2 != chunkid)
648  {
649  ERR("Faulty index or bug in handling: Wanted FCC: %s, Abs FCC: %s (@ %x), Rel FCC: %s (@ %s)\n",
650  debugstr_an((char *)&chunkid, 4), debugstr_an((char *)&temp, 4), offset,
651  debugstr_an((char *)&temp2, 4), wine_dbgstr_longlong(mov_pos + offset));
652  relative = -1;
653  }
654  else
655  TRACE("Scanned dwChunkId: %s\n", debugstr_an((char *)&temp2, 4));
656  }
657  else if (!relative)
658  TRACE("Scanned dwChunkId: %s\n", debugstr_an((char *)&temp, 4));
659  }
660  /* Only dump one packet */
661  else break;
662  }
663 
664  if (relative == -1)
665  {
666  FIXME("Dropping index: no idea whether it is relative or absolute\n");
667  CoTaskMemFree(This->oldindex);
668  This->oldindex = NULL;
669  }
670  else if (!relative)
671  This->offset = 0;
672  else
673  This->offset = (DWORD)mov_pos;
674 
675  return S_OK;
676 }
677 
679 {
680  PIN_INFO piOutput;
681  const RIFFCHUNK * pChunk;
682  HRESULT hr;
683  AM_MEDIA_TYPE amt;
684  float fSamplesPerSec = 0.0f;
685  DWORD dwSampleSize = 0;
686  DWORD dwLength = 0;
687  DWORD nstdindex = 0;
688  static const WCHAR wszStreamTemplate[] = {'S','t','r','e','a','m',' ','%','0','2','d',0};
690 
691  ZeroMemory(&amt, sizeof(amt));
692  piOutput.dir = PINDIR_OUTPUT;
693  piOutput.pFilter = &This->Parser.filter.IBaseFilter_iface;
694  wsprintfW(piOutput.achName, wszStreamTemplate, This->Parser.cStreams);
695  This->streams = CoTaskMemRealloc(This->streams, sizeof(StreamData) * (This->Parser.cStreams+1));
696  stream = This->streams + This->Parser.cStreams;
697  ZeroMemory(stream, sizeof(*stream));
698 
699  for (pChunk = (const RIFFCHUNK *)pData;
700  ((const BYTE *)pChunk >= pData) && ((const BYTE *)pChunk + sizeof(RIFFCHUNK) < pData + cb) && (pChunk->cb > 0);
701  pChunk = (const RIFFCHUNK *)((const BYTE*)pChunk + sizeof(RIFFCHUNK) + pChunk->cb)
702  )
703  {
704  switch (pChunk->fcc)
705  {
706  case ckidSTREAMHEADER:
707  {
708  const AVISTREAMHEADER * pStrHdr = (const AVISTREAMHEADER *)pChunk;
709  TRACE("processing stream header\n");
710  stream->streamheader = *pStrHdr;
711 
712  fSamplesPerSec = (float)pStrHdr->dwRate / (float)pStrHdr->dwScale;
713  CoTaskMemFree(amt.pbFormat);
714  amt.pbFormat = NULL;
715  amt.cbFormat = 0;
716 
717  switch (pStrHdr->fccType)
718  {
719  case streamtypeVIDEO:
720  amt.formattype = FORMAT_VideoInfo;
721  break;
722  case streamtypeAUDIO:
723  amt.formattype = FORMAT_WaveFormatEx;
724  break;
725  default:
726  FIXME("fccType %.4s not handled yet\n", (const char *)&pStrHdr->fccType);
727  amt.formattype = FORMAT_None;
728  }
729  amt.majortype = MEDIATYPE_Video;
730  amt.majortype.Data1 = pStrHdr->fccType;
731  amt.subtype = MEDIATYPE_Video;
732  amt.subtype.Data1 = pStrHdr->fccHandler;
733  TRACE("Subtype FCC: %.04s\n", (LPCSTR)&pStrHdr->fccHandler);
734  amt.lSampleSize = pStrHdr->dwSampleSize;
735  amt.bFixedSizeSamples = (amt.lSampleSize != 0);
736 
737  /* FIXME: Is this right? */
738  if (!amt.lSampleSize)
739  {
740  amt.lSampleSize = 1;
741  dwSampleSize = 1;
742  }
743 
744  amt.bTemporalCompression = IsEqualGUID(&amt.majortype, &MEDIATYPE_Video); /* FIXME? */
745  dwSampleSize = pStrHdr->dwSampleSize;
746  dwLength = pStrHdr->dwLength;
747  if (!dwLength)
748  dwLength = This->AviHeader.dwTotalFrames;
749 
750  if (pStrHdr->dwSuggestedBufferSize && pStrHdr->dwSuggestedBufferSize > props->cbBuffer)
751  props->cbBuffer = pStrHdr->dwSuggestedBufferSize;
752 
753  break;
754  }
755  case ckidSTREAMFORMAT:
756  TRACE("processing stream format data\n");
757  if (IsEqualIID(&amt.formattype, &FORMAT_VideoInfo))
758  {
759  VIDEOINFOHEADER * pvi;
760  /* biCompression member appears to override the value in the stream header.
761  * i.e. the stream header can say something completely contradictory to what
762  * is in the BITMAPINFOHEADER! */
763  if (pChunk->cb < sizeof(BITMAPINFOHEADER))
764  {
765  ERR("Not enough bytes for BITMAPINFOHEADER\n");
766  return E_FAIL;
767  }
768  amt.cbFormat = sizeof(VIDEOINFOHEADER) - sizeof(BITMAPINFOHEADER) + pChunk->cb;
769  amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
770  ZeroMemory(amt.pbFormat, amt.cbFormat);
771  pvi = (VIDEOINFOHEADER *)amt.pbFormat;
772  pvi->AvgTimePerFrame = (LONGLONG)(10000000.0 / fSamplesPerSec);
773 
774  CopyMemory(&pvi->bmiHeader, pChunk + 1, pChunk->cb);
775  if (pvi->bmiHeader.biCompression)
776  amt.subtype.Data1 = pvi->bmiHeader.biCompression;
777  }
778  else if (IsEqualIID(&amt.formattype, &FORMAT_WaveFormatEx))
779  {
780  amt.cbFormat = pChunk->cb;
781  if (amt.cbFormat < sizeof(WAVEFORMATEX))
782  amt.cbFormat = sizeof(WAVEFORMATEX);
783  amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
784  ZeroMemory(amt.pbFormat, amt.cbFormat);
785  CopyMemory(amt.pbFormat, pChunk + 1, pChunk->cb);
786  }
787  else
788  {
789  amt.cbFormat = pChunk->cb;
790  amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
791  CopyMemory(amt.pbFormat, pChunk + 1, amt.cbFormat);
792  }
793  break;
794  case ckidSTREAMNAME:
795  TRACE("processing stream name\n");
796  /* FIXME: this doesn't exactly match native version (we omit the "##)" prefix), but hey... */
797  MultiByteToWideChar(CP_ACP, 0, (LPCSTR)(pChunk + 1), pChunk->cb, piOutput.achName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
798  break;
800  FIXME("process stream handler data\n");
801  break;
802  case ckidAVIPADDING:
803  TRACE("JUNK chunk ignored\n");
804  break;
805  case ckidAVISUPERINDEX:
806  {
807  const AVISUPERINDEX *pIndex = (const AVISUPERINDEX *)pChunk;
808  DWORD x;
809  UINT rest = pIndex->cb - sizeof(AVISUPERINDEX) + sizeof(RIFFCHUNK) + sizeof(pIndex->aIndex[0]) * ANYSIZE_ARRAY;
810 
811  if (pIndex->cb < sizeof(AVISUPERINDEX) - sizeof(RIFFCHUNK))
812  {
813  FIXME("size %u\n", pIndex->cb);
814  break;
815  }
816 
817  if (nstdindex++ > 0)
818  {
819  ERR("Stream %d got more than 1 superindex?\n", This->Parser.cStreams);
820  break;
821  }
822 
823  TRACE("wLongsPerEntry: %hd\n", pIndex->wLongsPerEntry);
824  TRACE("bIndexSubType: %u\n", pIndex->bIndexSubType);
825  TRACE("bIndexType: %u\n", pIndex->bIndexType);
826  TRACE("nEntriesInUse: %u\n", pIndex->nEntriesInUse);
827  TRACE("dwChunkId: %.4s\n", (const char *)&pIndex->dwChunkId);
828  if (pIndex->dwReserved[0])
829  TRACE("dwReserved[0]: %u\n", pIndex->dwReserved[0]);
830  if (pIndex->dwReserved[1])
831  TRACE("dwReserved[1]: %u\n", pIndex->dwReserved[1]);
832  if (pIndex->dwReserved[2])
833  TRACE("dwReserved[2]: %u\n", pIndex->dwReserved[2]);
834 
835  if (pIndex->bIndexType != AVI_INDEX_OF_INDEXES
836  || pIndex->wLongsPerEntry != 4
837  || rest < (pIndex->nEntriesInUse * sizeof(DWORD) * pIndex->wLongsPerEntry)
838  || (pIndex->bIndexSubType != AVI_INDEX_SUB_2FIELD && pIndex->bIndexSubType != AVI_INDEX_SUB_DEFAULT))
839  {
840  FIXME("Invalid index chunk encountered\n");
841  break;
842  }
843 
844  stream->entries = pIndex->nEntriesInUse;
845  stream->stdindex = CoTaskMemRealloc(stream->stdindex, sizeof(*stream->stdindex) * stream->entries);
846  for (x = 0; x < pIndex->nEntriesInUse; ++x)
847  {
848  TRACE("qwOffset: %s\n", wine_dbgstr_longlong(pIndex->aIndex[x].qwOffset));
849  TRACE("dwSize: %u\n", pIndex->aIndex[x].dwSize);
850  TRACE("dwDuration: %u (unreliable)\n", pIndex->aIndex[x].dwDuration);
851 
852  AVISplitter_ProcessIndex(This, &stream->stdindex[x], pIndex->aIndex[x].qwOffset, pIndex->aIndex[x].dwSize);
853  }
854  break;
855  }
856  default:
857  FIXME("unknown chunk type \"%.04s\" ignored\n", (LPCSTR)&pChunk->fcc);
858  }
859  }
860 
861  if (IsEqualGUID(&amt.formattype, &FORMAT_WaveFormatEx))
862  {
863  amt.subtype = MEDIATYPE_Video;
864  amt.subtype.Data1 = ((WAVEFORMATEX *)amt.pbFormat)->wFormatTag;
865  }
866 
867  dump_AM_MEDIA_TYPE(&amt);
868  TRACE("fSamplesPerSec = %f\n", (double)fSamplesPerSec);
869  TRACE("dwSampleSize = %x\n", dwSampleSize);
870  TRACE("dwLength = %x\n", dwLength);
871 
872  stream->fSamplesPerSec = fSamplesPerSec;
873  stream->dwSampleSize = dwSampleSize;
874  stream->dwLength = dwLength; /* TODO: Use this for mediaseeking */
875  stream->packet_queued = CreateEventW(NULL, 0, 0, NULL);
876 
877  hr = Parser_AddPin(&(This->Parser), &piOutput, props, &amt);
878  CoTaskMemFree(amt.pbFormat);
879 
880 
881  return hr;
882 }
883 
885 {
886  const RIFFCHUNK * pChunk;
887 
888  for (pChunk = (const RIFFCHUNK *)pData;
889  ((const BYTE *)pChunk >= pData) && ((const BYTE *)pChunk + sizeof(RIFFCHUNK) < pData + cb) && (pChunk->cb > 0);
890  pChunk = (const RIFFCHUNK *)((const BYTE*)pChunk + sizeof(RIFFCHUNK) + pChunk->cb)
891  )
892  {
893  switch (pChunk->fcc)
894  {
895  case ckidAVIEXTHEADER:
896  {
897  int x;
898  const AVIEXTHEADER * pExtHdr = (const AVIEXTHEADER *)pChunk;
899 
900  TRACE("processing extension header\n");
901  if (pExtHdr->cb != sizeof(AVIEXTHEADER) - sizeof(RIFFCHUNK))
902  {
903  FIXME("Size: %u\n", pExtHdr->cb);
904  break;
905  }
906  TRACE("dwGrandFrames: %u\n", pExtHdr->dwGrandFrames);
907  for (x = 0; x < 61; ++x)
908  if (pExtHdr->dwFuture[x])
909  FIXME("dwFuture[%i] = %u (0x%08x)\n", x, pExtHdr->dwFuture[x], pExtHdr->dwFuture[x]);
910  This->ExtHeader = *pExtHdr;
911  break;
912  }
913  default:
914  FIXME("unknown chunk type \"%.04s\" ignored\n", (LPCSTR)&pChunk->fcc);
915  }
916  }
917 
918  return S_OK;
919 }
920 
922 {
923  unsigned int x;
924 
925  if (This->oldindex)
926  {
927  DWORD nMax, n;
928 
929  for (x = 0; x < This->Parser.cStreams; ++x)
930  {
931  This->streams[x].frames = 0;
932  This->streams[x].pos = ~0;
933  This->streams[x].index = 0;
934  }
935 
936  nMax = This->oldindex->cb / sizeof(This->oldindex->aIndex[0]);
937 
938  /* Ok, maybe this is more of an exercise to see if I interpret everything correctly or not, but that is useful for now. */
939  for (n = 0; n < nMax; ++n)
940  {
941  DWORD streamId = StreamFromFOURCC(This->oldindex->aIndex[n].dwChunkId);
942  if (streamId >= This->Parser.cStreams)
943  {
944  FIXME("Stream id %s ignored\n", debugstr_an((char*)&This->oldindex->aIndex[n].dwChunkId, 4));
945  continue;
946  }
947  if (This->streams[streamId].pos == ~0U)
948  This->streams[streamId].pos = n;
949 
950  if (This->streams[streamId].streamheader.dwSampleSize)
951  This->streams[streamId].frames += This->oldindex->aIndex[n].dwSize / This->streams[streamId].streamheader.dwSampleSize;
952  else
953  ++This->streams[streamId].frames;
954  }
955 
956  for (x = 0; x < This->Parser.cStreams; ++x)
957  {
958  if ((DWORD)This->streams[x].frames != This->streams[x].streamheader.dwLength)
959  {
960  FIXME("stream %u: frames found: %u, frames meant to be found: %u\n", x, (DWORD)This->streams[x].frames, This->streams[x].streamheader.dwLength);
961  }
962  }
963 
964  }
965  else if (!This->streams[0].entries)
966  {
967  for (x = 0; x < This->Parser.cStreams; ++x)
968  {
969  This->streams[x].frames = This->streams[x].streamheader.dwLength;
970  }
971  /* MS Avi splitter does seek through the whole file, we should! */
972  ERR("We should be manually seeking through the entire file to build an index, because the index is missing!!!\n");
973  return E_NOTIMPL;
974  }
975 
976  /* Not much here yet */
977  for (x = 0; x < This->Parser.cStreams; ++x)
978  {
979  StreamData *stream = This->streams + x;
980  DWORD y;
981  DWORD64 frames = 0;
982 
983  stream->seek = TRUE;
984 
985  if (stream->stdindex)
986  {
987  stream->index = 0;
988  stream->pos = 0;
989  for (y = 0; y < stream->entries; ++y)
990  {
991  if (stream->streamheader.dwSampleSize)
992  {
993  DWORD z;
994 
995  for (z = 0; z < stream->stdindex[y]->nEntriesInUse; ++z)
996  {
997  UINT len = stream->stdindex[y]->aIndex[z].dwSize & ~(1u << 31);
998  frames += len / stream->streamheader.dwSampleSize + !!(len % stream->streamheader.dwSampleSize);
999  }
1000  }
1001  else
1002  frames += stream->stdindex[y]->nEntriesInUse;
1003  }
1004  }
1005  else frames = stream->frames;
1006 
1007  frames *= stream->streamheader.dwScale;
1008  /* Keep accuracy as high as possible for duration */
1009  This->Parser.sourceSeeking.llDuration = frames * 10000000;
1010  This->Parser.sourceSeeking.llDuration /= stream->streamheader.dwRate;
1011  This->Parser.sourceSeeking.llStop = This->Parser.sourceSeeking.llDuration;
1012  This->Parser.sourceSeeking.llCurrent = 0;
1013 
1014  frames /= stream->streamheader.dwRate;
1015 
1016  TRACE("Duration: %d days, %d hours, %d minutes and %d.%03u seconds\n", (DWORD)(frames / 86400),
1017  (DWORD)((frames % 86400) / 3600), (DWORD)((frames % 3600) / 60), (DWORD)(frames % 60),
1018  (DWORD)(This->Parser.sourceSeeking.llDuration/10000) % 1000);
1019  }
1020 
1021  return S_OK;
1022 }
1023 
1024 static HRESULT AVISplitter_Disconnect(LPVOID iface);
1025 
1026 /* FIXME: fix leaks on failure here */
1028 {
1030  HRESULT hr;
1031  RIFFLIST list;
1032  LONGLONG pos = 0; /* in bytes */
1033  BYTE * pBuffer;
1034  RIFFCHUNK * pCurrentChunk;
1035  LONGLONG total, avail;
1036  ULONG x;
1037  DWORD indexes;
1038 
1039  AVISplitterImpl * pAviSplit = (AVISplitterImpl *)This->pin.pinInfo.pFilter;
1040 
1041  hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(list), (BYTE *)&list);
1042  pos += sizeof(list);
1043 
1044  if (list.fcc != FOURCC_RIFF)
1045  {
1046  ERR("Input stream not a RIFF file\n");
1047  return E_FAIL;
1048  }
1049  if (list.fccListType != formtypeAVI)
1050  {
1051  ERR("Input stream not an AVI RIFF file\n");
1052  return E_FAIL;
1053  }
1054 
1055  hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(list), (BYTE *)&list);
1056  if (list.fcc != FOURCC_LIST)
1057  {
1058  ERR("Expected LIST chunk, but got %.04s\n", (LPSTR)&list.fcc);
1059  return E_FAIL;
1060  }
1061  if (list.fccListType != listtypeAVIHEADER)
1062  {
1063  ERR("Header list expected. Got: %.04s\n", (LPSTR)&list.fccListType);
1064  return E_FAIL;
1065  }
1066 
1067  pBuffer = HeapAlloc(GetProcessHeap(), 0, list.cb - sizeof(RIFFLIST) + sizeof(RIFFCHUNK));
1068  hr = IAsyncReader_SyncRead(This->pReader, pos + sizeof(list), list.cb - sizeof(RIFFLIST) + sizeof(RIFFCHUNK), pBuffer);
1069 
1070  pAviSplit->AviHeader.cb = 0;
1071 
1072  /* Stream list will set the buffer size here, so set a default and allow an override */
1073  props->cbBuffer = 0x20000;
1074 
1075  for (pCurrentChunk = (RIFFCHUNK *)pBuffer; (BYTE *)pCurrentChunk + sizeof(*pCurrentChunk) < pBuffer + list.cb; pCurrentChunk = (RIFFCHUNK *)(((BYTE *)pCurrentChunk) + sizeof(*pCurrentChunk) + pCurrentChunk->cb))
1076  {
1077  RIFFLIST * pList;
1078 
1079  switch (pCurrentChunk->fcc)
1080  {
1081  case ckidMAINAVIHEADER:
1082  /* AVIMAINHEADER includes the structure that is pCurrentChunk at the moment */
1083  memcpy(&pAviSplit->AviHeader, pCurrentChunk, sizeof(pAviSplit->AviHeader));
1084  break;
1085  case FOURCC_LIST:
1086  pList = (RIFFLIST *)pCurrentChunk;
1087  switch (pList->fccListType)
1088  {
1089  case ckidSTREAMLIST:
1090  hr = AVISplitter_ProcessStreamList(pAviSplit, (BYTE *)pCurrentChunk + sizeof(RIFFLIST), pCurrentChunk->cb + sizeof(RIFFCHUNK) - sizeof(RIFFLIST), props);
1091  break;
1092  case ckidODML:
1093  hr = AVISplitter_ProcessODML(pAviSplit, (BYTE *)pCurrentChunk + sizeof(RIFFLIST), pCurrentChunk->cb + sizeof(RIFFCHUNK) - sizeof(RIFFLIST));
1094  break;
1095  }
1096  break;
1097  case ckidAVIPADDING:
1098  /* ignore */
1099  break;
1100  default:
1101  FIXME("unrecognised header list type: %.04s\n", (LPSTR)&pCurrentChunk->fcc);
1102  }
1103  }
1105 
1106  if (pAviSplit->AviHeader.cb != sizeof(pAviSplit->AviHeader) - sizeof(RIFFCHUNK))
1107  {
1108  ERR("Avi Header wrong size!\n");
1109  return E_FAIL;
1110  }
1111 
1112  /* Skip any chunks until we find the LIST chunk */
1113  do
1114  {
1115  pos += sizeof(RIFFCHUNK) + list.cb;
1116  hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(list), (BYTE *)&list);
1117  }
1118  while (hr == S_OK && (list.fcc != FOURCC_LIST || list.fccListType != listtypeAVIMOVIE));
1119 
1120  if (hr != S_OK)
1121  {
1122  ERR("Failed to find LIST chunk from AVI file\n");
1123  return E_FAIL;
1124  }
1125 
1126  IAsyncReader_Length(This->pReader, &total, &avail);
1127 
1128  /* FIXME: AVIX files are extended beyond the FOURCC chunk "AVI ", and thus won't be played here,
1129  * once I get one of the files I'll try to fix it */
1130  This->rtStart = pAviSplit->CurrentChunkOffset = MEDIATIME_FROM_BYTES(pos + sizeof(RIFFLIST));
1131  pos += list.cb + sizeof(RIFFCHUNK);
1132 
1133  pAviSplit->EndOfFile = This->rtStop = MEDIATIME_FROM_BYTES(pos);
1134  if (pos > total)
1135  {
1136  ERR("File smaller (%s) then EndOfFile (%s)\n", wine_dbgstr_longlong(total), wine_dbgstr_longlong(pAviSplit->EndOfFile));
1137  return E_FAIL;
1138  }
1139 
1140  hr = IAsyncReader_SyncRead(This->pReader, BYTES_FROM_MEDIATIME(pAviSplit->CurrentChunkOffset), sizeof(pAviSplit->CurrentChunk), (BYTE *)&pAviSplit->CurrentChunk);
1141 
1142  props->cbAlign = 1;
1143  props->cbPrefix = 0;
1144  /* Comrades, prevent shortage of buffers, or you will feel the consequences! DA! */
1145  props->cBuffers = 2 * pAviSplit->Parser.cStreams;
1146 
1147  /* Now peek into the idx1 index, if available */
1148  if (hr == S_OK && (total - pos) > sizeof(RIFFCHUNK))
1149  {
1150  memset(&list, 0, sizeof(list));
1151 
1152  hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(list), (BYTE *)&list);
1153  if (list.fcc == ckidAVIOLDINDEX)
1154  {
1155  pAviSplit->oldindex = CoTaskMemRealloc(pAviSplit->oldindex, list.cb + sizeof(RIFFCHUNK));
1156  if (pAviSplit->oldindex)
1157  {
1158  hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(RIFFCHUNK) + list.cb, (BYTE *)pAviSplit->oldindex);
1159  if (hr == S_OK)
1160  {
1161  hr = AVISplitter_ProcessOldIndex(pAviSplit);
1162  }
1163  else
1164  {
1165  CoTaskMemFree(pAviSplit->oldindex);
1166  pAviSplit->oldindex = NULL;
1167  hr = S_OK;
1168  }
1169  }
1170  }
1171  }
1172 
1173  indexes = 0;
1174  for (x = 0; x < pAviSplit->Parser.cStreams; ++x)
1175  if (pAviSplit->streams[x].entries)
1176  ++indexes;
1177 
1178  if (indexes)
1179  {
1180  CoTaskMemFree(pAviSplit->oldindex);
1181  pAviSplit->oldindex = NULL;
1182  if (indexes < pAviSplit->Parser.cStreams)
1183  {
1184  /* This error could possible be survived by switching to old type index,
1185  * but I would rather find out why it doesn't find everything here
1186  */
1187  ERR("%d indexes expected, but only have %d\n", indexes, pAviSplit->Parser.cStreams);
1188  indexes = 0;
1189  }
1190  }
1191  else if (pAviSplit->oldindex)
1192  indexes = pAviSplit->Parser.cStreams;
1193 
1194  if (!indexes && pAviSplit->AviHeader.dwFlags & AVIF_MUSTUSEINDEX)
1195  {
1196  FIXME("No usable index was found!\n");
1197  hr = E_FAIL;
1198  }
1199 
1200  /* Now, set up the streams */
1201  if (hr == S_OK)
1202  hr = AVISplitter_InitializeStreams(pAviSplit);
1203 
1204  if (hr != S_OK)
1205  {
1206  AVISplitter_Disconnect(pAviSplit);
1207  return E_FAIL;
1208  }
1209 
1210  TRACE("AVI File ok\n");
1211 
1212  return hr;
1213 }
1214 
1216 {
1217  AVISplitterImpl *This = iface;
1218  DWORD x;
1219  ULONG ref;
1220 
1221  TRACE("(%p)->()\n", This);
1222 
1223  for (x = 0; x < This->Parser.cStreams; ++x)
1224  {
1225  StreamData *stream = This->streams + x;
1226 
1227  if (stream->sample)
1228  {
1229  ref = IMediaSample_Release(stream->sample);
1230  assert(ref == 0);
1231  }
1232  stream->sample = NULL;
1233 
1234  ResetEvent(stream->packet_queued);
1235  assert(!stream->thread);
1236  }
1237 
1238  return S_OK;
1239 }
1240 
1242 {
1243  AVISplitterImpl *This = iface;
1244  ULONG x;
1245 
1246  /* TODO: Remove other memory that's allocated during connect */
1247  CoTaskMemFree(This->oldindex);
1248  This->oldindex = NULL;
1249 
1250  for (x = 0; x < This->Parser.cStreams; ++x)
1251  {
1252  DWORD i;
1253 
1254  StreamData *stream = &This->streams[x];
1255 
1256  for (i = 0; i < stream->entries; ++i)
1257  CoTaskMemFree(stream->stdindex[i]);
1258 
1259  CoTaskMemFree(stream->stdindex);
1260  CloseHandle(stream->packet_queued);
1261  }
1262  CoTaskMemFree(This->streams);
1263  This->streams = NULL;
1264  return S_OK;
1265 }
1266 
1268 {
1269  AVISplitterImpl *This = (AVISplitterImpl *)iface;
1270  ULONG ref;
1271 
1272  ref = InterlockedDecrement(&This->Parser.filter.refCount);
1273 
1274  TRACE("(%p)->() Release from %d\n", This, ref + 1);
1275 
1276  if (!ref)
1277  {
1279  Parser_Destroy(&This->Parser);
1280  }
1281 
1282  return ref;
1283 }
1284 
1286 {
1288  PullPin *pPin = This->Parser.pInputPin;
1289  LONGLONG newpos, endpos;
1290  DWORD x;
1291 
1292  newpos = This->Parser.sourceSeeking.llCurrent;
1293  endpos = This->Parser.sourceSeeking.llDuration;
1294 
1295  if (newpos > endpos)
1296  {
1297  WARN("Requesting position %x%08x beyond end of stream %x%08x\n", (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(endpos>>32), (DWORD)endpos);
1298  return E_INVALIDARG;
1299  }
1300 
1301  FIXME("Moving position to %u.%03u s!\n", (DWORD)(newpos / 10000000), (DWORD)((newpos / 10000)%1000));
1302 
1304  /* Send a flush to all output pins */
1305  IPin_BeginFlush(&pPin->pin.IPin_iface);
1306 
1307  /* Make sure this is done while stopped, BeginFlush takes care of this */
1308  EnterCriticalSection(&This->Parser.filter.csFilter);
1309  for (x = 0; x < This->Parser.cStreams; ++x)
1310  {
1312  StreamData *stream = This->streams + x;
1313  LONGLONG wanted_frames;
1314  DWORD last_keyframe = 0, last_keyframeidx = 0, preroll = 0;
1315 
1316  wanted_frames = newpos;
1317  wanted_frames *= stream->streamheader.dwRate;
1318  wanted_frames /= 10000000;
1319  wanted_frames /= stream->streamheader.dwScale;
1320 
1321  pin->dwSamplesProcessed = 0;
1322  stream->index = 0;
1323  stream->pos = 0;
1324  stream->seek = TRUE;
1325  if (stream->stdindex)
1326  {
1327  DWORD y, z = 0;
1328 
1329  for (y = 0; y < stream->entries; ++y)
1330  {
1331  for (z = 0; z < stream->stdindex[y]->nEntriesInUse; ++z)
1332  {
1333  if (stream->streamheader.dwSampleSize)
1334  {
1335  ULONG len = stream->stdindex[y]->aIndex[z].dwSize & ~(1u << 31);
1336  ULONG size = stream->streamheader.dwSampleSize;
1337 
1338  pin->dwSamplesProcessed += len / size;
1339  if (len % size)
1340  ++pin->dwSamplesProcessed;
1341  }
1342  else ++pin->dwSamplesProcessed;
1343 
1344  if (!(stream->stdindex[y]->aIndex[z].dwSize >> 31))
1345  {
1346  last_keyframe = z;
1347  last_keyframeidx = y;
1348  preroll = 0;
1349  }
1350  else
1351  ++preroll;
1352 
1353  if (pin->dwSamplesProcessed >= wanted_frames)
1354  break;
1355  }
1356  if (pin->dwSamplesProcessed >= wanted_frames)
1357  break;
1358  }
1359  stream->index = last_keyframeidx;
1360  stream->pos = last_keyframe;
1361  }
1362  else
1363  {
1364  DWORD nMax, n;
1365  nMax = This->oldindex->cb / sizeof(This->oldindex->aIndex[0]);
1366 
1367  for (n = 0; n < nMax; ++n)
1368  {
1369  DWORD streamId = StreamFromFOURCC(This->oldindex->aIndex[n].dwChunkId);
1370  if (streamId != x)
1371  continue;
1372 
1373  if (stream->streamheader.dwSampleSize)
1374  {
1375  ULONG len = This->oldindex->aIndex[n].dwSize;
1376  ULONG size = stream->streamheader.dwSampleSize;
1377 
1378  pin->dwSamplesProcessed += len / size;
1379  if (len % size)
1380  ++pin->dwSamplesProcessed;
1381  }
1382  else ++pin->dwSamplesProcessed;
1383 
1384  if (This->oldindex->aIndex[n].dwFlags & AVIIF_KEYFRAME)
1385  {
1386  last_keyframe = n;
1387  preroll = 0;
1388  }
1389  else
1390  ++preroll;
1391 
1392  if (pin->dwSamplesProcessed >= wanted_frames)
1393  break;
1394  }
1395  assert(n < nMax);
1396  stream->pos = last_keyframe;
1397  stream->index = 0;
1398  }
1399  stream->preroll = preroll;
1400  stream->seek = TRUE;
1401  }
1402  LeaveCriticalSection(&This->Parser.filter.csFilter);
1403 
1404  TRACE("Done flushing\n");
1405  IPin_EndFlush(&pPin->pin.IPin_iface);
1407 
1408  return S_OK;
1409 }
1410 
1411 static const IBaseFilterVtbl AVISplitterImpl_Vtbl =
1412 {
1414  Parser_AddRef,
1417  Parser_Stop,
1418  Parser_Pause,
1419  Parser_Run,
1428 };
1429 
1431 {
1432  HRESULT hr;
1434 
1435  TRACE("(%p, %p)\n", pUnkOuter, ppv);
1436 
1437  *ppv = NULL;
1438 
1439  if (pUnkOuter)
1440  return CLASS_E_NOAGGREGATION;
1441 
1442  /* Note: This memory is managed by the transform filter once created */
1443  This = CoTaskMemAlloc(sizeof(AVISplitterImpl));
1444 
1445  This->streams = NULL;
1446  This->oldindex = NULL;
1447 
1449 
1450  if (FAILED(hr))
1451  return hr;
1452 
1453  *ppv = &This->Parser.filter.IBaseFilter_iface;
1454 
1455  return hr;
1456 }
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
HRESULT AVISplitter_create(IUnknown *pUnkOuter, LPVOID *ppv)
Definition: avisplit.c:1430
#define ckidMAINAVIHEADER
Definition: aviriff.h:53
#define AVIIF_LIST
Definition: aviriff.h:130
ULONG cStreams
Definition: parser.h:40
HANDLE thread
Definition: avisplit.c:76
DWORD cb
Definition: aviriff.h:57
void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *pmt)
Definition: enummedia.c:27
#define TRUE
Definition: types.h:120
static HRESULT AVISplitter_next_request(AVISplitterImpl *This, DWORD streamnumber)
Definition: avisplit.c:148
StreamData * streams
Definition: avisplit.c:95
#define CloseHandle
Definition: compat.h:398
Definition: aviriff.h:214
BOOL seek
Definition: avisplit.c:67
#define ckidSTREAMFORMAT
Definition: aviriff.h:125
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:422
HRESULT hr
Definition: shlfolder.c:183
static DWORD WINAPI AVISplitter_thread_reader(LPVOID data)
Definition: avisplit.c:356
#define ANYSIZE_ARRAY
Definition: typedefs.h:45
#define ckidAVIPADDING
Definition: vfw.h:916
#define ckidSTREAMLIST
Definition: aviriff.h:81
HRESULT WINAPI Parser_Pause(IBaseFilter *iface)
Definition: parser.c:279
HRESULT WINAPI Parser_QueryInterface(IBaseFilter *iface, REFIID riid, LPVOID *ppv)
Definition: parser.c:142
#define listtypeAVIHEADER
Definition: vfw.h:890
#define CP_ACP
Definition: compat.h:99
IPin IPin_iface
Definition: strmbase.h:35
#define AVI_INDEX_OF_INDEXES
Definition: aviriff.h:172
#define WARN(fmt,...)
Definition: debug.h:111
#define U(x)
Definition: wordpad.c:44
#define AVI_INDEX_SUB_DEFAULT
Definition: aviriff.h:178
DWORD offset
Definition: avisplit.c:93
GLintptr offset
Definition: glext.h:5920
static HRESULT AVISplitter_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE *pmt)
Definition: avisplit.c:545
REFIID LPVOID * ppv
Definition: atlbase.h:39
GLdouble n
Definition: glext.h:7729
#define AVIF_MUSTUSEINDEX
Definition: aviriff.h:47
#define AVIIF_KEYFRAME
Definition: aviriff.h:131
struct AVISplitterImpl AVISplitterImpl
#define assert(x)
Definition: debug.h:53
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:679
#define ZeroMemory
Definition: winbase.h:1635
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
HRESULT WINAPI Parser_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
Definition: parser.c:313
AVIOLDINDEX * oldindex
Definition: avisplit.c:92
#define ckidSTREAMHEADER
Definition: aviriff.h:88
struct tWAVEFORMATEX WAVEFORMATEX
Definition: austream.idl:23
HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *pGraph, LPCWSTR pName)
Definition: parser.c:424
DWORD dwSuggestedBufferSize
Definition: aviriff.h:112
DWORD index_next
Definition: avisplit.c:70
AVISplitterImpl * This
Definition: avisplit.c:99
#define AVI_INDEX_OF_CHUNKS
Definition: aviriff.h:173
DWORD dwFlags
Definition: aviriff.h:61
FLOAT fSamplesPerSec
Definition: avisplit.c:60
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
char * LPSTR
Definition: xmlstorage.h:182
static HRESULT WINAPI AVISplitter_seek(IMediaSeeking *iface)
Definition: avisplit.c:1285
#define E_FAIL
Definition: ddrawi.h:102
Definition: match.c:390
static PullPin * impl_PullPin_from_IPin(IPin *iface)
Definition: pin.h:132
#define DWORD
Definition: nt_native.h:44
static HRESULT AVISplitter_ProcessODML(AVISplitterImpl *This, const BYTE *pData, DWORD cb)
Definition: avisplit.c:884
HRESULT WINAPI Parser_GetSyncSource(IBaseFilter *iface, IReferenceClock **ppClock)
Definition: parser.c:397
Definition: send.c:47
static int avail
Definition: adh-main.c:39
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:597
struct _avioldindex::_avioldindex_entry aIndex[ANYSIZE_ARRAY]
Definition: regsvr.c:103
static HRESULT AVISplitter_InputPin_PreConnect(IPin *iface, IPin *pConnectPin, ALLOCATOR_PROPERTIES *props)
Definition: avisplit.c:1027
FOURCC fcc
Definition: aviriff.h:27
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
Definition: pin.h:70
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
unsigned int BOOL
Definition: ntddk_ex.h:94
LONGLONG EndOfFile
Definition: avisplit.c:88
GLenum GLint ref
Definition: glext.h:6028
#define FIXME(fmt,...)
Definition: debug.h:110
#define ckidODML
Definition: aviriff.h:71
HRESULT WINAPI Parser_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin)
Definition: parser.c:409
DWORD biCompression
Definition: amvideo.idl:35
#define S_FALSE
Definition: winerror.h:2357
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
static HRESULT AVISplitter_SendEndOfFile(AVISplitterImpl *This, DWORD streamnumber)
Definition: avisplit.c:128
#define E_INVALIDARG
Definition: ddrawi.h:101
GLdouble GLdouble z
Definition: glext.h:5874
REFERENCE_TIME AvgTimePerFrame
Definition: amvideo.idl:187
#define ckidAVIOLDINDEX
Definition: aviriff.h:127
DWORD cb
Definition: aviriff.h:28
static HRESULT AVISplitter_Sample(LPVOID iface, IMediaSample *pSample, DWORD_PTR cookie)
Definition: avisplit.c:394
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:111
static HRESULT AVISplitter_first_request(LPVOID iface)
Definition: avisplit.c:429
smooth NULL
Definition: ftsmooth.c:416
PVOID pBuffer
BITMAPINFOHEADER bmiHeader
Definition: amvideo.idl:189
CRITICAL_SECTION thread_lock
Definition: pin.h:94
GLuint index
Definition: glext.h:6031
const char * LPCSTR
Definition: xmlstorage.h:183
#define VFW_E_NOT_CONNECTED
Definition: vfwmsgs.h:48
static HRESULT AVISplitter_InitializeStreams(AVISplitterImpl *This)
Definition: avisplit.c:921
DWORD cb
Definition: aviriff.h:138
HRESULT WINAPI Parser_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
Definition: parser.c:404
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
FOURCC fccType
Definition: aviriff.h:102
DWORD dwLength
Definition: aviriff.h:111
int64_t LONGLONG
Definition: typedefs.h:66
AVISTREAMHEADER streamheader
Definition: avisplit.c:63
#define TRACE(s)
Definition: solgame.cpp:4
DWORD entries
Definition: avisplit.c:64
GLsizeiptr size
Definition: glext.h:5919
LONGLONG CurrentChunkOffset
Definition: avisplit.c:87
#define GetProcessHeap()
Definition: compat.h:395
#define FOURCC_LIST
Definition: mmsystem.h:565
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define AVIIF_MIDPART
Definition: vfw.h:981
AVIMAINHEADER AviHeader
Definition: avisplit.c:89
#define ckidSTREAMHANDLERDATA
Definition: vfw.h:895
__wchar_t WCHAR
Definition: xmlstorage.h:180
static DWORD DWORD * dwLength
Definition: fusion.c:83
DWORD preroll
Definition: avisplit.c:80
LONG HRESULT
Definition: typedefs.h:77
HANDLE packet_queued
Definition: avisplit.c:76
struct _avisuperindex AVISUPERINDEX
uint64_t ULONGLONG
Definition: typedefs.h:65
IMediaSample * sample
Definition: avisplit.c:77
static HRESULT AVISplitter_Disconnect(LPVOID iface)
Definition: avisplit.c:1241
#define WINAPI
Definition: msvc.h:8
#define CopyMemory
Definition: winbase.h:1633
unsigned long DWORD
Definition: ntddk_ex.h:95
BasePin pin
Definition: pin.h:73
HRESULT WINAPI Parser_Stop(IBaseFilter *iface)
Definition: parser.c:241
static DWORD cb
Definition: integrity.c:41
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
struct _riffchunk RIFFCHUNK
GLbitfield flags
Definition: glext.h:7161
#define WAIT_TIMEOUT
Definition: dderror.h:14
#define BYTES_FROM_MEDIATIME(time)
HRESULT Parser_AddPin(ParserImpl *This, const PIN_INFO *piOutput, ALLOCATOR_PROPERTIES *props, const AM_MEDIA_TYPE *amt)
Definition: parser.c:446
DWORD pos
Definition: avisplit.c:70
FOURCC fccListType
Definition: aviriff.h:35
FOURCC fccHandler
Definition: aviriff.h:103
static AVISplitterImpl * impl_from_IMediaSeeking(IMediaSeeking *iface)
Definition: avisplit.c:103
static ULONG WINAPI AVISplitter_Release(IBaseFilter *iface)
Definition: avisplit.c:1267
AVISTDINDEX ** stdindex
Definition: avisplit.c:65
#define FOURCC_RIFF
Definition: mmsystem.h:564
#define InterlockedDecrement
Definition: armddk.h:52
DWORD dwSampleSize
Definition: aviriff.h:114
Definition: parse.h:22
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:47
GLuint GLuint stream
Definition: glext.h:7522
static HRESULT AVISplitter_ProcessOldIndex(AVISplitterImpl *This)
Definition: avisplit.c:607
#define mmioFOURCC(c0, c1, c2, c3)
Definition: mmsystem.h:38
#define streamtypeAUDIO
Definition: aviriff.h:93
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
Definition: _list.h:228
HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter *iface, LPWSTR *pVendorInfo)
Definition: parser.c:429
#define CLASS_E_NOAGGREGATION
Definition: winerror.h:2662
RIFFCHUNK CurrentChunk
Definition: avisplit.c:86
uint32_t DWORD_PTR
Definition: typedefs.h:63
DWORD index
Definition: avisplit.c:70
#define streamtypeVIDEO
Definition: aviriff.h:92
#define ERR(fmt,...)
Definition: debug.h:109
ULARGE_INTEGER pos
Definition: request.c:4080
#define ckidAVIEXTHEADER
Definition: aviriff.h:72
static HRESULT AVISplitter_Receive(AVISplitterImpl *This, IMediaSample *sample, DWORD streamnumber)
Definition: avisplit.c:293
#define S_OK
Definition: intsafe.h:59
#define ckidAVISUPERINDEX
Definition: aviriff.h:194
_Out_ PULONG _Out_ PULONG pIndex
Definition: ndis.h:4564
uint64_t DWORD64
Definition: typedefs.h:65
HRESULT WINAPI Parser_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
Definition: parser.c:361
static const IBaseFilterVtbl AVISplitterImpl_Vtbl
Definition: avisplit.c:1411
static calc_node_t temp
Definition: rpn_ieee.c:38
GLuint start
Definition: gl.h:1545
static Parser_OutputPin * unsafe_impl_Parser_OutputPin_from_IPin(IPin *iface)
Definition: parser.h:81
Definition: axcore.idl:91
#define formtypeAVI
Definition: vfw.h:889
#define E_NOTIMPL
Definition: ddrawi.h:99
#define listtypeAVIMOVIE
Definition: vfw.h:898
#define list
Definition: rosglue.h:35
DWORD cb
Definition: aviriff.h:76
unsigned int UINT
Definition: ndis.h:50
BOOL WINAPI IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
Definition: compobj.c:4021
DWORD dwLength
Definition: avisplit.c:61
DWORD dwFuture[61]
Definition: aviriff.h:78
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
BOOL WINAPI DECLSPEC_HOTPATCH ResetEvent(IN HANDLE hEvent)
Definition: synch.c:660
#define MultiByteToWideChar
Definition: compat.h:100
HRESULT WINAPI Parser_SetSyncSource(IBaseFilter *iface, IReferenceClock *pClock)
Definition: parser.c:383
HRESULT WINAPI Parser_GetClassID(IBaseFilter *iface, CLSID *pClsid)
Definition: parser.c:228
HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin *This, IMediaSample *pSample)
Definition: pin.c:574
unsigned long long DWORDLONG
Definition: intsafe.h:99
DWORD stream
Definition: avisplit.c:100
static const WCHAR props[]
Definition: wbemdisp.c:288
float FLOAT
Definition: typedefs.h:67
#define ckidSTREAMNAME
Definition: vfw.h:896
unsigned int ULONG
Definition: retypes.h:1
static __inline const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: compat.h:41
static HRESULT AVISplitter_Flush(LPVOID iface)
Definition: avisplit.c:1215
#define StreamFromFOURCC(fcc)
Definition: vfw.h:919
static HRESULT AVISplitter_done_process(LPVOID iface)
Definition: avisplit.c:514
HRESULT Parser_Create(ParserImpl *pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID *pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, STOPPROCESSPROC fnDone, SourceSeeking_ChangeStop stop, SourceSeeking_ChangeStart start, SourceSeeking_ChangeRate rate)
Definition: parser.c:96
LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, SIZE_T size)
Definition: ifs.c:440
DWORD frames
Definition: avisplit.c:66
#define MEDIATIME_FROM_BYTES(x)
struct StreamData StreamData
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void Parser_Destroy(ParserImpl *This)
Definition: parser.c:176
DWORD dwSampleSize
Definition: avisplit.c:59
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1827
#define INFINITE
Definition: serial.h:102
ULONG WINAPI Parser_AddRef(IBaseFilter *iface)
Definition: parser.c:171
#define memset(x, y, z)
Definition: compat.h:39
HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *pInfo)
Definition: parser.c:419
#define args
Definition: format.c:66
static TfClientId tid
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
Definition: ifs.c:406
WINE_DEFAULT_DEBUG_CHANNEL(quartz)
#define HeapFree(x, y, z)
Definition: compat.h:394
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:90
ParserImpl Parser
Definition: avisplit.c:85
struct tagVIDEOINFOHEADER VIDEOINFOHEADER
static HRESULT AVISplitter_ProcessStreamList(AVISplitterImpl *This, const BYTE *pData, DWORD cb, ALLOCATOR_PROPERTIES *props)
Definition: avisplit.c:678
#define SUCCEEDED(hr)
Definition: intsafe.h:57
DWORD dwGrandFrames
Definition: aviriff.h:77
AVIEXTHEADER ExtHeader
Definition: avisplit.c:90
DWORD pos_next
Definition: avisplit.c:70
static HRESULT AVISplitter_ProcessIndex(AVISplitterImpl *This, AVISTDINDEX **index, LONGLONG qwOffset, DWORD cb)
Definition: avisplit.c:552
#define AVI_INDEX_SUB_2FIELD
Definition: aviriff.h:179