OSDN Git Service

Fix PFR issue where there are different number of frames in 1st and 2nd pass.
[handbrake-jp/handbrake-jp-git.git] / macosx / HBAudio.m
1 //
2 //  HBAudio.m
3 //  HandBrake
4 //
5 //  Created on 2010-08-30.
6 //
7
8 #import "HBAudio.h"
9 #import "HBAudioController.h"
10 #import "hb.h"
11
12 NSString *keyAudioCodecName = @"keyAudioCodecName";
13 NSString *keyAudioMP4 = @"keyAudioMP4";
14 NSString *keyAudioMKV = @"keyAudioMKV";
15 NSString *keyAudioSampleRateName = @"keyAudioSampleRateName";
16 NSString *keyAudioBitrateName = @"keyAudioBitrateName";
17 NSString *keyAudioMustMatchTrack = @"keyAudioMustMatchTrack";
18 NSString *keyAudioMixdownName = @"keyAudioMixdownName";
19
20 NSString *keyAudioCodec = @"codec";
21 NSString *keyAudioMixdown = @"mixdown";
22 NSString *keyAudioSamplerate = @"samplerate";
23 NSString *keyAudioBitrate = @"bitrate";
24
25 static NSMutableArray *masterCodecArray = nil;
26 static NSMutableArray *masterMixdownArray = nil;
27 static NSMutableArray *masterSampleRateArray = nil;
28 static NSMutableArray *masterBitRateArray = nil;
29
30 @interface NSArray (HBAudioSupport)
31 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
32 - (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey;
33 @end
34 @implementation NSArray (HBAudioSupport)
35 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey reverse: (BOOL) reverse
36
37 {
38         NSDictionary *retval = nil;
39         NSEnumerator *enumerator = reverse ? [self reverseObjectEnumerator] : [self objectEnumerator];
40         NSDictionary *dict;
41         id aValue;
42         
43         while (nil != (dict = [enumerator nextObject]) && nil == retval) {
44                 if (nil != (aValue = [dict objectForKey: aKey]) && YES == [aValue isEqual: anObject]) {
45                         retval = dict;
46                 }
47         }
48         return retval;
49 }
50 - (NSDictionary *) dictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
51 {       return [self dictionaryWithObject: anObject matchingKey: aKey reverse: NO];     }
52 - (NSDictionary *) lastDictionaryWithObject: (id) anObject matchingKey: (NSString *) aKey
53 {       return [self dictionaryWithObject: anObject matchingKey: aKey reverse: YES];    }
54
55 @end
56
57 @implementation HBAudio
58
59 #pragma mark -
60 #pragma mark Object Setup
61
62 + (void) load
63
64 {
65         if ([HBAudio class] == self) {
66                 int i;
67                 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
68                 NSDictionary *dict;
69                 
70                 masterCodecArray = [[NSMutableArray alloc] init];       //      knowingly leaked
71                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
72                                                                           NSLocalizedString(@"AAC (CoreAudio)", @"AAC (CoreAudio)"), keyAudioCodecName,
73                                                                           [NSNumber numberWithInt: HB_ACODEC_CA_AAC], keyAudioCodec,
74                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
75                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
76                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
77                                                                           nil]];
78                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
79                                                                           NSLocalizedString(@"AAC (faac)", @"AAC (faac)"), keyAudioCodecName,
80                                                                           [NSNumber numberWithInt: HB_ACODEC_FAAC], keyAudioCodec,
81                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
82                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
83                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
84                                                                           nil]];
85                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
86                                                                           NSLocalizedString(@"MP3 (lame)", @"MP3 (lame)"), keyAudioCodecName,
87                                                                           [NSNumber numberWithInt: HB_ACODEC_LAME], keyAudioCodec,
88                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
89                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
90                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
91                                                                           nil]];
92                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
93                                                                           NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioCodecName,
94                                                                           [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioCodec,
95                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
96                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
97                                                                           [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioMustMatchTrack,
98                                                                           nil]];
99                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
100                                                                           NSLocalizedString(@"AC3", @"AC3"), keyAudioCodecName,
101                                                                           [NSNumber numberWithInt: HB_ACODEC_AC3], keyAudioCodec,
102                                                                           [NSNumber numberWithBool: YES], keyAudioMP4,
103                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
104                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
105                                                                           nil]];
106                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
107                                                                           NSLocalizedString(@"DTS Passthru", @"DTS Passthru"), keyAudioCodecName,
108                                                                           [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioCodec,
109                                                                           [NSNumber numberWithBool: NO], keyAudioMP4,
110                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
111                                                                           [NSNumber numberWithInt: HB_ACODEC_DCA], keyAudioMustMatchTrack,
112                                                                           nil]];
113                 [masterCodecArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
114                                                                           NSLocalizedString(@"Vorbis (vorbis)", @"Vorbis (vorbis)"), keyAudioCodecName,
115                                                                           [NSNumber numberWithInt: HB_ACODEC_VORBIS], keyAudioCodec,
116                                                                           [NSNumber numberWithBool: NO], keyAudioMP4,
117                                                                           [NSNumber numberWithBool: YES], keyAudioMKV,
118                                                                           [NSNumber numberWithBool: NO], keyAudioMustMatchTrack,
119                                                                           nil]];
120                 
121                 masterMixdownArray = [[NSMutableArray alloc] init];     //      knowingly leaked
122                 [masterMixdownArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
123                                                                                 NSLocalizedString(@"AC3 Passthru", @"AC3 Passthru"), keyAudioMixdownName,
124                                                                                 [NSNumber numberWithInt: HB_ACODEC_AC3_PASS], keyAudioMixdown,
125                                                                                 nil]];
126                 [masterMixdownArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
127                                                                                 NSLocalizedString(@"DTS Passthru", @"DTS Passthru"), keyAudioMixdownName,
128                                                                                 [NSNumber numberWithInt: HB_ACODEC_DCA_PASS], keyAudioMixdown,
129                                                                                 nil]];
130                 for (i = 0; i < hb_audio_mixdowns_count; i++) {
131                         [masterMixdownArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
132                                                                                         [NSString stringWithUTF8String: hb_audio_mixdowns[i].human_readable_name], keyAudioMixdownName,
133                                                                                         [NSNumber numberWithInt: hb_audio_mixdowns[i].amixdown], keyAudioMixdown,
134                                                                                         nil]];
135                 }
136
137                 //      Note that for the Auto value we use 0 for the sample rate because our controller will give back the track's
138                 //      input sample rate when it finds this 0 value as the selected sample rate.  We do this because the input
139                 //      sample rate depends on the track, which means it depends on the title, so cannot be nicely set up here.
140                 masterSampleRateArray = [[NSMutableArray alloc] init];  //      knowingly leaked
141                 [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
142                                                                                    NSLocalizedString(@"Auto", @"Auto"), keyAudioSampleRateName,
143                                                                                    [NSNumber numberWithInt: 0], keyAudioSamplerate,
144                                                                                    nil]];
145                 for (i = 0; i < hb_audio_rates_count; i++) {
146                         [masterSampleRateArray addObject: [NSDictionary dictionaryWithObjectsAndKeys:
147                                                                                            [NSString stringWithUTF8String: hb_audio_rates[i].string], keyAudioSampleRateName,
148                                                                                            [NSNumber numberWithInt: hb_audio_rates[i].rate], keyAudioSamplerate,
149                                                                                            nil]];
150                 }
151                 
152                 masterBitRateArray = [[NSMutableArray alloc] init];     // knowingly leaked
153                 for (i = 0; i < hb_audio_bitrates_count; i++) {
154                         dict = [NSDictionary dictionaryWithObjectsAndKeys:
155                                         [NSString stringWithUTF8String: hb_audio_bitrates[i].string], keyAudioBitrateName,
156                                         [NSNumber numberWithInt: hb_audio_bitrates[i].rate], keyAudioBitrate,
157                                         nil];
158                         [masterBitRateArray addObject: dict];
159                 }
160                 
161                 [pool release];
162         }
163         return;
164 }
165
166 //      Ensure the list of codecs is accurate
167 //      Update the current value of codec based on the revised list
168 - (void) updateCodecs
169
170 {
171         NSMutableArray *permittedCodecs = [NSMutableArray array];
172         unsigned int count = [masterCodecArray count];
173         NSDictionary *dict;
174         NSString *keyThatAllows = nil;
175
176         //      Determine which key we use to see which codecs are permitted
177         switch ([videoContainerTag intValue]) {
178                 case HB_MUX_MP4:
179                         keyThatAllows = keyAudioMP4;
180                         break;
181                 case HB_MUX_MKV:
182                         keyThatAllows = keyAudioMKV;
183                         break;
184                 default:
185                         keyThatAllows = @"error condition";
186                         break;
187         }
188
189         //      First get a list of the permitted codecs based on the internal rules
190         if (nil != track && YES == [self enabled]) {
191                 BOOL goodToAdd;
192
193                 for (unsigned int i = 0; i < count; i++) {
194                         dict = [masterCodecArray objectAtIndex: i];
195                         
196                         //      First make sure only codecs permitted by the container are here
197                         goodToAdd = [[dict objectForKey: keyThatAllows] boolValue];
198                         
199                         //      Now we make sure if DTS or AC3 is not available in the track it is not put in the codec list, but in a general way
200                         if (YES == [[dict objectForKey: keyAudioMustMatchTrack] boolValue]) {
201                                 if ([[dict objectForKey: keyAudioMustMatchTrack] intValue] != [[[self track] objectForKey: keyAudioInputCodec] intValue]) {
202                                         goodToAdd = NO;
203                                 }
204                         }
205                         
206                         if (YES == goodToAdd) {
207                                 [permittedCodecs addObject: dict];
208                         }
209                 }
210         }
211         
212         //      Now make sure the permitted list and the actual ones matches
213         [self setCodecs: permittedCodecs];
214
215         //      Ensure our codec is on the list of permitted codecs
216         if (nil == [self codec] || NO == [permittedCodecs containsObject: [self codec]]) {
217                 if (0 < [permittedCodecs count]) {
218                         [self setCodec: [permittedCodecs objectAtIndex: 0]];    //      This should be defaulting to Core Audio
219                 }
220                 else {
221                         [self setCodec: nil];
222                 }
223         }
224
225         return;
226 }
227
228 - (void) updateMixdowns: (BOOL) shouldSetDefault
229
230 {
231         NSMutableArray *permittedMixdowns = [NSMutableArray array];
232         NSDictionary *dict;
233         BOOL shouldAdd;
234         int currentMixdown;
235
236         unsigned int count = [masterMixdownArray count];
237         int codecCodec = [[codec objectForKey: keyAudioCodec] intValue];
238         int channelLayout = [[track objectForKey: keyAudioInputChannelLayout] intValue];
239         int theDefaultMixdown = hb_get_default_mixdown(codecCodec, channelLayout);
240         int theBestMixdown = hb_get_best_mixdown(codecCodec, channelLayout, 0);
241
242         for (unsigned int i = 0; i < count; i++) {
243                 dict = [masterMixdownArray objectAtIndex: i];
244                 currentMixdown = [[dict objectForKey: keyAudioMixdown] intValue];
245
246                 //      Basically with the way the mixdowns are stored, the assumption from the libhb point of view
247                 //      currently is that all mixdowns from the best down to mono are supported.
248                 if (currentMixdown <= theBestMixdown) {
249                         shouldAdd = YES;
250                 } else if (0 == theBestMixdown && codecCodec == currentMixdown) {
251                         // 0 means passthrough, add the current mixdown if it matches the passthrough codec
252                         shouldAdd = YES;
253                 } else {
254                         shouldAdd = NO;
255                 }
256
257                 if (YES == shouldAdd) {
258                         [permittedMixdowns addObject: dict];
259                 }
260         }
261
262         if (0 == theDefaultMixdown) {
263                 // a mixdown of 0 means passthrough
264                 theDefaultMixdown = codecCodec;
265         }
266
267         if (NO == [self enabled]) {
268                 permittedMixdowns = nil;
269         }
270
271         //      Now make sure the permitted list and the actual ones matches
272         [self setMixdowns: permittedMixdowns];
273
274         //      Select the proper one
275         if (YES == shouldSetDefault) {
276                 [self setMixdown: [permittedMixdowns dictionaryWithObject: [NSNumber numberWithInt: theDefaultMixdown] matchingKey: keyAudioMixdown]];
277         }
278
279         if (nil == [self mixdown] || NO == [permittedMixdowns containsObject: [self mixdown]]) {
280                 [self setMixdown: [permittedMixdowns lastObject]];
281         }
282
283         return;
284 }
285
286 - (void) updateBitRates: (BOOL) shouldSetDefault
287
288 {
289         NSMutableArray *permittedBitRates = [NSMutableArray array];
290         NSDictionary *dict;
291         int minBitRate;
292         int maxBitRate;
293         int currentBitRate;
294         BOOL shouldAdd;
295         
296         unsigned int count = [masterBitRateArray count];
297         int trackInputBitRate = [[[self track] objectForKey: keyAudioInputBitrate] intValue];
298         BOOL limitsToTrackInputBitRate = ([[codec objectForKey: keyAudioCodec] intValue] & HB_ACODEC_PASS_FLAG) ? YES : NO;
299         int theSampleRate = [[[self sampleRate] objectForKey: keyAudioSamplerate] intValue];
300                 
301         if (0 == theSampleRate) {       //      this means Auto
302                 theSampleRate = [[[self track] objectForKey: keyAudioInputSampleRate] intValue];
303                 }
304
305         int ourCodec = [[codec objectForKey: keyAudioCodec] intValue];
306         int ourMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
307         hb_get_audio_bitrate_limits(ourCodec, theSampleRate, ourMixdown, &minBitRate, &maxBitRate);
308         int theDefaultBitRate = hb_get_default_audio_bitrate(ourCodec, theSampleRate, ourMixdown);
309
310         for (unsigned int i = 0; i < count; i++) {
311                 dict = [masterBitRateArray objectAtIndex: i];
312                 currentBitRate = [[dict objectForKey: keyAudioBitrate] intValue];
313                 
314                 //      First ensure the bitrate falls within range of the codec
315                 shouldAdd = (currentBitRate >= minBitRate && currentBitRate <= maxBitRate);
316                 
317                 //      Now make sure the mixdown is not limiting us to the track input bitrate
318                 if (YES == shouldAdd && YES == limitsToTrackInputBitRate) {
319                         if (currentBitRate != trackInputBitRate) {
320                                 shouldAdd = NO;
321                         }
322                 }
323                                 
324                 if (YES == shouldAdd) {
325                         [permittedBitRates addObject: dict];
326                 }
327         }
328         
329         //      There is a situation where we have a mixdown requirement to match the track input bit rate,
330         //      but it does not fall into the range the codec supports.  Therefore, we force it here.
331         if (YES == limitsToTrackInputBitRate && 0 == [permittedBitRates count]) {
332                 NSDictionary *missingBitRate = [masterBitRateArray dictionaryWithObject: [NSNumber numberWithInt: trackInputBitRate] matchingKey: keyAudioBitrate];
333                 if (nil == missingBitRate) {
334                         //      We are in an even worse situation where the requested bit rate does not even exist in the underlying
335                         //      library of supported bitrates.  Of course since this value is ignored we can freely make a bogus one
336                         //      for the UI just to make the user a little more aware.
337                         missingBitRate = [NSDictionary dictionaryWithObjectsAndKeys:
338                                                           [NSString stringWithFormat: @"%d", trackInputBitRate], keyAudioBitrateName,
339                                                           [NSNumber numberWithInt: trackInputBitRate], keyAudioBitrate,
340                                                           nil];
341                         }
342                 [permittedBitRates addObject: missingBitRate];
343         }
344
345         if (NO == [self enabled]) {
346                 permittedBitRates = nil;
347         }
348
349         //      Make sure we are updated with the permitted list
350         [self setBitRates: permittedBitRates];
351
352         //      Select the proper one
353         if (YES == shouldSetDefault) {
354                 [self setBitRateFromName: [NSString stringWithFormat:@"%d", theDefaultBitRate]];
355                 }
356
357         if (nil == [self bitRate] || NO == [permittedBitRates containsObject: [self bitRate]]) {
358                 [self setBitRate: [permittedBitRates lastObject]];
359         }
360         
361         return;
362 }
363
364 - (id) init
365
366 {
367         if (self = [super init]) {
368                 [self addObserver: self forKeyPath: @"videoContainerTag" options: 0 context: NULL];
369                 [self addObserver: self forKeyPath: @"track" options: NSKeyValueObservingOptionOld context: NULL];
370                 [self addObserver: self forKeyPath: @"codec" options: 0 context: NULL];
371                 [self addObserver: self forKeyPath: @"mixdown" options: 0 context: NULL];
372                 [self addObserver: self forKeyPath: @"sampleRate" options: 0 context: NULL];
373                 }
374         return self;
375 }
376
377 #pragma mark -
378 #pragma mark Accessors
379
380 @synthesize track;
381 @synthesize codec;
382 @synthesize mixdown;
383 @synthesize sampleRate;
384 @synthesize bitRate;
385 @synthesize drc;
386 @synthesize videoContainerTag;
387 @synthesize controller;
388
389 @synthesize codecs;
390 @synthesize mixdowns;
391 @synthesize bitRates;
392
393 - (NSArray *) tracks    {       return [controller masterTrackArray];   }
394
395 - (NSArray *) sampleRates       {       return masterSampleRateArray;   }
396
397 - (void) dealloc
398
399 {
400         [self removeObserver: self forKeyPath: @"videoContainerTag"];
401         [self removeObserver: self forKeyPath: @"track"];
402         [self removeObserver: self forKeyPath: @"codec"];
403         [self removeObserver: self forKeyPath: @"mixdown"];
404         [self removeObserver: self forKeyPath: @"sampleRate"];
405         [self setTrack: nil];
406         [self setCodec: nil];
407         [self setMixdown: nil];
408         [self setSampleRate: nil];
409         [self setBitRate: nil];
410         [self setDrc: nil];
411         [self setVideoContainerTag: nil];
412         [self setCodecs: nil];
413         [self setMixdowns: nil];
414         [self setBitRates: nil];
415         [super dealloc];
416         return;
417 }
418
419 #pragma mark -
420 #pragma mark KVO
421
422 - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) object change: (NSDictionary *) change context: (void *) context
423
424 {
425         if (YES == [keyPath isEqualToString: @"videoContainerTag"]) {
426                 [self updateCodecs];
427                 }
428         else if (YES == [keyPath isEqualToString: @"track"]) {
429                 if (nil != [self track]) {
430                         [self updateCodecs];
431                         [self updateMixdowns: YES];
432                         if (YES == [self enabled]) {
433                                 [self setSampleRate: [[self sampleRates] objectAtIndex: 0]];    // default to Auto
434                                 }
435                         if (YES == [[controller noneTrack] isEqual: [change objectForKey: NSKeyValueChangeOldKey]]) {
436                                 [controller switchingTrackFromNone: self];
437                                 }
438                         if (YES == [[controller noneTrack] isEqual: [self track]]) {
439                                 [controller settingTrackToNone: self];
440                                 }
441                         }
442                 }
443         else if (YES == [keyPath isEqualToString: @"codec"]) {
444                 [self updateMixdowns: YES];
445                 [self updateBitRates: YES];
446                 }
447         else if (YES == [keyPath isEqualToString: @"mixdown"]) {
448                 [self updateBitRates: YES];
449                 [[NSNotificationCenter defaultCenter] postNotificationName: HBMixdownChangedNotification object: self];
450                 }
451         else if (YES == [keyPath isEqualToString: @"sampleRate"]) {
452                 [self updateBitRates: NO];
453                 }
454         return;
455 }
456
457 #pragma mark -
458 #pragma mark Special Setters
459
460 - (void) setTrackFromIndex: (int) aValue
461
462 {
463         [self setTrack: [[self tracks] dictionaryWithObject: [NSNumber numberWithInt: aValue] matchingKey: keyAudioTrackIndex]];
464         return;
465 }
466
467 //      This returns whether it is able to set the actual codec desired.
468 - (BOOL) setCodecFromName: (NSString *) aValue
469
470 {
471         NSDictionary *dict = [[self codecs] dictionaryWithObject: aValue matchingKey: keyAudioCodecName];
472         
473         if (nil != dict) {
474                 [self setCodec: dict];
475         }
476         return (nil != dict);
477 }
478
479 - (void) setMixdownFromName: (NSString *) aValue
480
481 {
482         NSDictionary *dict = [[self mixdowns] dictionaryWithObject: aValue matchingKey: keyAudioMixdownName];
483
484         if (nil != dict) {
485                 [self setMixdown: dict];
486         }
487         return;
488 }
489
490 - (void) setSampleRateFromName: (NSString *) aValue
491
492 {
493         NSDictionary *dict = [[self sampleRates] dictionaryWithObject: aValue matchingKey: keyAudioSampleRateName];
494         
495         if (nil != dict) {
496                 [self setSampleRate: dict];
497         }
498         return;
499 }
500
501 - (void) setBitRateFromName: (NSString *) aValue
502
503 {
504         NSDictionary *dict = [[self bitRates] dictionaryWithObject: aValue matchingKey: keyAudioBitrateName];
505         
506         if (nil != dict) {
507                 [self setBitRate: dict];
508         }
509         return;
510 }
511
512
513 #pragma mark -
514 #pragma mark Validation
515
516 //      Because we have indicated that the binding for the drc validates immediately we can implement the
517 //      key value binding method to ensure the drc stays in our accepted range.
518 - (BOOL) validateDrc: (id *) ioValue error: (NSError *) outError
519
520 {
521         BOOL retval = YES;
522         
523         if (nil != *ioValue) {
524                 if (0.0 < [*ioValue floatValue] && 1.0 > [*ioValue floatValue]) {
525                         *ioValue = [NSNumber numberWithFloat: 1.0];
526                 }
527         }
528         
529         return retval;
530 }
531
532 #pragma mark -
533 #pragma mark Bindings Support
534
535 - (BOOL) enabled
536
537 {
538         return (nil != track) ? (NO == [track isEqual: [controller noneTrack]]) : NO;
539 }
540
541 - (BOOL) mixdownEnabled
542
543 {
544         BOOL retval = [self enabled];
545
546         if (YES == retval) {
547                 int myMixdown = [[[self mixdown] objectForKey: keyAudioMixdown] intValue];
548                 if (HB_ACODEC_AC3_PASS == myMixdown || HB_ACODEC_DCA_PASS == myMixdown) {
549                         retval = NO;
550                 }
551         }
552         return retval;
553 }
554
555 - (BOOL) AC3Enabled
556
557 {
558         BOOL retval = [self enabled];
559         
560         if (YES == retval) {
561                 int myTrackCodec = [[[self track] objectForKey: keyAudioInputCodec] intValue];
562                 int myCodecCodec = [[[self codec] objectForKey: keyAudioCodec] intValue];
563                 if (HB_ACODEC_AC3 != myTrackCodec || HB_ACODEC_AC3_PASS == myCodecCodec) {
564                         retval = NO;
565                 }
566         }
567         return retval;
568 }
569
570 + (NSSet *) keyPathsForValuesAffectingValueForKey: (NSString *) key
571
572 {
573         NSSet *retval = nil;
574
575         if (YES == [key isEqualToString: @"enabled"]) {
576                 retval = [NSSet setWithObjects: @"track", nil];
577                 }
578         else if (YES == [key isEqualToString: @"AC3Enabled"]) {
579                 retval = [NSSet setWithObjects: @"track", @"codec", nil];
580         }
581         else if (YES == [key isEqualToString: @"mixdownEnabled"]) {
582                 retval = [NSSet setWithObjects: @"track", @"mixdown", nil];
583                 }
584         return retval;
585 }
586
587 @end