📄 qtmoviewin.cpp
字号:
void QTMovieWin::setVolume(float volume){ if (!m_private->m_movie) return; SetMovieVolume(m_private->m_movie, static_cast<short>(volume * 256));}unsigned QTMovieWin::dataSize() const{ if (!m_private->m_movie) return 0; return GetMovieDataSize(m_private->m_movie, 0, GetMovieDuration(m_private->m_movie));}float QTMovieWin::maxTimeLoaded() const{ if (!m_private->m_movie) return 0; TimeValue val; GetMaxLoadedTimeInMovie(m_private->m_movie, &val); TimeScale scale = GetMovieTimeScale(m_private->m_movie); return static_cast<float>(val) / scale;}long QTMovieWin::loadState() const{ return m_private->m_loadState;}void QTMovieWin::getNaturalSize(int& width, int& height){ Rect rect = { 0, }; if (m_private->m_movie) GetMovieNaturalBoundsRect(m_private->m_movie, &rect); width = rect.right; height = rect.bottom;}void QTMovieWin::setSize(int width, int height){ m_private->setSize(width, height); updateTaskTimer(0);}void QTMovieWin::setVisible(bool b){ m_private->m_visible = b; m_private->updateGWorld();}void QTMovieWin::paint(HDC hdc, int x, int y){ if (!m_private->m_gWorld) return; HDC hdcSrc = static_cast<HDC>(GetPortHDC(reinterpret_cast<GrafPtr>(m_private->m_gWorld))); if (!hdcSrc) return; // FIXME: If we could determine the movie has no alpha, we could use BitBlt for those cases, which might be faster. BLENDFUNCTION blendFunction; blendFunction.BlendOp = AC_SRC_OVER; blendFunction.BlendFlags = 0; blendFunction.SourceConstantAlpha = 255; blendFunction.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(hdc, x, y, m_private->m_width, m_private->m_height, hdcSrc, 0, 0, m_private->m_width, m_private->m_height, blendFunction);}void QTMovieWin::load(const UChar* url, int len){ if (m_private->m_movie) { m_private->endTask(); if (m_private->m_gWorld) m_private->deleteGWorld(); if (m_private->m_movieController) DisposeMovieController(m_private->m_movieController); m_private->m_movieController = 0; DisposeMovie(m_private->m_movie); m_private->m_movie = 0; } // Define a property array for NewMovieFromProperties. 8 should be enough for our needs. QTNewMoviePropertyElement movieProps[8]; ItemCount moviePropCount = 0; bool boolTrue = true; // Create a URL data reference of type CFURL CFStringRef urlStringRef = CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(url), len); // Disable streaming support for now. if (CFStringHasPrefix(urlStringRef, CFSTR("rtsp:"))) { m_private->m_loadError = noMovieFound; goto end; } CFURLRef urlRef = CFURLCreateWithString(kCFAllocatorDefault, urlStringRef, 0); // Add the movie data location to the property array movieProps[moviePropCount].propClass = kQTPropertyClass_DataLocation; movieProps[moviePropCount].propID = kQTDataLocationPropertyID_CFURL; movieProps[moviePropCount].propValueSize = sizeof(urlRef); movieProps[moviePropCount].propValueAddress = &urlRef; movieProps[moviePropCount].propStatus = 0; moviePropCount++; movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_DontAskUnresolvedDataRefs; movieProps[moviePropCount].propValueSize = sizeof(boolTrue); movieProps[moviePropCount].propValueAddress = &boolTrue; movieProps[moviePropCount].propStatus = 0; moviePropCount++; movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; movieProps[moviePropCount].propID = kQTMovieInstantiationPropertyID_AsyncOK; movieProps[moviePropCount].propValueSize = sizeof(boolTrue); movieProps[moviePropCount].propValueAddress = &boolTrue; movieProps[moviePropCount].propStatus = 0; moviePropCount++; movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty; movieProps[moviePropCount].propID = kQTNewMoviePropertyID_Active; movieProps[moviePropCount].propValueSize = sizeof(boolTrue); movieProps[moviePropCount].propValueAddress = &boolTrue; movieProps[moviePropCount].propStatus = 0; moviePropCount++; movieProps[moviePropCount].propClass = kQTPropertyClass_NewMovieProperty; movieProps[moviePropCount].propID = kQTNewMoviePropertyID_DontInteractWithUser; movieProps[moviePropCount].propValueSize = sizeof(boolTrue); movieProps[moviePropCount].propValueAddress = &boolTrue; movieProps[moviePropCount].propStatus = 0; moviePropCount++; movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; movieProps[moviePropCount].propID = '!url'; movieProps[moviePropCount].propValueSize = sizeof(boolTrue); movieProps[moviePropCount].propValueAddress = &boolTrue; movieProps[moviePropCount].propStatus = 0; moviePropCount++; movieProps[moviePropCount].propClass = kQTPropertyClass_MovieInstantiation; movieProps[moviePropCount].propID = 'site'; movieProps[moviePropCount].propValueSize = sizeof(boolTrue); movieProps[moviePropCount].propValueAddress = &boolTrue; movieProps[moviePropCount].propStatus = 0; moviePropCount++; m_private->m_loadError = NewMovieFromProperties(moviePropCount, movieProps, 0, NULL, &m_private->m_movie); CFRelease(urlRef);end: m_private->startTask(); // get the load fail callback quickly if (m_private->m_loadError) updateTaskTimer(0); else m_private->registerDrawingCallback(); CFRelease(urlStringRef);}void QTMovieWin::disableUnsupportedTracks(unsigned& enabledTrackCount){ if (!m_private->m_movie) { enabledTrackCount = 0; return; } static HashSet<OSType>* allowedTrackTypes = 0; if (!allowedTrackTypes) { allowedTrackTypes = new HashSet<OSType>; allowedTrackTypes->add(VideoMediaType); allowedTrackTypes->add(SoundMediaType); allowedTrackTypes->add(TextMediaType); allowedTrackTypes->add(BaseMediaType); allowedTrackTypes->add('clcp'); // Closed caption allowedTrackTypes->add('sbtl'); // Subtitle } long trackCount = GetMovieTrackCount(m_private->m_movie); enabledTrackCount = trackCount; // Track indexes are 1-based. yuck. These things must descend from old- // school mac resources or something. for (long trackIndex = 1; trackIndex <= trackCount; trackIndex++) { // Grab the track at the current index. If there isn't one there, then // we can move onto the next one. Track currentTrack = GetMovieIndTrack(m_private->m_movie, trackIndex); if (!currentTrack) continue; // Check to see if the track is disabled already, we should move along. // We don't need to re-disable it. if (!GetTrackEnabled(currentTrack)) continue; // Grab the track's media. We're going to check to see if we need to // disable the tracks. They could be unsupported. Media trackMedia = GetTrackMedia(currentTrack); if (!trackMedia) continue; // Grab the media type for this track. Make sure that we don't // get an error in doing so. If we do, then something really funky is // wrong. OSType mediaType; GetMediaHandlerDescription(trackMedia, &mediaType, nil, nil); OSErr mediaErr = GetMoviesError(); if (mediaErr != noErr) continue; if (!allowedTrackTypes->contains(mediaType)) { // Different mpeg variants import as different track types so check for the "mpeg // characteristic" instead of hard coding the (current) list of mpeg media types. if (GetMovieIndTrackType(m_private->m_movie, 1, 'mpeg', movieTrackCharacteristic | movieTrackEnabledOnly)) continue; SetTrackEnabled(currentTrack, false); --enabledTrackCount; } // Grab the track reference count for chapters. This will tell us if it // has chapter tracks in it. If there aren't any references, then we // can move on the next track. long referenceCount = GetTrackReferenceCount(currentTrack, kTrackReferenceChapterList); if (referenceCount <= 0) continue; long referenceIndex = 0; while (1) { // If we get nothing here, we've overstepped our bounds and can stop // looking. Chapter indices here are 1-based as well - hence, the // pre-increment. referenceIndex++; Track chapterTrack = GetTrackReference(currentTrack, kTrackReferenceChapterList, referenceIndex); if (!chapterTrack) break; // Try to grab the media for the track. Media chapterMedia = GetTrackMedia(chapterTrack); if (!chapterMedia) continue; // Grab the media type for this track. Make sure that we don't // get an error in doing so. If we do, then something really // funky is wrong. OSType mediaType; GetMediaHandlerDescription(chapterMedia, &mediaType, nil, nil); OSErr mediaErr = GetMoviesError(); if (mediaErr != noErr) continue; // Check to see if the track is a video track. We don't care about // other non-video tracks. if (mediaType != VideoMediaType) continue; // Check to see if the track is already disabled. If it is, we // should move along. if (!GetTrackEnabled(chapterTrack)) continue; // Disabled the evil, evil track. SetTrackEnabled(chapterTrack, false); --enabledTrackCount; } }}bool QTMovieWin::hasVideo() const{ if (!m_private->m_movie) return false; return (GetMovieIndTrackType(m_private->m_movie, 1, VisualMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly));}pascal OSErr movieDrawingCompleteProc(Movie movie, long data){ UppParam param; param.longValue = data; QTMovieWinPrivate* mp = static_cast<QTMovieWinPrivate*>(param.ptr); if (mp) mp->drawingComplete(); return 0;}static void initializeSupportedTypes() { if (gSupportedTypes) return; gSupportedTypes = new Vector<CFStringRef>; if (quickTimeVersion < minimumQuickTimeVersion) { LOG_ERROR("QuickTime version %x detected, at least %x required. Returning empty list of supported media MIME types.", quickTimeVersion, minimumQuickTimeVersion); return; } // QuickTime doesn't have an importer for video/quicktime. Add it manually. gSupportedTypes->append(CFSTR("video/quicktime")); for (int index = 0; index < 2; index++) { ComponentDescription findCD; // look at all movie importers that can import in place and are installed. findCD.componentType = MovieImportType; findCD.componentSubType = 0; findCD.componentManufacturer = 0; findCD.componentFlagsMask = cmpIsMissing | movieImportSubTypeIsFileExtension | canMovieImportInPlace | dontAutoFileMovieImport; // look at those registered by HFS file types the first time through, by file extension the second time findCD.componentFlags = canMovieImportInPlace | (index ? movieImportSubTypeIsFileExtension : 0); long componentCount = CountComponents(&findCD); if (!componentCount) continue; Component comp = 0; while (comp = FindNextComponent(comp, &findCD)) { // Does this component have a MIME type container? ComponentDescription infoCD; OSErr err = GetComponentInfo(comp, &infoCD, nil /*name*/, nil /*info*/, nil /*icon*/); if (err) continue; if (!(infoCD.componentFlags & hasMovieImportMIMEList)) continue; QTAtomContainer mimeList = NULL; err = MovieImportGetMIMETypeList((ComponentInstance)comp, &mimeList); if (err || !mimeList) continue; // Grab every type from the container. QTLockContainer(mimeList); int typeCount = QTCountChildrenOfType(mimeList, kParentAtomIsContainer, kMimeInfoMimeTypeTag); for (int typeIndex = 1; typeIndex <= typeCount; typeIndex++) { QTAtom mimeTag = QTFindChildByIndex(mimeList, 0, kMimeInfoMimeTypeTag, typeIndex, NULL); if (!mimeTag) continue; char* atomData; long typeLength; if (noErr != QTGetAtomDataPtr(mimeList, mimeTag, &typeLength, &atomData)) continue; char typeBuffer[256]; if (typeLength >= sizeof(typeBuffer)) continue; memcpy(typeBuffer, atomData, typeLength); typeBuffer[typeLength] = 0; // Only add "audio/..." and "video/..." types. if (strncmp(typeBuffer, "audio/", 6) && strncmp(typeBuffer, "video/", 6)) continue; CFStringRef cfMimeType = CFStringCreateWithCString(NULL, typeBuffer, kCFStringEncodingUTF8); if (!cfMimeType) continue; // Only add each type once. bool alreadyAdded = false; for (int addedIndex = 0; addedIndex < gSupportedTypes->size(); addedIndex++) { CFStringRef type = gSupportedTypes->at(addedIndex); if (kCFCompareEqualTo == CFStringCompare(cfMimeType, type, kCFCompareCaseInsensitive)) { alreadyAdded = true; break; } } if (!alreadyAdded) gSupportedTypes->append(cfMimeType); else CFRelease(cfMimeType); } DisposeHandle(mimeList); } }}unsigned QTMovieWin::countSupportedTypes(){ initializeSupportedTypes(); return static_cast<unsigned>(gSupportedTypes->size());}void QTMovieWin::getSupportedType(unsigned index, const UChar*& str, unsigned& len){ initializeSupportedTypes(); ASSERT(index < gSupportedTypes->size()); // Allocate sufficient buffer to hold any MIME type static UniChar* staticBuffer = 0; if (!staticBuffer) staticBuffer = new UniChar[32]; CFStringRef cfstr = gSupportedTypes->at(index); len = CFStringGetLength(cfstr); CFRange range = { 0, len }; CFStringGetCharacters(cfstr, range, staticBuffer); str = reinterpret_cast<const UChar*>(staticBuffer); }bool QTMovieWin::initializeQuickTime() { static bool initialized = false; static bool initializationSucceeded = false; if (!initialized) { initialized = true; // Initialize and check QuickTime version OSErr result = InitializeQTML(0); if (result == noErr) result = Gestalt(gestaltQuickTime, &quickTimeVersion); if (result != noErr) { LOG_ERROR("No QuickTime available. Disabling <video> and <audio> support."); return false; } if (quickTimeVersion < minimumQuickTimeVersion) { LOG_ERROR("QuickTime version %x detected, at least %x required. Disabling <video> and <audio> support.", quickTimeVersion, minimumQuickTimeVersion); return false; } EnterMovies(); setSharedTimerFiredFunction(taskTimerFired); gMovieDrawingCompleteUPP = NewMovieDrawingCompleteUPP(movieDrawingCompleteProc); initializationSucceeded = true; } return initializationSucceeded;}BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ switch (fdwReason) { case DLL_PROCESS_ATTACH: setSharedTimerInstanceHandle(hinstDLL); return TRUE; case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: return FALSE; } ASSERT_NOT_REACHED(); return FALSE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -