// Registers a DataFlavor/FE pair void nsDataObjCollection::AddDataFlavor(const char * aDataFlavor, LPFORMATETC aFE) { // Add the FormatEtc to our list if it's not already there. We don't care // about the internal aDataFlavor because nsDataObj handles that. IEnumFORMATETC * ifEtc; FORMATETC fEtc; ULONG num; if (S_OK != this->EnumFormatEtc(DATADIR_GET, &ifEtc)) return; while (S_OK == ifEtc->Next(1, &fEtc, &num)) { NS_ASSERTION(1 == num, "Bit off more than we can chew in nsDataObjCollection::AddDataFlavor"); if (FormatsMatch(fEtc, *aFE)) { ifEtc->Release(); return; } } // If we didn't find a matching format, add this one ifEtc->Release(); m_enumFE->AddFormatEtc(aFE); }
AudioConverterStream::AudioConverterStream(WaveFormat sourceFormat, WaveFormat destFormat, WaveFormat** prevSourceFormats , int numPrevSourceFormats) : outBuffer(nullptr), outSize(0), outBufferAllocated(0), stream(nullptr), isProxy(false), m_failed(false), subConverter(nullptr), startOffset(0) { if (sourceFormat.GetSize() == destFormat.GetSize()) { LPWAVEFORMATEX src = static_cast<LPWAVEFORMATEX>(sourceFormat); LPWAVEFORMATEX dest = static_cast<LPWAVEFORMATEX>(destFormat); if (memcmp(src, dest, sourceFormat.GetSize()) == 0) { // Source and destination formats are identical, so we'll just pass the input through to // the output isProxy = true; return; } } MMRESULT mm = acmStreamOpen(&stream, nullptr, sourceFormat, destFormat, nullptr, 0, 0, ACM_STREAMOPENF_NONREALTIME); if (mm != MMSYSERR_NOERROR) { // Not supported directly, so try letting ACM suggest an intermediate format, so we can // perform the conversion in multiple stages. WaveFormat intermediateFormat; // This weird looping structure is because we must try all combinations of four flags, and // even when a given combination yields a valid suggestion, we must be able to backtrack and // continue looping (tryMoreSuggestions) if the conversion based on that suggestion later // fails or dead-ends. bool foundSuggest = false; int chan, samp, bits, form, done; for (done = 0; done < 1 && !foundSuggest; foundSuggest ? 0 : ++done) { for (chan = 1; chan >= 0 && !foundSuggest; foundSuggest ? 0 : --chan) { for (samp = 1; samp >= 0 && !foundSuggest; foundSuggest ? 0 : --samp) { for (bits = 0; bits <= 1 && !foundSuggest; foundSuggest ? 0 : ++bits) { for (form = 0; form <= 1 && !foundSuggest; foundSuggest ? 0 : ++form) { int flags = 0; flags |= chan ? ACM_FORMATSUGGESTF_NCHANNELS : 0; flags |= samp ? ACM_FORMATSUGGESTF_NSAMPLESPERSEC : 0; flags |= bits ? ACM_FORMATSUGGESTF_WBITSPERSAMPLE : 0; flags |= form ? ACM_FORMATSUGGESTF_WFORMATTAG : 0; intermediateFormat = destFormat; MMRESULT mmSuggest = acmFormatSuggest(NULL, sourceFormat, intermediateFormat, intermediateFormat.GetSize(), flags); if (mmSuggest == MMSYSERR_NOERROR) { // Got a possibly-valid suggestion, but it might be a suggestion to // do absolutely nothing (which would be bad), so we first make sure // there's some sort of change involved: if (!FormatsMatch(sourceFormat, intermediateFormat)) { // We got a suggestion foundSuggest = true; // Now check to see if it's identical to a previous conversion // state. If it is, then we'll revert foundSuggest to false to // prevent endless conversion cycles. for (int prev = 0; prev < numPrevSourceFormats && prevSourceFormats && foundSuggest; prev++) { WaveFormat& oldFormat = *prevSourceFormats[prev]; if (FormatsMatch(oldFormat, intermediateFormat)) { // We already went through this exact format foundSuggest = false; } } } } tryMoreSuggestions: continue; } } } } } if (!foundSuggest) { m_failed = true; return; } // we'll handle conversion to the intermediate format mm = acmStreamOpen(&stream, nullptr, sourceFormat, intermediateFormat, nullptr, 0, 0, ACM_STREAMOPENF_NONREALTIME); if (mm != MMSYSERR_NOERROR) { if (!done) { foundSuggest = false; goto tryMoreSuggestions; // continue the search } // reached dead end m_failed = true; return; } // create temporary updated conversion history for cycle prevention size_t prevSize = sizeof(WaveFormat*) * (numPrevSourceFormats + 1); WaveFormat** prevFormats = static_cast<WaveFormat**>(alloca(prevSize)); if (prevSourceFormats) { memcpy(prevFormats, prevSourceFormats, prevSize); } prevFormats[numPrevSourceFormats] = &sourceFormat; // delegate the rest of the conversion to a new converter (recursive construction) subConverter = new AudioConverterStream(intermediateFormat, destFormat, prevFormats, numPrevSourceFormats + 1); if (subConverter->m_failed) { delete subConverter; subConverter = nullptr; if (!done) { foundSuggest = false; goto tryMoreSuggestions; // continue the search } // reached dead end m_failed = true; return; } } // prepare the stream header memset(&header, 0, sizeof(ACMSTREAMHEADER)); header.cbStruct = sizeof(ACMSTREAMHEADER); header.pbSrc = inWorkBuffer; header.cbSrcLength = sizeof(inWorkBuffer); header.pbDst = outWorkBuffer; header.cbDstLength = sizeof(outWorkBuffer); mm = acmStreamPrepareHeader(stream, &header, 0); if (mm != MMSYSERR_NOERROR) { m_failed = true; } }