1 /***********************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3
4 (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com),
5 Jerremy Koot (jkoot@snes9x.com)
6
7 (c) Copyright 2002 - 2004 Matthew Kendora
8
9 (c) Copyright 2002 - 2005 Peter Bortas (peter@bortas.org)
10
11 (c) Copyright 2004 - 2005 Joel Yliluoma (http://iki.fi/bisqwit/)
12
13 (c) Copyright 2001 - 2006 John Weidman (jweidman@slip.net)
14
15 (c) Copyright 2002 - 2006 funkyass (funkyass@spam.shaw.ca),
16 Kris Bleakley (codeviolation@hotmail.com)
17
18 (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net),
19 Nach (n-a-c-h@users.sourceforge.net),
20
21 (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com)
22
23 (c) Copyright 2006 - 2007 nitsuja
24
25 (c) Copyright 2009 - 2016 BearOso,
26 OV2
27
28
29 BS-X C emulator code
30 (c) Copyright 2005 - 2006 Dreamer Nom,
31 zones
32
33 C4 x86 assembler and some C emulation code
34 (c) Copyright 2000 - 2003 _Demo_ (_demo_@zsnes.com),
35 Nach,
36 zsKnight (zsknight@zsnes.com)
37
38 C4 C++ code
39 (c) Copyright 2003 - 2006 Brad Jorsch,
40 Nach
41
42 DSP-1 emulator code
43 (c) Copyright 1998 - 2006 _Demo_,
44 Andreas Naive (andreasnaive@gmail.com),
45 Gary Henderson,
46 Ivar (ivar@snes9x.com),
47 John Weidman,
48 Kris Bleakley,
49 Matthew Kendora,
50 Nach,
51 neviksti (neviksti@hotmail.com)
52
53 DSP-2 emulator code
54 (c) Copyright 2003 John Weidman,
55 Kris Bleakley,
56 Lord Nightmare (lord_nightmare@users.sourceforge.net),
57 Matthew Kendora,
58 neviksti
59
60 DSP-3 emulator code
61 (c) Copyright 2003 - 2006 John Weidman,
62 Kris Bleakley,
63 Lancer,
64 z80 gaiden
65
66 DSP-4 emulator code
67 (c) Copyright 2004 - 2006 Dreamer Nom,
68 John Weidman,
69 Kris Bleakley,
70 Nach,
71 z80 gaiden
72
73 OBC1 emulator code
74 (c) Copyright 2001 - 2004 zsKnight,
75 pagefault (pagefault@zsnes.com),
76 Kris Bleakley
77 Ported from x86 assembler to C by sanmaiwashi
78
79 SPC7110 and RTC C++ emulator code used in 1.39-1.51
80 (c) Copyright 2002 Matthew Kendora with research by
81 zsKnight,
82 John Weidman,
83 Dark Force
84
85 SPC7110 and RTC C++ emulator code used in 1.52+
86 (c) Copyright 2009 byuu,
87 neviksti
88
89 S-DD1 C emulator code
90 (c) Copyright 2003 Brad Jorsch with research by
91 Andreas Naive,
92 John Weidman
93
94 S-RTC C emulator code
95 (c) Copyright 2001 - 2006 byuu,
96 John Weidman
97
98 ST010 C++ emulator code
99 (c) Copyright 2003 Feather,
100 John Weidman,
101 Kris Bleakley,
102 Matthew Kendora
103
104 Super FX x86 assembler emulator code
105 (c) Copyright 1998 - 2003 _Demo_,
106 pagefault,
107 zsKnight
108
109 Super FX C emulator code
110 (c) Copyright 1997 - 1999 Ivar,
111 Gary Henderson,
112 John Weidman
113
114 Sound emulator code used in 1.5-1.51
115 (c) Copyright 1998 - 2003 Brad Martin
116 (c) Copyright 1998 - 2006 Charles Bilyue'
117
118 Sound emulator code used in 1.52+
119 (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com)
120
121 S-SMP emulator code used in 1.54+
122 (c) Copyright 2016 byuu
123
124 SH assembler code partly based on x86 assembler code
125 (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
126
127 2xSaI filter
128 (c) Copyright 1999 - 2001 Derek Liauw Kie Fa
129
130 HQ2x, HQ3x, HQ4x filters
131 (c) Copyright 2003 Maxim Stepin (maxim@hiend3d.com)
132
133 NTSC filter
134 (c) Copyright 2006 - 2007 Shay Green
135
136 GTK+ GUI code
137 (c) Copyright 2004 - 2016 BearOso
138
139 Win32 GUI code
140 (c) Copyright 2003 - 2006 blip,
141 funkyass,
142 Matthew Kendora,
143 Nach,
144 nitsuja
145 (c) Copyright 2009 - 2016 OV2
146
147 Mac OS GUI code
148 (c) Copyright 1998 - 2001 John Stiles
149 (c) Copyright 2001 - 2011 zones
150
151
152 Specific ports contains the works of other authors. See headers in
153 individual files.
154
155
156 Snes9x homepage: http://www.snes9x.com/
157
158 Permission to use, copy, modify and/or distribute Snes9x in both binary
159 and source form, for non-commercial purposes, is hereby granted without
160 fee, providing that this license information and copyright notice appear
161 with all copies and any derived work.
162
163 This software is provided 'as-is', without any express or implied
164 warranty. In no event shall the authors be held liable for any damages
165 arising from the use of this software or it's derivatives.
166
167 Snes9x is freeware for PERSONAL USE only. Commercial users should
168 seek permission of the copyright holders first. Commercial use includes,
169 but is not limited to, charging money for Snes9x or software derived from
170 Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
171 using Snes9x as a promotion for your commercial product.
172
173 The copyright holders request that bug fixes and improvements to the code
174 should be forwarded to them so everyone can benefit from the modifications
175 in future versions.
176
177 Super NES and Super Nintendo Entertainment System are trademarks of
178 Nintendo Co., Limited and its subsidiary companies.
179 ***********************************************************************************/
180
181 /***********************************************************************************
182 SNES9X for Mac OS (c) Copyright John Stiles
183
184 Snes9x for Mac OS X
185
186 (c) Copyright 2001 - 2011 zones
187 (c) Copyright 2002 - 2005 107
188 (c) Copyright 2002 PB1400c
189 (c) Copyright 2004 Alexander and Sander
190 (c) Copyright 2004 - 2005 Steven Seeger
191 (c) Copyright 2005 Ryan Vogt
192 ***********************************************************************************/
193
194
195 #include "snes9x.h"
196 #include "memmap.h"
197 #include "apu.h"
198
199 #include <QuickTime/QuickTime.h>
200
201 #include "mac-prefix.h"
202 #include "mac-gworld.h"
203 #include "mac-os.h"
204 #include "mac-screenshot.h"
205 #include "mac-quicktime.h"
206
207 #define kMovDoubleSize (1 << 0)
208 #define kMovExtendedHeight (1 << 1)
209
210 static void CheckError (OSStatus, int);
211 static void MacQTOpenVideoComponent (ComponentInstance *);
212 static void MacQTCloseVideoComponent (ComponentInstance);
213 static OSStatus WriteFrameCallBack (void *, ICMCompressionSessionRef, OSStatus, ICMEncodedFrameRef, void *);
214
215 typedef struct
216 {
217 Movie movie;
218 Track vTrack, sTrack;
219 Media vMedia, sMedia;
220 ComponentInstance vci;
221 SoundDescriptionHandle soundDesc;
222 DataHandler dataHandler;
223 Handle soundBuffer;
224 Handle dataRef;
225 OSType dataRefType;
226 CVPixelBufferPoolRef pool;
227 ICMCompressionSessionRef session;
228 ICMCompressionSessionOptionsRef option;
229 CGImageRef srcImage;
230 TimeValue64 timeStamp;
231 long keyFrame, keyFrameCount;
232 long frameSkip, frameSkipCount;
233 int width, height;
234 int soundBufferSize;
235 int samplesPerSec;
236 } MacQTState;
237
238 static MacQTState sqt;
239
240
CheckError(OSStatus err,int n)241 static void CheckError (OSStatus err, int n)
242 {
243 if (err != noErr)
244 {
245 char mes[32];
246
247 sprintf(mes, "quicktime %02d", n);
248 QuitWithFatalError(err, mes);
249 }
250 }
251
MacQTOpenVideoComponent(ComponentInstance * rci)252 static void MacQTOpenVideoComponent (ComponentInstance *rci)
253 {
254 OSStatus err;
255 ComponentInstance ci;
256 CFDataRef data;
257
258 ci = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
259
260 data = (CFDataRef) CFPreferencesCopyAppValue(CFSTR("QTVideoSetting"), kCFPreferencesCurrentApplication);
261 if (data)
262 {
263 CFIndex len;
264 Handle hdl;
265
266 len = CFDataGetLength(data);
267 hdl = NewHandleClear((Size) len);
268 if (MemError() == noErr)
269 {
270 HLock(hdl);
271 CFDataGetBytes(data, CFRangeMake(0, len), (unsigned char *) *hdl);
272 err = SCSetInfo(ci, scSettingsStateType, &hdl);
273
274 DisposeHandle(hdl);
275 }
276
277 CFRelease(data);
278 }
279 else
280 {
281 SCSpatialSettings ss;
282 SCTemporalSettings ts;
283
284 ss.codecType = kAnimationCodecType;
285 ss.codec = 0;
286 ss.depth = 16;
287 ss.spatialQuality = codecMaxQuality;
288 err = SCSetInfo(ci, scSpatialSettingsType, &ss);
289
290 ts.frameRate = FixRatio(Memory.ROMFramesPerSecond, 1);
291 ts.keyFrameRate = Memory.ROMFramesPerSecond;
292 ts.temporalQuality = codecMaxQuality;
293 err = SCSetInfo(ci, scTemporalSettingsType, &ts);
294 }
295
296 *rci = ci;
297 }
298
MacQTCloseVideoComponent(ComponentInstance ci)299 static void MacQTCloseVideoComponent (ComponentInstance ci)
300 {
301 OSStatus err;
302
303 err = CloseComponent(ci);
304 }
305
MacQTVideoConfig(void)306 void MacQTVideoConfig (void)
307 {
308 OSStatus err;
309 ComponentInstance ci;
310
311 MacQTOpenVideoComponent(&ci);
312
313 long flag;
314 flag = scListEveryCodec | scAllowZeroKeyFrameRate | scDisableFrameRateItem | scAllowEncodingWithCompressionSession;
315 err = SCSetInfo(ci, scPreferenceFlagsType, &flag);
316
317 SCWindowSettings ws;
318 ws.size = sizeof(SCWindowSettings);
319 ws.windowRefKind = scWindowRefKindCarbon;
320 ws.parentWindow = NULL;
321 err = SCSetInfo(ci, scWindowOptionsType, &ws);
322
323 err = SCRequestSequenceSettings(ci);
324 if (err == noErr)
325 {
326 CFDataRef data;
327 Handle hdl;
328
329 err = SCGetInfo(ci, scSettingsStateType, &hdl);
330 if (err == noErr)
331 {
332 HLock(hdl);
333 data = CFDataCreate(kCFAllocatorDefault, (unsigned char *) *hdl, GetHandleSize(hdl));
334 if (data)
335 {
336 CFPreferencesSetAppValue(CFSTR("QTVideoSetting"), data, kCFPreferencesCurrentApplication);
337 CFRelease(data);
338 }
339
340 DisposeHandle(hdl);
341 }
342 }
343
344 MacQTCloseVideoComponent(ci);
345 }
346
MacQTStartRecording(char * path)347 void MacQTStartRecording (char *path)
348 {
349 OSStatus err;
350 CFStringRef str;
351 CFURLRef url;
352
353 memset(&sqt, 0, sizeof(sqt));
354
355 // storage
356
357 str = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
358 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, str, kCFURLPOSIXPathStyle, false);
359 err = QTNewDataReferenceFromCFURL(url, 0, &(sqt.dataRef), &(sqt.dataRefType));
360 CheckError(err, 21);
361 CFRelease(url);
362 CFRelease(str);
363
364 err = CreateMovieStorage(sqt.dataRef, sqt.dataRefType, 'TVOD', smSystemScript, createMovieFileDeleteCurFile | newMovieActive, &(sqt.dataHandler), &(sqt.movie));
365 CheckError(err, 22);
366
367 // video
368
369 MacQTOpenVideoComponent(&(sqt.vci));
370
371 long flag;
372 SCTemporalSettings ts;
373
374 flag = scAllowEncodingWithCompressionSession;
375 err = SCSetInfo(sqt.vci, scPreferenceFlagsType, &flag);
376
377 err = SCGetInfo(sqt.vci, scTemporalSettingsType, &ts);
378 ts.frameRate = FixRatio(Memory.ROMFramesPerSecond, 1);
379 if (ts.keyFrameRate < 1)
380 ts.keyFrameRate = Memory.ROMFramesPerSecond;
381 sqt.keyFrame = sqt.keyFrameCount = ts.keyFrameRate;
382 sqt.frameSkip = sqt.frameSkipCount = (macQTMovFlag & 0xFF00) >> 8;
383 err = SCSetInfo(sqt.vci, scTemporalSettingsType, &ts);
384
385 sqt.width = ((macQTMovFlag & kMovDoubleSize) ? 2 : 1) * SNES_WIDTH;
386 sqt.height = ((macQTMovFlag & kMovDoubleSize) ? 2 : 1) * ((macQTMovFlag & kMovExtendedHeight) ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT);
387
388 sqt.srcImage = NULL;
389 sqt.timeStamp = 0;
390
391 SCSpatialSettings ss;
392 ICMEncodedFrameOutputRecord record;
393 ICMMultiPassStorageRef nullStorage = NULL;
394
395 err = SCCopyCompressionSessionOptions(sqt.vci, &(sqt.option));
396 CheckError(err, 61);
397 err = ICMCompressionSessionOptionsSetProperty(sqt.option, kQTPropertyClass_ICMCompressionSessionOptions, kICMCompressionSessionOptionsPropertyID_MultiPassStorage, sizeof(ICMMultiPassStorageRef), &nullStorage);
398
399 record.encodedFrameOutputCallback = WriteFrameCallBack;
400 record.encodedFrameOutputRefCon = NULL;
401 record.frameDataAllocator = NULL;
402 err = SCGetInfo(sqt.vci, scSpatialSettingsType, &ss);
403 err = ICMCompressionSessionCreate(kCFAllocatorDefault, sqt.width, sqt.height, ss.codecType, Memory.ROMFramesPerSecond, sqt.option, NULL, &record, &(sqt.session));
404 CheckError(err, 62);
405
406 CFMutableDictionaryRef dic;
407 CFNumberRef val;
408 OSType pix = k16BE555PixelFormat;
409 int row = sqt.width * 2;
410
411 dic = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
412
413 val = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pix);
414 CFDictionaryAddValue(dic, kCVPixelBufferPixelFormatTypeKey, val);
415 CFRelease(val);
416
417 val = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &(sqt.width));
418 CFDictionaryAddValue(dic, kCVPixelBufferWidthKey, val);
419 CFRelease(val);
420
421 val = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &(sqt.height));
422 CFDictionaryAddValue(dic, kCVPixelBufferHeightKey, val);
423 CFRelease(val);
424
425 val = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &row);
426 CFDictionaryAddValue(dic, kCVPixelBufferBytesPerRowAlignmentKey, val);
427 CFRelease(val);
428
429 CFDictionaryAddValue(dic, kCVPixelBufferCGImageCompatibilityKey, kCFBooleanTrue);
430 CFDictionaryAddValue(dic, kCVPixelBufferCGBitmapContextCompatibilityKey, kCFBooleanTrue);
431
432 err = CVPixelBufferPoolCreate(kCFAllocatorDefault, NULL, dic, &(sqt.pool));
433 CheckError(err, 63);
434
435 CFRelease(dic);
436
437 sqt.vTrack = NewMovieTrack(sqt.movie, FixRatio(sqt.width, 1), FixRatio(sqt.height, 1), kNoVolume);
438 CheckError(GetMoviesError(), 23);
439
440 sqt.vMedia = NewTrackMedia(sqt.vTrack, VideoMediaType, Memory.ROMFramesPerSecond, NULL, 0);
441 CheckError(GetMoviesError(), 24);
442
443 err = BeginMediaEdits(sqt.vMedia);
444 CheckError(err, 25);
445
446 // sound
447
448 sqt.soundDesc = (SoundDescriptionHandle) NewHandleClear(sizeof(SoundDescription));
449 CheckError(MemError(), 26);
450
451 (**sqt.soundDesc).descSize = sizeof(SoundDescription);
452 #ifdef __BIG_ENDIAN__
453 (**sqt.soundDesc).dataFormat = Settings.SixteenBitSound ? k16BitBigEndianFormat : k8BitOffsetBinaryFormat;
454 #else
455 (**sqt.soundDesc).dataFormat = Settings.SixteenBitSound ? k16BitLittleEndianFormat : k8BitOffsetBinaryFormat;
456 #endif
457 (**sqt.soundDesc).numChannels = Settings.Stereo ? 2 : 1;
458 (**sqt.soundDesc).sampleSize = Settings.SixteenBitSound ? 16 : 8;
459 (**sqt.soundDesc).sampleRate = (UnsignedFixed) FixRatio(Settings.SoundPlaybackRate, 1);
460
461 sqt.samplesPerSec = Settings.SoundPlaybackRate / Memory.ROMFramesPerSecond;
462
463 sqt.soundBufferSize = sqt.samplesPerSec;
464 if (Settings.SixteenBitSound)
465 sqt.soundBufferSize <<= 1;
466 if (Settings.Stereo)
467 sqt.soundBufferSize <<= 1;
468
469 sqt.soundBuffer = NewHandleClear(sqt.soundBufferSize);
470 CheckError(MemError(), 27);
471 HLock(sqt.soundBuffer);
472
473 sqt.sTrack = NewMovieTrack(sqt.movie, 0, 0, kFullVolume);
474 CheckError(GetMoviesError(), 28);
475
476 sqt.sMedia = NewTrackMedia(sqt.sTrack, SoundMediaType, Settings.SoundPlaybackRate, NULL, 0);
477 CheckError(GetMoviesError(), 29);
478
479 err = BeginMediaEdits(sqt.sMedia);
480 CheckError(err, 30);
481 }
482
MacQTRecordFrame(int width,int height)483 void MacQTRecordFrame (int width, int height)
484 {
485 OSStatus err;
486
487 // video
488
489 if (sqt.frameSkipCount == sqt.frameSkip)
490 {
491 CVPixelBufferRef buf;
492
493 err = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, sqt.pool, &buf);
494 if (err == noErr)
495 {
496 CGColorSpaceRef color;
497 CGContextRef ctx;
498 uint16 *p;
499
500 err = CVPixelBufferLockBaseAddress(buf, 0);
501 p = (uint16 *) CVPixelBufferGetBaseAddress(buf);
502
503 color = CGColorSpaceCreateDeviceRGB();
504 ctx = CGBitmapContextCreate((void *) p, sqt.width, sqt.height, 5, sqt.width * 2, color, kCGImageAlphaNoneSkipFirst | ((systemVersion >= 0x1040) ? kCGBitmapByteOrder16Host : 0));
505 CGContextSetShouldAntialias(ctx, false);
506
507 if (sqt.srcImage)
508 CGImageRelease(sqt.srcImage);
509 sqt.srcImage = CreateGameScreenCGImage();
510
511 CGRect dst = CGRectMake(0.0f, 0.0f, (float) sqt.width, (float) sqt.height);
512
513 if ((!(height % SNES_HEIGHT_EXTENDED)) && (!(macQTMovFlag & kMovExtendedHeight)))
514 {
515 CGRect src;
516
517 src.size.width = (float) width;
518 src.size.height = (float) ((height > 256) ? (SNES_HEIGHT << 1) : SNES_HEIGHT);
519 src.origin.x = (float) 0;
520 src.origin.y = (float) height - src.size.height;
521 DrawSubCGImage(ctx, sqt.srcImage, src, dst);
522 }
523 else
524 if ((sqt.height << 1) % height)
525 {
526 CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f);
527 CGContextFillRect(ctx, dst);
528
529 float dh = (float) ((sqt.height > 256) ? (SNES_HEIGHT << 1) : SNES_HEIGHT);
530 float ofs = (float) ((int) ((drawoverscan ? 1.0 : 0.5) * ((float) sqt.height - dh) + 0.5));
531 dst = CGRectMake(0.0f, ofs, (float) sqt.width, dh);
532 CGContextDrawImage(ctx, dst, sqt.srcImage);
533 }
534 else
535 CGContextDrawImage(ctx, dst, sqt.srcImage);
536
537 CGContextRelease(ctx);
538 CGColorSpaceRelease(color);
539
540 #ifndef __BIG_ENDIAN__
541 for (int i = 0; i < sqt.width * sqt.height; i++)
542 SWAP_WORD(p[i]);
543 #endif
544
545 err = CVPixelBufferUnlockBaseAddress(buf, 0);
546
547 err = ICMCompressionSessionEncodeFrame(sqt.session, buf, sqt.timeStamp, 0, kICMValidTime_DisplayTimeStampIsValid, NULL, NULL, NULL);
548
549 CVPixelBufferRelease(buf);
550 }
551
552 sqt.keyFrameCount--;
553 if (sqt.keyFrameCount <= 0)
554 sqt.keyFrameCount = sqt.keyFrame;
555 }
556
557 sqt.frameSkipCount--;
558 if (sqt.frameSkipCount < 0)
559 sqt.frameSkipCount = sqt.frameSkip;
560
561 sqt.timeStamp++;
562
563 // sound
564
565 int sample_count = sqt.soundBufferSize;
566 if (Settings.SixteenBitSound)
567 sample_count >>= 1;
568
569 S9xMixSamples((uint8 *) *(sqt.soundBuffer), sample_count);
570
571 err = AddMediaSample(sqt.sMedia, sqt.soundBuffer, 0, sqt.soundBufferSize, 1, (SampleDescriptionHandle) sqt.soundDesc, sqt.samplesPerSec, mediaSampleNotSync, NULL);
572 }
573
WriteFrameCallBack(void * refCon,ICMCompressionSessionRef session,OSStatus r,ICMEncodedFrameRef frame,void * reserved)574 static OSStatus WriteFrameCallBack (void *refCon, ICMCompressionSessionRef session, OSStatus r, ICMEncodedFrameRef frame, void *reserved)
575 {
576 OSStatus err;
577
578 err = AddMediaSampleFromEncodedFrame(sqt.vMedia, frame, NULL);
579 return (err);
580 }
581
MacQTStopRecording(void)582 void MacQTStopRecording (void)
583 {
584 OSStatus err;
585
586 // video
587
588 err = ICMCompressionSessionCompleteFrames(sqt.session, true, 0, sqt.timeStamp);
589 err = ExtendMediaDecodeDurationToDisplayEndTime(sqt.vMedia, NULL);
590
591 err = EndMediaEdits(sqt.vMedia);
592 CheckError(err, 52);
593
594 err = InsertMediaIntoTrack(sqt.vTrack, 0, 0, (TimeValue) GetMediaDisplayDuration(sqt.vMedia), fixed1);
595 CheckError(err, 58);
596
597 CGImageRelease(sqt.srcImage);
598 CVPixelBufferPoolRelease(sqt.pool);
599 ICMCompressionSessionRelease(sqt.session);
600 ICMCompressionSessionOptionsRelease(sqt.option);
601
602 // sound
603
604 err = EndMediaEdits(sqt.sMedia);
605 CheckError(err, 54);
606
607 err = InsertMediaIntoTrack(sqt.sTrack, 0, 0, GetMediaDuration(sqt.sMedia), fixed1);
608 CheckError(err, 55);
609
610 DisposeHandle(sqt.soundBuffer);
611 DisposeHandle((Handle) sqt.soundDesc);
612
613 // storage
614
615 err = AddMovieToStorage(sqt.movie, sqt.dataHandler);
616 CheckError(err, 56);
617
618 MacQTCloseVideoComponent(sqt.vci);
619
620 err = CloseMovieStorage(sqt.dataHandler);
621 CheckError(err, 57);
622
623 DisposeHandle(sqt.dataRef);
624 DisposeMovie(sqt.movie);
625 }
626