Unitys MovieTexture crasht auf dem Mac [Lösungen]
Videos innerhalb eines Spiels abzuspielen, ist mit einigen technischen Herausforderungen verbunden. So müssen z.B. verhältnismäßig viele Daten in kurzer Zeit in den Videospeicher gestreamt werden, um sie auf einer MovieTexture im 3D-Raum rendern zu können. Unity nimmt uns hier glücklicherweise durch seine „Just works“-Mentalität wieder einmal viel Last ab. Dennoch kann es zu Problemen kommen, wie folgendes Beispiel zeigt:
Am Ende der Demo von A Room Beyond sollte ein Marketing-Video abgespielt werden. Dazu wird eine separate Szene im Spiel geladen, in der sich das Video als MovieTexture eines RawImage-Objekts befindet. Lief alles prima, bis ich den Build auf einem Mac testete. Das Spiel hat schlicht nicht mehr reagiert anstatt in die Video-Szene zu springen.
Ursache des fehlerhaften Ladens der MovieTexture ermitteln
Das Fehlerprotokoll des Players sah in etwa so aus:
Receiving unhandled NULL exception Obtained 25 stack frames. #0 0x00000100e09e2e in BaseVideoTexture::InitVideoMemory(int, int) #1 0x00000100b47b49 in PersistentManager::IntegrateObjectAndUnlockIntegrationMutexInternal(int) #2 0x00000100b1289d in TimeSliceAwakeFromLoadQueue::IntegrateTimeSliced(int) #3 0x00000100b126fd in LoadOperation::IntegrateTimeSliced(int) #4 0x00000100b13dee in LoadSceneOperation::IntegrateTimeSliced(int) #5 0x00000100b10d37 in PreloadManager::UpdatePreloadingSingleStep(PreloadManager::UpdatePreloadingFlags, int) #6 0x00000100b11592 in PreloadManager::WaitForAllAsyncOperationsToComplete() #7 0x00000100932ee5 in RuntimeSceneManager::LoadScene(UnityStr const&, UnityStr const&, UnityStr const&, UnityGUID const&, int, RuntimeSceneManager::LoadingMode) #8 0x00000100aa7489 in PlayerStartFirstScene(bool) #9 0x0000010106f2d8 in -[PlayerAppDelegate UpdatePlayer] #10 0x007fff8ae2fdec in __NSFireTimer #11 0x007fff91fa9af4 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ #12 0x007fff91fa9783 in __CFRunLoopDoTimer #13 0x007fff91fa92da in __CFRunLoopDoTimers #14 0x007fff91fa07d1 in __CFRunLoopRun #15 0x007fff91f9fe38 in CFRunLoopRunSpecific #16 0x007fff998b9935 in RunCurrentEventLoopInMode #17 0x007fff998b976f in ReceiveNextEventCommon #18 0x007fff998b95af in _BlockUntilNextEventMatchingListInModeWithFilter #19 0x007fff923d6df6 in _DPSNextEvent #20 0x007fff923d6226 in -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] #21 0x007fff923cad80 in -[NSApplication run] #22 0x007fff92394368 in NSApplicationMain #23 0x0000010106de92 in PlayerMain(int, char const**) #24 0x00000100001a34 in start
Zeile 1 zeigt, dass es zu einer Nullpointer-Exception kam. Der Funktionsname InitVideoMemory
in Zeile 3 lässt darauf schließen, dass das Problem mit dem Laden des Videos zusammenhängt. Der Rest des Stacktraces zeigt außerdem auf Unity-interne Methoden, das Problem liegt also wahrscheinlich nicht an meinem Code.
Lösungsansätze, um die MovieTexture auch auf dem Mac abspielen zu können
Im Unity-Forum vermutet man, dass das Problem mit dem Laden, bzw. dem Entladen von Videos abspielenden Szenen zusammenhängen könnte. Folglich habe ich versucht, das Video verzögert zu laden, d.h mit Hilfe einer Coroutine, die einige Frames wartet, bevor das Video dem RawImage zugewiesen und abgespielt wird. Wenn es am Laden liegt, müsste das Problem ja behoben sein, wenn sich die Software erst mit dem Video befasst, nachdem der Szenen-Ladevorgang abgeschlossen ist. Leider blieb das Problem aber bestehen.
Weil die fehlgeschlagene Funktion den Begriff „VideoMemory“ enthielt, fragte ich mich dann, ob das Video womöglich zu groß sei und der Testrechner (ein Macbook) schlicht zu wenig Speicherkapazität hätte. Allerdings war das Video lediglich 10MB groß, so dass dieses Problem sehr unwahrscheinlich schien. Um dennoch auszuschließen, dass etwas grundsätzlich mit der Video-Datei nicht stimmt und um mich an das Problem näher heranzutasten, begann ich ein einfaches Experiment.
Ich legte auf dem Mac schlicht ein neues Unity-Projekt an und erstellte eine Test-Szene, die nichts außer einem Canvas mit RawImage enthielt, dem die Video-Datei zugewiesen wurde. Der Standalone-Build lief einwandfrei, das Video wurde sauber in-game abgespielt. Worin unterschied sich nun also mein Testprojekt von meinem Spielprojekt?
Ich fand das Problem relativ schnell: Es liegt am Build-Typ des Mac-Players. Scheinbar funktioniert das Laden der Videos nicht richtig, wenn ein Universal-Build erzeugt wird. Die Lösung bestand letztlich also im Umstellen auf den 32-bit-Architektur-Typ x86.
Ich hätte auch auf x86_64 umstellen können, dann läuft das Spiel jedoch nur noch auf 64-bit Rechnern. Der 32-bit-Build dagegen sollte sowohl auf 64- wie auch 32-bit-Systemen laufen.