summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamiano Galassi <[email protected]>2016-05-03 18:47:14 +0200
committerDamiano Galassi <[email protected]>2016-05-03 18:47:14 +0200
commite53308f9342d911a9d3e8f4d1eeba6e53fabc0ab (patch)
treef65f5390d9174276022790a308660e17d7a3601f
parent4ab21a0ca630dc4bac79149a6eec598921899fe5 (diff)
MacGui: use AVFoundation as the first option for the preview playback. Add volume and tracks controls to the player hud.
-rw-r--r--macosx/English.lproj/HBPictureViewController.xib22
-rw-r--r--macosx/English.lproj/PicturePreview.xib252
-rw-r--r--macosx/HBAVPlayer.h28
-rw-r--r--macosx/HBAVPlayer.m367
-rw-r--r--macosx/HBEncodingProgressHUDController.h23
-rw-r--r--macosx/HBEncodingProgressHUDController.m63
-rw-r--r--macosx/HBEncodingProgressHUDController.xib46
-rw-r--r--macosx/HBHUD.h21
-rw-r--r--macosx/HBHUDButtonCell.m7
-rw-r--r--macosx/HBHUDView.m73
-rw-r--r--macosx/HBPictureHUDController.h30
-rw-r--r--macosx/HBPictureHUDController.m163
-rw-r--r--macosx/HBPictureHUDController.xib114
-rw-r--r--macosx/HBPlayer.h57
-rw-r--r--macosx/HBPlayerHUDController.h23
-rw-r--r--macosx/HBPlayerHUDController.m341
-rw-r--r--macosx/HBPlayerHUDController.xib152
-rw-r--r--macosx/HBPlayerTrack.h21
-rw-r--r--macosx/HBPlayerTrack.m22
-rw-r--r--macosx/HBPreviewController.m777
-rw-r--r--macosx/HBQTKitPlayer.h28
-rw-r--r--macosx/HBQTKitPlayer.m404
-rw-r--r--macosx/HandBrake.xcodeproj/project.pbxproj128
-rw-r--r--macosx/NSWindow+HBAdditions.h25
-rw-r--r--macosx/NSWindow+HBAdditions.m79
-rw-r--r--macosx/QTKit+HBQTMovieExtensions.h22
-rw-r--r--macosx/QTKit+HBQTMovieExtensions.m49
-rw-r--r--macosx/icons/NextTemplate.pdf (renamed from macosx/icons/next-p.pdf)bin2357 -> 2357 bytes
-rw-r--r--macosx/icons/PauseTemplate.pdf (renamed from macosx/icons/pause-p.pdf)bin2314 -> 2314 bytes
-rw-r--r--macosx/icons/PlayTemplate.pdf (renamed from macosx/icons/play-p.pdf)bin2316 -> 2316 bytes
-rw-r--r--macosx/icons/PrevTemplate.pdf (renamed from macosx/icons/prev-p.pdf)bin2356 -> 2356 bytes
-rw-r--r--macosx/icons/volHighTemplate.pdfbin0 -> 2701 bytes
-rw-r--r--macosx/icons/volLowTemplate.pdfbin0 -> 2633 bytes
33 files changed, 2389 insertions, 948 deletions
diff --git a/macosx/English.lproj/HBPictureViewController.xib b/macosx/English.lproj/HBPictureViewController.xib
index 9d12a5738..6c4b0686f 100644
--- a/macosx/English.lproj/HBPictureViewController.xib
+++ b/macosx/English.lproj/HBPictureViewController.xib
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10115" systemVersion="15E61b" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F24b" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<development version="6300" identifier="xcode"/>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10115"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="HBPictureViewController">
@@ -50,7 +50,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
<size key="cellSize" width="90" height="20"/>
<size key="intercellSpacing" width="2" height="3"/>
- <buttonCell key="prototype" type="radio" title="Radio" imagePosition="left" alignment="left" controlSize="small" inset="2" id="S7K-vF-t1n" customClass="HBHUDButtonCell">
+ <buttonCell key="prototype" type="radio" title="Radio" imagePosition="left" alignment="left" controlSize="small" inset="2" id="S7K-vF-t1n">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="smallSystem"/>
</buttonCell>
@@ -678,7 +678,7 @@ Players will scale the image in order to achieve the specified aspect.</string>
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="FwZ-6T-zJe">
<rect key="frame" x="151" y="281" width="15" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
- <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="NP7-P2-Qga">
+ <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="NP7-P2-Qga">
<font key="font" metaFont="smallSystem"/>
</stepperCell>
<connections>
@@ -952,7 +952,7 @@ Players will scale the image in order to achieve the specified aspect.</string>
<stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="2s0-5k-fjU">
<rect key="frame" x="240" y="281" width="15" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
- <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="MwK-aS-Oaf">
+ <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="MwK-aS-Oaf">
<font key="font" metaFont="smallSystem"/>
</stepperCell>
<connections>
@@ -1192,17 +1192,17 @@ If a deinterlace filter is enabled, only frames that this filter finds to be int
</popUpButtonCell>
<connections>
<accessibilityConnection property="title" destination="Mg1-Yq-F9S" id="nhI-oN-u5h"/>
- <binding destination="-2" name="contentValues" keyPath="self.filters.combDetectionSettings" id="lKn-uj-nGl"/>
- <binding destination="-2" name="selectedValue" keyPath="self.filters.combDetection" previousBinding="lKn-uj-nGl" id="XIZ-dC-cLu">
+ <binding destination="-2" name="enabled" keyPath="self.filters" id="mJ8-zq-tQ8">
<dictionary key="options">
- <string key="NSValueTransformerName">HBCombDetectionTransformer</string>
+ <string key="NSValueTransformerName">NSIsNotNil</string>
</dictionary>
</binding>
- <binding destination="-2" name="enabled" keyPath="self.filters" id="mJ8-zq-tQ8">
+ <binding destination="-2" name="selectedValue" keyPath="self.filters.combDetection" previousBinding="lKn-uj-nGl" id="XIZ-dC-cLu">
<dictionary key="options">
- <string key="NSValueTransformerName">NSIsNotNil</string>
+ <string key="NSValueTransformerName">HBCombDetectionTransformer</string>
</dictionary>
</binding>
+ <binding destination="-2" name="contentValues" keyPath="self.filters.combDetectionSettings" id="lKn-uj-nGl"/>
<outlet property="nextKeyView" destination="rPg-F2-gtl" id="46r-ZD-dTe"/>
</connections>
</popUpButton>
@@ -1216,12 +1216,12 @@ If a deinterlace filter is enabled, only frames that this filter finds to be int
</textFieldCell>
<accessibility description="Custom interlace detection settings."/>
<connections>
+ <binding destination="-2" name="value" keyPath="self.filters.combDetectionCustomString" id="pTK-PZ-3ZE"/>
<binding destination="-2" name="hidden" keyPath="self.filters.customCombDetectionSelected" id="avq-Zl-5gA">
<dictionary key="options">
<string key="NSValueTransformerName">NSNegateBoolean</string>
</dictionary>
</binding>
- <binding destination="-2" name="value" keyPath="self.filters.combDetectionCustomString" id="pTK-PZ-3ZE"/>
</connections>
</textField>
</subviews>
diff --git a/macosx/English.lproj/PicturePreview.xib b/macosx/English.lproj/PicturePreview.xib
index 77013fe9f..3550b20f6 100644
--- a/macosx/English.lproj/PicturePreview.xib
+++ b/macosx/English.lproj/PicturePreview.xib
@@ -1,28 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9052" systemVersion="15B30a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F24b" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<development version="6300" identifier="xcode"/>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9052"/>
- <plugIn identifier="com.apple.QTKitIBPlugin" version="9052"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="HBPreviewController">
<connections>
- <outlet property="fEncodingControlBox" destination="F8A-dU-Y1l" id="s29-SQ-WXg"/>
- <outlet property="fInfoField" destination="38" id="73"/>
- <outlet property="fMovieCreationProgressIndicator" destination="213" id="214"/>
- <outlet property="fMovieInfoField" destination="372" id="374"/>
- <outlet property="fMoviePlaybackControlBox" destination="COi-Ia-2yt" id="dcQ-Bp-1jG"/>
- <outlet property="fMovieScrubberSlider" destination="341" id="371"/>
- <outlet property="fMovieView" destination="207" id="208"/>
- <outlet property="fPictureControlBox" destination="2me-4k-EDi" id="ABj-KD-Z3U"/>
- <outlet property="fPictureSlider" destination="209" id="211"/>
- <outlet property="fPlayPauseButton" destination="361" id="364"/>
- <outlet property="fPreviewMovieLengthPopUp" destination="226" id="232"/>
- <outlet property="fPreviewMovieStatusField" destination="223" id="225"/>
- <outlet property="fScaleToScreenToggleButton" destination="275" id="yX0-fL-6J9"/>
- <outlet property="fscaleInfoField" destination="280" id="282"/>
<outlet property="previewView" destination="ooo-9X-9Al" id="als-Lt-aVz"/>
<outlet property="window" destination="5" id="184"/>
</connections>
@@ -41,235 +26,8 @@
<customView id="ooo-9X-9Al" customClass="HBPreviewView">
<rect key="frame" x="0.0" y="0.0" width="500" height="360"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <animations/>
- </customView>
- <qtMovieView preservesAspectRatio="YES" id="207">
- <rect key="frame" x="0.0" y="0.0" width="500" height="360"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <animations/>
- <color key="fillColor" red="0.80000000999999998" green="0.80000000999999998" blue="0.80000000999999998" alpha="1" colorSpace="calibratedRGB"/>
- </qtMovieView>
- <customView id="2me-4k-EDi" userLabel="Picture Controls" customClass="HBHUDView">
- <rect key="frame" x="20" y="136" width="460" height="100"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <subviews>
- <button toolTip="Encode And Play Back A Live Preview At Your Current Settings" verticalHuggingPriority="750" id="215">
- <rect key="frame" x="17" y="11" width="80" height="16"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <animations/>
- <buttonCell key="cell" type="push" title="Live Preview" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="216">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="miniSystem"/>
- </buttonCell>
- <connections>
- <action selector="createMoviePreview:" target="-2" id="218"/>
- </connections>
- </button>
- <button toolTip="Show Picture Settings Inspector" verticalHuggingPriority="750" id="271">
- <rect key="frame" x="378" y="11" width="61" height="16"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
- <animations/>
- <buttonCell key="cell" type="push" title="Settings" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="272">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="miniSystem"/>
- </buttonCell>
- <connections>
- <action selector="showPictureSettings:" target="-2" id="274"/>
- </connections>
- </button>
- <button toolTip="Scale Preview To Screen" verticalHuggingPriority="750" id="275">
- <rect key="frame" x="276" y="11" width="96" height="16"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
- <animations/>
- <buttonCell key="cell" type="push" title="Scale To Screen" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="276">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="miniSystem"/>
- </buttonCell>
- <connections>
- <action selector="toggleScaleToScreen:" target="-2" id="279"/>
- </connections>
- </button>
- <textField verticalHuggingPriority="750" id="234">
- <rect key="frame" x="105" y="14" width="48" height="11"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
- <animations/>
- <textFieldCell key="cell" controlSize="mini" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Duration:" id="235">
- <font key="font" metaFont="miniSystemBold"/>
- <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" id="q81-Om-Azd">
- <rect key="frame" x="211" y="14" width="21" height="11"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
- <animations/>
- <textFieldCell key="cell" controlSize="mini" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="sec" id="APs-l9-qFj">
- <font key="font" metaFont="miniSystemBold"/>
- <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <popUpButton toolTip="Select The Length Of Live Preview to Encode" verticalHuggingPriority="750" id="226">
- <rect key="frame" x="158" y="12" width="49" height="15"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
- <animations/>
- <popUpButtonCell key="cell" type="push" title="240" bezelStyle="rounded" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" selectedItem="231" id="227">
- <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="miniSystem"/>
- <menu key="menu" title="OtherViews" id="228">
- <items>
- <menuItem title="240" state="on" id="231"/>
- </items>
- </menu>
- </popUpButtonCell>
- <connections>
- <action selector="previewDurationPopUpChanged:" target="-2" id="233"/>
- </connections>
- </popUpButton>
- <slider verticalHuggingPriority="750" id="209">
- <rect key="frame" x="18" y="39" width="420" height="16"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
- <animations/>
- <sliderCell key="cell" controlSize="mini" continuous="YES" alignment="left" maxValue="9" tickMarkPosition="above" numberOfTickMarks="10" allowsTickMarkValuesOnly="YES" sliderType="linear" id="210">
- <font key="font" metaFont="miniSystem"/>
- </sliderCell>
- <connections>
- <action selector="pictureSliderChanged:" target="-2" id="212"/>
- </connections>
- </slider>
- <textField verticalHuggingPriority="750" id="38">
- <rect key="frame" x="15" y="55" width="430" height="20"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
- <animations/>
- <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" alignment="left" id="165">
- <font key="font" metaFont="smallSystemBold"/>
- <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" id="280">
- <rect key="frame" x="15" y="77" width="426" height="12"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
- <animations/>
- <textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" alignment="left" id="281">
- <font key="font" metaFont="miniSystemBold"/>
- <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- </subviews>
- <animations/>
- </customView>
- <customView hidden="YES" id="COi-Ia-2yt" userLabel="Playback Controls" customClass="HBHUDView">
- <rect key="frame" x="20" y="32" width="460" height="100"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <subviews>
- <slider verticalHuggingPriority="750" id="341">
- <rect key="frame" x="18" y="17" width="337" height="21"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
- <animations/>
- <sliderCell key="cell" continuous="YES" alignment="left" maxValue="100" tickMarkPosition="above" sliderType="linear" id="346"/>
- <connections>
- <action selector="previewScrubberChanged:" target="-2" id="384"/>
- </connections>
- </slider>
- <button toolTip="Toggle Play/Pause" id="361">
- <rect key="frame" x="207" y="44" width="36" height="36"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
- <animations/>
- <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="play-p" imagePosition="only" alignment="center" alternateImage="pause-p" imageScaling="proportionallyDown" id="362">
- <behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="toggleMoviePreviewPlayPause:" target="-2" id="370"/>
- </connections>
- </button>
- <button toolTip="Go To Beginning" id="375">
- <rect key="frame" x="165" y="49" width="32" height="26"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
- <animations/>
- <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="prev-p" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" id="376">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="moviePlaybackGoToBeginning:" target="-2" id="382"/>
- </connections>
- </button>
- <button toolTip="Go To End" id="378">
- <rect key="frame" x="253" y="49" width="32" height="26"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
- <animations/>
- <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="next-p" imagePosition="only" alignment="center" controlSize="mini" imageScaling="proportionallyDown" id="379">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="miniSystem"/>
- </buttonCell>
- <connections>
- <action selector="moviePlaybackGoToEnd:" target="-2" id="383"/>
- </connections>
- </button>
- <button toolTip="Show Still Previews" verticalHuggingPriority="750" id="365">
- <rect key="frame" x="350" y="54" width="81" height="16"/>
- <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <animations/>
- <buttonCell key="cell" type="push" title="Still Previews" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="366">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="miniSystem"/>
- </buttonCell>
- <connections>
- <action selector="showPicturesPreview:" target="-2" id="396"/>
- </connections>
- </button>
- <textField verticalHuggingPriority="750" id="372">
- <rect key="frame" x="349" y="20" width="94" height="14"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
- <animations/>
- <textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" alignment="right" title="00:00:00" id="373">
- <font key="font" metaFont="smallSystemBold"/>
- <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- </subviews>
- <animations/>
- </customView>
- <customView hidden="YES" id="F8A-dU-Y1l" userLabel="Encoding Controls" customClass="HBHUDView">
- <rect key="frame" x="20" y="240" width="460" height="100"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
- <subviews>
- <textField verticalHuggingPriority="750" id="223">
- <rect key="frame" x="17" y="60" width="425" height="14"/>
- <autoresizingMask key="autoresizingMask"/>
- <animations/>
- <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Preparing Preview" id="224">
- <font key="font" metaFont="smallSystemBold"/>
- <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
- <color key="backgroundColor" red="0.90196085000000004" green="0.90196085000000004" blue="0.90196085000000004" alpha="0.0" colorSpace="deviceRGB"/>
- </textFieldCell>
- </textField>
- <progressIndicator verticalHuggingPriority="750" maxValue="1" bezeled="NO" indeterminate="YES" controlSize="small" style="bar" id="213">
- <rect key="frame" x="20" y="27" width="346" height="12"/>
- <autoresizingMask key="autoresizingMask"/>
- <animations/>
- </progressIndicator>
- <button toolTip="Cancel Live Preview Encode" verticalHuggingPriority="750" id="261">
- <rect key="frame" x="383" y="25" width="58" height="16"/>
- <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
- <animations/>
- <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="262">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="miniSystem"/>
- </buttonCell>
- <connections>
- <action selector="cancelCreateMoviePreview:" target="-2" id="395"/>
- </connections>
- </button>
- </subviews>
- <animations/>
</customView>
</subviews>
- <animations/>
</view>
<connections>
<outlet property="delegate" destination="-2" id="7iq-HC-WuX"/>
@@ -277,10 +35,4 @@
<point key="canvasLocation" x="-182" y="-40"/>
</window>
</objects>
- <resources>
- <image name="next-p" width="48" height="48"/>
- <image name="pause-p" width="48" height="48"/>
- <image name="play-p" width="48" height="48"/>
- <image name="prev-p" width="48" height="48"/>
- </resources>
</document>
diff --git a/macosx/HBAVPlayer.h b/macosx/HBAVPlayer.h
new file mode 100644
index 000000000..d8593efc4
--- /dev/null
+++ b/macosx/HBAVPlayer.h
@@ -0,0 +1,28 @@
+/* HBAVPlayer.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Foundation/Foundation.h>
+#import <QuartzCore/QuartzCore.h>
+
+#import "HBPlayer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface HBAVPlayer : NSObject <HBPlayer>
+
+@property (nonatomic, readonly) CALayer *layer;
+
+@property (nonatomic, readonly) NSTimeInterval duration;
+@property (nonatomic) NSTimeInterval currentTime;
+
+@property (nonatomic) float rate;
+@property (nonatomic) float volume;
+
+@property (nonatomic, readonly, getter=isPlayable) BOOL playable;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/macosx/HBAVPlayer.m b/macosx/HBAVPlayer.m
new file mode 100644
index 000000000..ef72734c2
--- /dev/null
+++ b/macosx/HBAVPlayer.m
@@ -0,0 +1,367 @@
+/* HBAVPlayer.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import "HBAVPlayer.h"
+
+@import AVFoundation;
+@import HandBrakeKit;
+
+static void *HBAVPlayerRateContext = &HBAVPlayerRateContext;
+static void *HBAVPlayerItemStatusContext = &HBAVPlayerItemStatusContext;
+
+typedef void (^HBRateObverser)(void);
+typedef void (^HBPlayableObverser)(void);
+
+@interface HBAVPlayerRateObserver : NSObject
+
+@property (nonatomic) HBRateObverser block;
+
+- (void)postNotification;
+
+@end
+
+@implementation HBAVPlayerRateObserver
+
+- (void)postNotification;
+{
+ self.block();
+}
+
+@end
+
+@interface HBAVPlayer ()
+
+@property (nonatomic, strong) AVAsset *movie;
+@property (nonatomic, strong) AVPlayer *player;
+
+@property (nonatomic, strong) NSMutableSet<HBAVPlayerRateObserver *> *rateObservers;
+@property (nonatomic, strong) NSMutableSet<HBPlayableObverser> *playableObservers;
+
+@property (nonatomic, readwrite) BOOL playable;
+
+@end
+
+@implementation HBAVPlayer
+
+- (instancetype)initWithURL:(NSURL *)url
+{
+ self = [super init];
+
+ if (self)
+ {
+ _movie = [AVAsset assetWithURL:url];;
+
+ if (!_movie)
+ {
+ return nil;
+ }
+
+ _player = [[AVPlayer alloc] init];
+ _layer = [CALayer layer];
+
+ if (!_layer || !_player)
+ {
+ return nil;
+ }
+
+ _rateObservers = [NSMutableSet set];
+ _playableObservers = [NSMutableSet set];
+
+ [self addObserver:self forKeyPath:@"player.rate" options:NSKeyValueObservingOptionNew context:HBAVPlayerRateContext];
+ [self addObserver:self forKeyPath:@"player.currentItem.status" options:NSKeyValueObservingOptionNew context:HBAVPlayerItemStatusContext];
+
+ NSArray *assetKeysToLoadAndTest = @[@"playable"];
+ [_movie loadValuesAsynchronouslyForKeys:assetKeysToLoadAndTest completionHandler:^(void) {
+
+ // The asset invokes its completion handler on an arbitrary queue when loading is complete.
+ // Because we want to access our AVPlayer in our ensuing set-up, we must dispatch our handler to the main queue.
+ dispatch_async(dispatch_get_main_queue(), ^(void) {
+ [self _setUpPlaybackOfAsset:_movie withKeys:assetKeysToLoadAndTest];
+ });
+
+ }];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ @try
+ {
+ [self removeObserver:self forKeyPath:@"player.rate"];
+ [self removeObserver:self forKeyPath:@"player.currentItem.status"];
+ }
+ @catch (NSException *exception) {}
+}
+
+- (void)_setUpPlaybackOfAsset:(AVAsset *)asset withKeys:(NSArray *)keys
+{
+ // First test whether the values of each of the keys we need have been successfully loaded.
+ for (NSString *key in keys)
+ {
+ NSError *error = nil;
+
+ if ([asset statusOfValueForKey:key error:&error] == AVKeyValueStatusFailed)
+ {
+ self.playable = NO;
+ return;
+ }
+
+ if (!asset.isPlayable)
+ {
+ self.playable = NO;
+ return;
+ }
+
+ AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
+ [self.player replaceCurrentItemWithPlayerItem:playerItem];
+
+ AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
+ playerLayer.frame = self.layer.bounds;
+ playerLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
+
+ [self.layer addSublayer:playerLayer];
+ }
+}
+
+- (void)setPlayable:(BOOL)playable
+{
+ _playable = playable;
+
+ for (HBPlayableObverser block in self.playableObservers)
+ {
+ block();
+ }
+ [self.playableObservers removeAllObjects];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+ if (context == HBAVPlayerItemStatusContext)
+ {
+ AVPlayerStatus status = [change[NSKeyValueChangeNewKey] integerValue];
+ switch (status)
+ {
+ case AVPlayerItemStatusUnknown:
+ break;
+ case AVPlayerItemStatusReadyToPlay:
+ self.playable = YES;
+ break;
+ case AVPlayerItemStatusFailed:
+ self.playable = YES;
+ break;
+ }
+
+ }
+ else if (context == HBAVPlayerRateContext)
+ {
+ for (HBAVPlayerRateObserver *observer in self.rateObservers)
+ {
+ [observer postNotification];
+ }
+ }
+ else
+ {
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+ }
+}
+
+#pragma mark Public properties
+
+- (NSArray<HBPlayerTrack *> *)tracksWithMediaType:(NSString *)mediaType
+{
+ NSMutableArray *result = [NSMutableArray array];
+ NSArray<AVPlayerItemTrack *> *tracks = self.player.currentItem.tracks;
+
+ for (AVPlayerItemTrack *track in tracks)
+ {
+ AVAssetTrack *assetTrack = track.assetTrack;
+ if ([assetTrack.mediaType isEqualToString:mediaType])
+ {
+ NSString *name = [HBUtilities languageCodeForIso6392Code:assetTrack.languageCode];
+ HBPlayerTrack *playerTrack = [[HBPlayerTrack alloc] initWithTrackName:name object:@(assetTrack.trackID) enabled:track.isEnabled];
+ [result addObject:playerTrack];
+ }
+ }
+ return result;
+}
+
+@synthesize audioTracks = _audioTracks;
+
+- (NSArray<HBPlayerTrack *> *)audioTracks
+{
+ if (_audioTracks == nil)
+ {
+ _audioTracks = [self tracksWithMediaType:AVMediaTypeAudio];
+ }
+ return _audioTracks;
+}
+
+@synthesize subtitlesTracks = _subtitlesTracks;
+
+- (NSArray<HBPlayerTrack *> *)subtitlesTracks
+{
+ if (_subtitlesTracks == nil)
+ {
+ _subtitlesTracks = [self tracksWithMediaType:AVMediaTypeSubtitle];
+ }
+ return _subtitlesTracks;
+}
+
+- (void)_enableTrack:(HBPlayerTrack *)playerTrack mediaType:(NSString *)mediaType
+{
+ NSArray<AVPlayerItemTrack *> *tracks = self.player.currentItem.tracks;
+ for (AVPlayerItemTrack *track in tracks)
+ {
+ if ([track.assetTrack.mediaType isEqualToString:mediaType])
+ {
+ if (track.assetTrack.trackID == [playerTrack.representedObject integerValue])
+ {
+ track.enabled = YES;
+ }
+ else
+ {
+ track.enabled = NO;
+ }
+ }
+ }
+}
+
+- (void)enableAudioTrack:(HBPlayerTrack *)playerTrack
+{
+ for (HBPlayerTrack *track in self.audioTracks)
+ {
+ track.enabled = NO;
+ }
+ playerTrack.enabled = YES;
+ [self _enableTrack:playerTrack mediaType:AVMediaTypeAudio];
+}
+
+- (void)enableSubtitlesTrack:(HBPlayerTrack *)playerTrack
+{
+ for (HBPlayerTrack *track in self.subtitlesTracks)
+ {
+ track.enabled = NO;
+ }
+ playerTrack.enabled = YES;
+ [self _enableTrack:playerTrack mediaType:AVMediaTypeSubtitle];
+}
+
+- (NSTimeInterval)duration
+{
+ return CMTimeGetSeconds(self.movie.duration);
+}
+
+- (NSTimeInterval)currentTime
+{
+ return CMTimeGetSeconds(self.player.currentTime);
+}
+
+- (void)setCurrentTime:(NSTimeInterval)value
+{
+ [self.player seekToTime:CMTimeMake((int64_t)(value * 1000), 1000) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
+}
+
+- (void)setRate:(float)rate
+{
+ self.player.rate = rate;
+}
+
+- (float)rate
+{
+ return self.player.rate;
+}
+
+- (float)volume
+{
+ return self.player.volume;
+}
+
+- (void)setVolume:(float)volume
+{
+ self.player.volume = volume;
+}
+
+#pragma mark public methods
+
+- (void)loadPlayableValueAsynchronouslyWithCompletionHandler:(nullable void (^)(void))handler;
+{
+ if (self.playable)
+ {
+ handler();
+ }
+ else
+ {
+ [self.playableObservers addObject:handler];
+ }
+}
+
+- (id)addPeriodicTimeObserverUsingBlock:(void (^)(NSTimeInterval time))block
+{
+ CMTime interval = CMTimeMake(100, 1000);
+
+ id observer = [self.player addPeriodicTimeObserverForInterval:interval queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
+ block(0);
+ }];
+
+ return observer;
+}
+
+- (void)removeTimeObserver:(id)observer
+{
+ [self.player removeTimeObserver:observer];
+}
+
+- (id)addRateObserverUsingBlock:(void (^)(void))block
+{
+ HBAVPlayerRateObserver *observer = [[HBAVPlayerRateObserver alloc] init];
+ observer.block = block;
+ [self.rateObservers addObject:observer];
+
+ return observer;
+}
+
+- (void)removeRateObserver:(id)observer
+{
+ [self.rateObservers removeObject:observer];
+}
+
+- (void)play
+{
+ [self.player play];
+}
+
+- (void)pause
+{
+ [self.player pause];
+}
+
+- (void)gotoBeginning
+{
+ [self.player seekToTime:kCMTimeZero toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
+}
+
+- (void)gotoEnd
+{
+ [self.player seekToTime:self.player.currentItem.duration toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
+}
+
+- (void)stepForward
+{
+ CMTime frameTime = CMTimeMakeWithSeconds(1.0/30.0, self.player.currentItem.duration.timescale);
+ CMTime forwardTime = CMTimeAdd([self.player.currentItem currentTime], frameTime);
+ [self.player seekToTime:forwardTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
+}
+
+- (void)stepBackward
+{
+ CMTime frameTime = CMTimeMakeWithSeconds(-1.0/30.0, self.player.currentItem.duration.timescale);
+ CMTime backwardTime = CMTimeAdd([self.player.currentItem currentTime], frameTime);
+ [self.player seekToTime:backwardTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
+}
+
+@end
diff --git a/macosx/HBEncodingProgressHUDController.h b/macosx/HBEncodingProgressHUDController.h
new file mode 100644
index 000000000..e147d09c4
--- /dev/null
+++ b/macosx/HBEncodingProgressHUDController.h
@@ -0,0 +1,23 @@
+/* HBEncodingProgressHUDController.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Cocoa/Cocoa.h>
+#import "HBHUD.h"
+
+@protocol HBEncodingProgressHUDControllerDelegate <NSObject>
+
+- (void)cancelEncoding;
+
+@end
+
+@interface HBEncodingProgressHUDController : NSViewController <HBHUD>
+
+@property (nonatomic, nullable, assign) id<HBEncodingProgressHUDControllerDelegate> delegate;
+
+@property (nonatomic, nonnull) NSString *info;
+@property (nonatomic) double progress;
+
+@end
diff --git a/macosx/HBEncodingProgressHUDController.m b/macosx/HBEncodingProgressHUDController.m
new file mode 100644
index 000000000..4ac16e1ea
--- /dev/null
+++ b/macosx/HBEncodingProgressHUDController.m
@@ -0,0 +1,63 @@
+/* HBEncodingProgressHUDController.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import "HBEncodingProgressHUDController.h"
+
+@interface HBEncodingProgressHUDController ()
+
+@property (weak) IBOutlet NSProgressIndicator *progressIndicator;
+@property (weak) IBOutlet NSTextField *infoLabel;
+
+@end
+
+@implementation HBEncodingProgressHUDController
+
+- (NSString *)nibName
+{
+ return @"HBEncodingProgressHUDController";
+}
+
+- (void)loadView
+{
+ [super loadView];
+
+ if (NSClassFromString(@"NSVisualEffectView") == NO)
+ {
+ self.infoLabel.textColor = [NSColor whiteColor];
+ }
+}
+
+- (BOOL)canBeHidden
+{
+ return NO;
+}
+
+- (void)setInfo:(NSString *)info
+{
+ self.infoLabel.stringValue = info;
+}
+
+- (void)setProgress:(double)progress
+{
+ self.progressIndicator.doubleValue = progress;
+}
+
+- (IBAction)cancelEncoding:(id)sender
+{
+ [self.delegate cancelEncoding];
+}
+
+- (BOOL)HB_keyDown:(NSEvent *)event
+{
+ return NO;
+}
+
+- (BOOL)HB_scrollWheel:(NSEvent *)theEvent
+{
+ return NO;
+}
+
+@end
diff --git a/macosx/HBEncodingProgressHUDController.xib b/macosx/HBEncodingProgressHUDController.xib
new file mode 100644
index 000000000..6f3f919ed
--- /dev/null
+++ b/macosx/HBEncodingProgressHUDController.xib
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F28b" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+ <dependencies>
+ <deployment identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="HBEncodingProgressHUDController">
+ <connections>
+ <outlet property="infoLabel" destination="eKh-n7-BCx" id="Ekf-s1-gAB"/>
+ <outlet property="progressIndicator" destination="oJT-Rc-VeH" id="09U-Ur-Aru"/>
+ <outlet property="view" destination="Bz7-r6-NCQ" id="hXI-Gx-WVV"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+ <customView hidden="YES" id="Bz7-r6-NCQ" userLabel="Encoding Controls" customClass="HBHUDView">
+ <rect key="frame" x="0.0" y="0.0" width="460" height="100"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <subviews>
+ <progressIndicator verticalHuggingPriority="750" fixedFrame="YES" maxValue="1" bezeled="NO" controlSize="small" style="bar" translatesAutoresizingMaskIntoConstraints="NO" id="oJT-Rc-VeH">
+ <rect key="frame" x="20" y="27" width="346" height="12"/>
+ </progressIndicator>
+ <button toolTip="Cancel Live Preview Encode" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SEa-H6-T26">
+ <rect key="frame" x="383" y="25" width="58" height="16"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Ha0-iE-RLa">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="miniSystem"/>
+ </buttonCell>
+ <connections>
+ <action selector="cancelEncoding:" target="-2" id="XDk-r6-Ihc"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eKh-n7-BCx">
+ <rect key="frame" x="17" y="60" width="425" height="14"/>
+ <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="Preparing Preview" id="tM8-gj-kBo">
+ <font key="font" metaFont="smallSystemBold"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" red="0.90196085000000004" green="0.90196085000000004" blue="0.90196085000000004" alpha="0.0" colorSpace="deviceRGB"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <point key="canvasLocation" x="55" y="349"/>
+ </customView>
+ </objects>
+</document>
diff --git a/macosx/HBHUD.h b/macosx/HBHUD.h
new file mode 100644
index 000000000..d10e42f69
--- /dev/null
+++ b/macosx/HBHUD.h
@@ -0,0 +1,21 @@
+/* HBHUD.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+#import <Foundation/Foundation.h>
+
+@protocol HBHUD <NSObject>
+
+/// Whether the hud can be hidden or not;
+- (BOOL)canBeHidden;
+
+// Responder chains is nice and good, but NSViewController
+// are not automatically insterted in the responder chain prior 10.10
+// and are removed when the view is hidden, so let's deliver the
+// events manually.
+
+- (BOOL)HB_keyDown:(NSEvent *)event;
+- (BOOL)HB_scrollWheel:(NSEvent *)theEvent;
+
+@end
diff --git a/macosx/HBHUDButtonCell.m b/macosx/HBHUDButtonCell.m
index 3464a7499..a5e4119ec 100644
--- a/macosx/HBHUDButtonCell.m
+++ b/macosx/HBHUDButtonCell.m
@@ -10,9 +10,14 @@
- (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView
{
- NSAttributedString *attrLabel = [[NSAttributedString alloc] initWithString:[title string]
+ NSAttributedString *attrLabel = title;
+
+ if (!NSClassFromString(@"NSVisualEffectView"))
+ {
+ attrLabel = [[NSAttributedString alloc] initWithString:[title string]
attributes:@{ NSFontAttributeName:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:self.controlSize]],
NSForegroundColorAttributeName: [NSColor whiteColor]}];
+ }
return [super drawTitle:attrLabel withFrame:frame inView:controlView];
}
diff --git a/macosx/HBHUDView.m b/macosx/HBHUDView.m
index e4030f743..1d6079d96 100644
--- a/macosx/HBHUDView.m
+++ b/macosx/HBHUDView.m
@@ -6,37 +6,37 @@
#import "HBHUDView.h"
-@implementation HBHUDView
+@interface HBHUDVisualEffectsView : NSVisualEffectView
+@end
+
+@implementation HBHUDVisualEffectsView
-+ (void)setupNewStyleHUD:(NSVisualEffectView *)view
+- (instancetype)initWithFrame:(NSRect)frame
{
- [view setWantsLayer:YES];
- [view.layer setCornerRadius:4];
+ self = [super initWithFrame:frame];
- [view setBlendingMode:NSVisualEffectBlendingModeWithinWindow];
- [view setMaterial:NSVisualEffectMaterialDark];
- [view setState:NSVisualEffectStateActive];
+ if (self)
+ {
+ self.wantsLayer = YES;
+ self.layer.cornerRadius = 4;
+
+ self.blendingMode = NSVisualEffectBlendingModeWithinWindow;
+ self.material = NSVisualEffectMaterialDark;
+ self.state = NSVisualEffectStateActive;
- [view setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]];
+ self.appearance = [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark];
+ }
+ return self;
}
-- (void)drawRect:(NSRect)dirtyRect
+- (BOOL)acceptsFirstResponder
{
- NSGraphicsContext *theContext = [NSGraphicsContext currentContext];
- [theContext saveGraphicsState];
-
- NSRect rect = NSMakeRect(0.0, 0.0, [self frame].size.width, [self frame].size.height);
-
- // Draw a standard HUD with black transparent background and white border.
- [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.6] setFill];
- [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(rect, 1, 1) xRadius:14.0 yRadius:14.0] fill];
+ return YES;
+}
- [[NSColor whiteColor] setStroke];
- [NSBezierPath setDefaultLineWidth:2.0];
- [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(rect, 1, 1) xRadius:14.0 yRadius:14.0] stroke];
+@end
- [theContext restoreGraphicsState];
-}
+@implementation HBHUDView
- (instancetype)initWithFrame:(NSRect)frame
{
@@ -44,11 +44,7 @@
{
// If NSVisualEffectView class is loaded
// release ourself and return a NSVisualEffectView instance instead.
- self = [[NSClassFromString(@"NSVisualEffectView") alloc] initWithFrame:frame];
- if (self)
- {
- [HBHUDView setupNewStyleHUD:(NSVisualEffectView *)self];
- }
+ self = (HBHUDView *)[[HBHUDVisualEffectsView alloc] initWithFrame:frame];
}
else
{
@@ -58,4 +54,27 @@
return self;
}
+- (BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+- (void)drawRect:(NSRect)dirtyRect
+{
+ NSGraphicsContext *theContext = [NSGraphicsContext currentContext];
+ [theContext saveGraphicsState];
+
+ NSRect rect = NSMakeRect(0.0, 0.0, self.frame.size.width, self.frame.size.height);
+
+ // Draw a standard HUD with black transparent background and white border.
+ [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:0.6] setFill];
+ [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(rect, 1, 1) xRadius:14.0 yRadius:14.0] fill];
+
+ [[NSColor whiteColor] setStroke];
+ [NSBezierPath setDefaultLineWidth:2.0];
+ [[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(rect, 1, 1) xRadius:14.0 yRadius:14.0] stroke];
+
+ [theContext restoreGraphicsState];
+}
+
@end \ No newline at end of file
diff --git a/macosx/HBPictureHUDController.h b/macosx/HBPictureHUDController.h
new file mode 100644
index 000000000..1a11d2063
--- /dev/null
+++ b/macosx/HBPictureHUDController.h
@@ -0,0 +1,30 @@
+/* HBPictureHUDController.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+//
+
+#import <Cocoa/Cocoa.h>
+#import "HBHUD.h"
+
+@protocol HBPictureHUDControllerDelegate <NSObject>
+
+- (void)displayPreviewAtIndex:(NSUInteger)idx;
+- (void)toggleScaleToScreen;
+- (void)showPictureSettings;
+- (void)createMoviePreviewWithPictureIndex:(NSUInteger)index duration:(NSUInteger)duration;
+
+@end
+
+@interface HBPictureHUDController : NSViewController <HBHUD>
+
+@property (nonatomic, nullable, assign) id<HBPictureHUDControllerDelegate> delegate;
+
+@property (nonatomic, nonnull) NSString *info;
+@property (nonatomic, nonnull) NSString *scale;
+
+@property (nonatomic) NSUInteger pictureCount;
+@property (nonatomic) NSUInteger selectedIndex;
+
+@end
diff --git a/macosx/HBPictureHUDController.m b/macosx/HBPictureHUDController.m
new file mode 100644
index 000000000..741e6d008
--- /dev/null
+++ b/macosx/HBPictureHUDController.m
@@ -0,0 +1,163 @@
+/* HBPictureHUDController.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import "HBPictureHUDController.h"
+
+@interface HBPictureHUDController ()
+
+@property (weak) IBOutlet NSTextField *scaleLabel;
+@property (weak) IBOutlet NSTextField *infoLabel;
+
+@property (weak) IBOutlet NSSlider *slider;
+
+@property (weak) IBOutlet NSPopUpButton *durationPopUp;
+@property (weak) IBOutlet NSButton *scaleToScreenButton;
+
+@property (nonatomic) BOOL fitToView;
+
+@end
+
+@implementation HBPictureHUDController
+
+- (NSString *)nibName
+{
+ return @"HBPictureHUDController";
+}
+
+- (void)loadView
+{
+ [super loadView];
+
+ if (NSClassFromString(@"NSVisualEffectView") == NO)
+ {
+ self.scaleLabel.textColor = [NSColor whiteColor];
+ self.infoLabel.textColor = [NSColor whiteColor];
+ }
+
+ // we set the preview length popup in seconds
+ [self.durationPopUp removeAllItems];
+ [self.durationPopUp addItemsWithTitles:@[@"15", @"30", @"45", @"60", @"90",
+ @"120", @"150", @"180", @"210", @"240"]];
+
+ if ([[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"])
+ {
+ [self.durationPopUp selectItemWithTitle:[[NSUserDefaults standardUserDefaults]
+ objectForKey:@"PreviewLength"]];
+ }
+ if (!self.durationPopUp.selectedItem)
+ {
+ // currently hard set default to 15 seconds
+ [self.durationPopUp selectItemAtIndex:0];
+ }
+}
+
+- (BOOL)canBeHidden
+{
+ return YES;
+}
+
+- (void)setPictureCount:(NSUInteger)pictureCount
+{
+ self.slider.numberOfTickMarks = pictureCount;
+ self.slider.maxValue = pictureCount - 1;
+
+ if (self.selectedIndex > pictureCount)
+ {
+ self.selectedIndex = pictureCount - 1;
+ }
+}
+
+- (NSUInteger)selectedIndex
+{
+ return self.slider.integerValue;
+}
+
+- (void)setSelectedIndex:(NSUInteger)selectedIndex
+{
+ self.slider.integerValue = selectedIndex;
+}
+
+- (void)setInfo:(NSString *)info
+{
+ self.infoLabel.stringValue = info;
+}
+
+- (void)setScale:(NSString *)scale
+{
+ self.scaleLabel.stringValue = scale;
+}
+
+- (IBAction)previewDurationPopUpChanged:(id)sender
+{
+ [[NSUserDefaults standardUserDefaults] setObject:self.durationPopUp.titleOfSelectedItem forKey:@"PreviewLength"];
+}
+
+- (IBAction)pictureSliderChanged:(id)sender
+{
+ [self.delegate displayPreviewAtIndex:self.slider.integerValue];
+}
+
+- (IBAction)toggleScaleToScreen:(id)sender
+{
+ [self.delegate toggleScaleToScreen];
+ if (self.fitToView == YES)
+ {
+ self.scaleToScreenButton.title = NSLocalizedString(@"Scale To Screen", nil);
+ }
+ else
+ {
+ self.scaleToScreenButton.title = NSLocalizedString(@"Actual Scale", nil);
+ }
+ self.fitToView = !self.fitToView;
+}
+
+- (IBAction)showPictureSettings:(id)sender
+{
+ [self.delegate showPictureSettings];
+}
+
+- (IBAction)createMoviePreview:(id)sender
+{
+ [self.delegate createMoviePreviewWithPictureIndex:self.slider.integerValue duration:self.durationPopUp.titleOfSelectedItem.intValue];
+}
+
+- (BOOL)HB_keyDown:(NSEvent *)event
+{
+ unichar key = [event.charactersIgnoringModifiers characterAtIndex:0];
+ if (key == NSLeftArrowFunctionKey)
+ {
+ self.slider.integerValue = self.selectedIndex > self.slider.minValue ? self.selectedIndex - 1 : self.selectedIndex;
+ [self.delegate displayPreviewAtIndex:self.slider.integerValue];
+ return YES;
+ }
+ else if (key == NSRightArrowFunctionKey)
+ {
+ self.slider.integerValue = self.selectedIndex < self.slider.maxValue ? self.selectedIndex + 1 : self.selectedIndex;
+ [self.delegate displayPreviewAtIndex:self.slider.integerValue];
+ return YES;
+ }
+ else
+ {
+ return NO;
+ }
+}
+
+- (BOOL)HB_scrollWheel:(NSEvent *)theEvent
+{
+ if (theEvent.deltaY < 0)
+ {
+ self.slider.integerValue = self.selectedIndex < self.slider.maxValue ? self.selectedIndex + 1 : self.selectedIndex;
+ [self.delegate displayPreviewAtIndex:self.slider.integerValue];
+ }
+ else if (theEvent.deltaY > 0)
+ {
+ self.slider.integerValue = self.selectedIndex > self.slider.minValue ? self.selectedIndex - 1 : self.selectedIndex;
+ [self.delegate displayPreviewAtIndex:self.slider.integerValue];
+ }
+ return YES;
+}
+
+@end
diff --git a/macosx/HBPictureHUDController.xib b/macosx/HBPictureHUDController.xib
new file mode 100644
index 000000000..fe3152960
--- /dev/null
+++ b/macosx/HBPictureHUDController.xib
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F28b" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+ <dependencies>
+ <deployment identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="HBPictureHUDController">
+ <connections>
+ <outlet property="durationPopUp" destination="ASA-X8-16P" id="Ti4-aX-nbp"/>
+ <outlet property="infoLabel" destination="MkW-KN-I1h" id="c2A-DS-cd1"/>
+ <outlet property="scaleLabel" destination="7UR-Zz-7iX" id="ukS-8e-xmA"/>
+ <outlet property="scaleToScreenButton" destination="12K-c3-Z7A" id="ISw-XG-Wg8"/>
+ <outlet property="slider" destination="wUk-SQ-GhS" id="xWn-kV-0gS"/>
+ <outlet property="view" destination="agq-EJ-miM" id="3Eb-l9-o2j"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+ <customView id="agq-EJ-miM" userLabel="Picture Controls" customClass="HBHUDView">
+ <rect key="frame" x="0.0" y="0.0" width="460" height="100"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <subviews>
+ <button toolTip="Encode And Play Back A Live Preview At Your Current Settings" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="16b-R9-bBU">
+ <rect key="frame" x="17" y="11" width="80" height="16"/>
+ <buttonCell key="cell" type="push" title="Live Preview" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="vkh-GY-5qx">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="miniSystem"/>
+ </buttonCell>
+ <connections>
+ <action selector="createMoviePreview:" target="-2" id="rhf-gy-aMT"/>
+ </connections>
+ </button>
+ <button toolTip="Show Picture Settings Inspector" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mV7-hU-tMt">
+ <rect key="frame" x="378" y="11" width="61" height="16"/>
+ <buttonCell key="cell" type="push" title="Settings" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="NWd-Lq-c1A">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="miniSystem"/>
+ </buttonCell>
+ <connections>
+ <action selector="showPictureSettings:" target="-2" id="aDd-cp-S1k"/>
+ </connections>
+ </button>
+ <button toolTip="Scale Preview To Screen" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="12K-c3-Z7A">
+ <rect key="frame" x="276" y="11" width="96" height="16"/>
+ <buttonCell key="cell" type="push" title="Scale To Screen" bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="STc-Po-p1X">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="miniSystem"/>
+ </buttonCell>
+ <connections>
+ <action selector="toggleScaleToScreen:" target="-2" id="bbI-nW-6zM"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5T3-Vx-mC1">
+ <rect key="frame" x="105" y="14" width="48" height="11"/>
+ <textFieldCell key="cell" controlSize="mini" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Duration:" id="USR-Qf-N5v">
+ <font key="font" metaFont="miniSystemBold"/>
+ <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Vrm-He-CjP">
+ <rect key="frame" x="215" y="14" width="21" height="11"/>
+ <textFieldCell key="cell" controlSize="mini" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="sec" id="ksF-Ma-hB1">
+ <font key="font" metaFont="miniSystemBold"/>
+ <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <popUpButton toolTip="Select The Length Of Live Preview to Encode" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ASA-X8-16P">
+ <rect key="frame" x="158" y="12" width="53" height="15"/>
+ <popUpButtonCell key="cell" type="push" title="240" bezelStyle="rounded" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" selectedItem="XYh-Ls-slf" id="yDS-gf-Y4N">
+ <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="miniSystem"/>
+ <menu key="menu" title="OtherViews" id="KrC-nR-rYk">
+ <items>
+ <menuItem title="240" state="on" id="XYh-Ls-slf"/>
+ </items>
+ </menu>
+ </popUpButtonCell>
+ <connections>
+ <action selector="previewDurationPopUpChanged:" target="-2" id="JSm-Eo-Ijw"/>
+ </connections>
+ </popUpButton>
+ <slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wUk-SQ-GhS">
+ <rect key="frame" x="18" y="39" width="420" height="17"/>
+ <sliderCell key="cell" controlSize="mini" continuous="YES" alignment="left" maxValue="9" tickMarkPosition="above" numberOfTickMarks="10" allowsTickMarkValuesOnly="YES" sliderType="linear" id="dPk-jb-w9o">
+ <font key="font" metaFont="miniSystem"/>
+ </sliderCell>
+ <connections>
+ <action selector="pictureSliderChanged:" target="-2" id="576-54-fMW"/>
+ </connections>
+ </slider>
+ <textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="426" translatesAutoresizingMaskIntoConstraints="NO" id="MkW-KN-I1h">
+ <rect key="frame" x="15" y="55" width="430" height="20"/>
+ <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" alignment="left" id="DKr-Lp-f2U">
+ <font key="font" metaFont="smallSystemBold"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="422" translatesAutoresizingMaskIntoConstraints="NO" id="7UR-Zz-7iX">
+ <rect key="frame" x="15" y="77" width="426" height="12"/>
+ <textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" alignment="left" id="CeL-Pu-NS6">
+ <font key="font" metaFont="miniSystemBold"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <point key="canvasLocation" x="23" y="360"/>
+ </customView>
+ </objects>
+</document>
diff --git a/macosx/HBPlayer.h b/macosx/HBPlayer.h
new file mode 100644
index 000000000..77d6ada6b
--- /dev/null
+++ b/macosx/HBPlayer.h
@@ -0,0 +1,57 @@
+/* HBPlayer.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+
+#import <Foundation/Foundation.h>
+#import <QuartzCore/QuartzCore.h>
+
+#import "HBPlayerTrack.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * A protocol for a generic player,
+ * users should call loadPlayableValueAsynchronouslyWithCompletionHandler
+ * before calling any other method or property.
+ */
+@protocol HBPlayer <NSObject>
+
+- (instancetype)initWithURL:(NSURL *)url;
+
+@property (nonatomic, readonly) CALayer *layer;
+
+@property (nonatomic, readonly) NSTimeInterval duration;
+@property (nonatomic) NSTimeInterval currentTime;
+
+@property (nonatomic, readonly, copy) NSArray<HBPlayerTrack *> *audioTracks;
+@property (nonatomic, readonly, copy) NSArray<HBPlayerTrack *> *subtitlesTracks;
+
+- (void)enableAudioTrack:(nullable HBPlayerTrack *)playerTrack;
+- (void)enableSubtitlesTrack:(nullable HBPlayerTrack *)playerTrack;
+
+@property (nonatomic) float rate;
+@property (nonatomic) float volume;
+
+@property (nonatomic, readonly, getter=isPlayable) BOOL playable;
+
+- (void)loadPlayableValueAsynchronouslyWithCompletionHandler:(nullable void (^)(void))handler;
+
+- (id)addPeriodicTimeObserverUsingBlock:(void (^)(NSTimeInterval time))block;
+- (void)removeTimeObserver:(id)observer;
+
+- (id)addRateObserverUsingBlock:(void (^)(void))block;
+- (void)removeRateObserver:(id)observer;
+
+- (void)play;
+- (void)pause;
+- (void)gotoBeginning;
+- (void)gotoEnd;
+- (void)stepForward;
+- (void)stepBackward;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/macosx/HBPlayerHUDController.h b/macosx/HBPlayerHUDController.h
new file mode 100644
index 000000000..7becadb64
--- /dev/null
+++ b/macosx/HBPlayerHUDController.h
@@ -0,0 +1,23 @@
+/* HBPlayerHUDController.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Cocoa/Cocoa.h>
+#import "HBPlayer.h"
+#import "HBHUD.h"
+
+@protocol HBPlayerHUDControllerDelegate <NSObject>
+
+- (void)stopPlayer;
+
+@end
+
+@interface HBPlayerHUDController : NSViewController <HBHUD>
+
+@property (nonatomic, nullable, assign) id<HBPlayerHUDControllerDelegate> delegate;
+
+@property (nonatomic, nullable) id<HBPlayer> player;
+
+@end
diff --git a/macosx/HBPlayerHUDController.m b/macosx/HBPlayerHUDController.m
new file mode 100644
index 000000000..03eed5a84
--- /dev/null
+++ b/macosx/HBPlayerHUDController.m
@@ -0,0 +1,341 @@
+/* HBPlayerHUDController.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import "HBPlayerHUDController.h"
+
+@interface HBPlayerHUDController ()
+
+@property (weak) IBOutlet NSButton *playButton;
+@property (weak) IBOutlet NSSlider *slider;
+
+@property (weak) IBOutlet NSSlider *volumeSlider;
+
+@property (weak) IBOutlet NSTextField *currentTimeLabel;
+@property (weak) IBOutlet NSTextField *remaingTimeLabel;
+
+@property (weak) IBOutlet NSPopUpButton *tracksSelection;
+
+@property (nonatomic, readonly) NSDictionary *monospacedAttr;
+
+@property (nonatomic, readwrite) id rateObserver;
+@property (nonatomic, readwrite) id periodicObserver;
+
+@end
+
+@implementation HBPlayerHUDController
+
+- (NSString *)nibName
+{
+ return @"HBPlayerHUDController";
+}
+
+- (void)loadView
+{
+ [super loadView];
+
+ if (NSClassFromString(@"NSVisualEffectView") == NO)
+ {
+ self.currentTimeLabel.textColor = [NSColor whiteColor];
+ self.remaingTimeLabel.textColor = [NSColor whiteColor];
+ }
+
+ if ([[NSFont class] respondsToSelector:@selector(monospacedDigitSystemFontOfSize:weight:)]) {
+ _monospacedAttr = @{NSFontAttributeName: [NSFont monospacedDigitSystemFontOfSize:[NSFont smallSystemFontSize] weight:NSFontWeightRegular]};
+ }
+ else {
+ _monospacedAttr = @{NSFontAttributeName: [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]};
+ }
+}
+
+- (BOOL)canBeHidden
+{
+ return YES;
+}
+
+- (void)setPlayer:(id<HBPlayer>)player
+{
+ if (_player)
+ {
+ [self.player removeRateObserver:self.rateObserver];
+ [self.player removeTimeObserver:self.periodicObserver];
+ [self _clearTracksMenu];
+ }
+
+ _player = player;
+
+ if (player)
+ {
+ [self _buildTracksMenu];
+
+ // 10.7 does not supports weak NSViewController,
+ // so use self and disable the warning for now.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-retain-cycles"
+
+ self.periodicObserver = [self.player addPeriodicTimeObserverUsingBlock:^(NSTimeInterval time) {
+ [self _refreshUI];
+ }];
+
+ self.rateObserver = [self.player addRateObserverUsingBlock:^{
+ if (self.player.rate != 0.0)
+ {
+ self.playButton.image = [NSImage imageNamed:@"PauseTemplate"];
+ }
+ else
+ {
+ self.playButton.image = [NSImage imageNamed:@"PlayTemplate"];
+ }
+ }];
+
+ [self.slider setMinValue:0.0];
+ [self.slider setMaxValue:self.player.duration];
+ [self.slider setDoubleValue:0.0];
+
+ [self.player play];
+ }
+}
+
+- (void)dealloc
+{
+ // Remove observers
+}
+
+#pragma mark - Audio and subtitles selection menu
+
+- (void)_buildTracksMenu
+{
+ [self _clearTracksMenu];
+
+ NSArray<HBPlayerTrack *> *audioTracks = self.player.audioTracks;
+ if (audioTracks.count)
+ {
+ [self _addSectionTitle:NSLocalizedString(@"Audio", nil)];
+ [self _addTracksItemFromArray:audioTracks selector:@selector(enableAudioTrack:)];
+ }
+
+ NSArray<HBPlayerTrack *> *subtitlesTracks = self.player.subtitlesTracks;
+ if (subtitlesTracks.count)
+ {
+ if (audioTracks.count)
+ {
+ [self.tracksSelection.menu addItem:[NSMenuItem separatorItem]];
+ }
+ [self _addSectionTitle:NSLocalizedString(@"Subtitles", nil)];
+ [self _addTracksItemFromArray:subtitlesTracks selector:@selector(enableSubtitlesTrack:)];
+ }
+}
+
+- (void)_clearTracksMenu
+{
+ for (NSMenuItem *item in [self.tracksSelection.menu.itemArray copy])
+ {
+ if (item.tag != 1)
+ {
+ [self.tracksSelection.menu removeItem:item];
+ }
+ }
+}
+
+- (void)_addSectionTitle:(NSString *)title
+{
+ NSMenuItem *sectionTitle = [[NSMenuItem alloc] init];
+ sectionTitle.title = title;
+ sectionTitle.enabled = NO;
+ sectionTitle.indentationLevel = 0;
+ [self.tracksSelection.menu addItem:sectionTitle];
+}
+
+- (void)_addTracksItemFromArray:(NSArray<HBPlayerTrack *> *)tracks selector:(SEL)selector
+{
+ for (HBPlayerTrack *track in tracks)
+ {
+ NSMenuItem *item = [[NSMenuItem alloc] init];
+ item.title = track.name;
+ item.enabled = YES;
+ item.indentationLevel = 1;
+ item.action = selector;
+ item.target = self;
+ item.state = track.enabled;
+ item.representedObject = track;
+ [self.tracksSelection.menu addItem:item];
+ }
+}
+
+- (void)_updateTracksMenuState
+{
+ for (NSMenuItem *item in self.tracksSelection.menu.itemArray)
+ {
+ if (item.representedObject)
+ {
+ HBPlayerTrack *track = (HBPlayerTrack *)item.representedObject;
+ item.state = track.enabled;
+ }
+ }
+}
+
+- (IBAction)enableAudioTrack:(NSMenuItem *)sender
+{
+ [self.player enableAudioTrack:sender.representedObject];
+ [self _updateTracksMenuState];
+}
+
+- (IBAction)enableSubtitlesTrack:(NSMenuItem *)sender
+{
+ [self.player enableSubtitlesTrack:sender.representedObject];
+ [self _updateTracksMenuState];
+}
+
+- (NSString *)_timeToTimecode:(NSTimeInterval)timeInSeconds
+{
+ UInt16 seconds = (UInt16)fmod(timeInSeconds, 60.0);
+ UInt16 minutes = (UInt16)fmod(timeInSeconds / 60.0, 60.0);
+ UInt16 milliseconds = (UInt16)((timeInSeconds - (int) timeInSeconds) * 1000);
+
+ return [NSString stringWithFormat:@"%02d:%02d.%03d", minutes, seconds, milliseconds];
+}
+
+- (NSAttributedString *)_monospacedString:(NSString *)string
+{
+ return [[NSAttributedString alloc] initWithString:string attributes:self.monospacedAttr];
+
+}
+
+- (void)_refreshUI
+{
+ if (self.player)
+ {
+ NSTimeInterval currentTime = self.player.currentTime;
+ NSTimeInterval duration = self.player.duration;
+
+ self.slider.doubleValue = currentTime;
+ self.currentTimeLabel.attributedStringValue = [self _monospacedString:[self _timeToTimecode:currentTime]];
+ self.remaingTimeLabel.attributedStringValue = [self _monospacedString:[self _timeToTimecode:duration - currentTime]];
+ }
+}
+
+- (IBAction)playPauseToggle:(id)sender
+{
+ if (self.player.rate != 0.0)
+ {
+ [self.player pause];
+ }
+ else
+ {
+ [self.player play];
+ }
+}
+
+- (IBAction)goToBeginning:(id)sender
+{
+ [self.player gotoBeginning];
+}
+
+- (IBAction)goToEnd:(id)sender
+{
+ [self.player gotoEnd];
+}
+
+- (IBAction)showPicturesPreview:(id)sender
+{
+ [self.delegate stopPlayer];
+}
+
+- (IBAction)sliderChanged:(NSSlider *)sender
+{
+ self.player.currentTime = sender.doubleValue;
+}
+
+- (IBAction)maxVolume:(id)sender
+{
+ self.volumeSlider.doubleValue = 1;
+ self.player.volume = 1;
+}
+
+- (IBAction)mute:(id)sender
+{
+ self.volumeSlider.doubleValue = 0;
+ self.player.volume = 0;
+}
+
+- (IBAction)volumeSliderChanged:(NSSlider *)sender
+{
+ self.player.volume = sender.floatValue;
+}
+
+#pragma mark - Keyboard and mouse wheel control
+
+- (BOOL)HB_keyDown:(NSEvent *)event
+{
+ unichar key = [event.charactersIgnoringModifiers characterAtIndex:0];
+
+ if (self.player)
+ {
+ if (key == 32)
+ {
+ if (self.player.rate != 0.0)
+ [self.player pause];
+ else
+ [self.player play];
+ }
+ else if (key == 'k')
+ [self.player pause];
+ else if (key == 'l')
+ {
+ float rate = self.player.rate;
+ rate += 1.0f;
+ [self.player play];
+ self.player.rate = rate;
+ }
+ else if (key == 'j')
+ {
+ float rate = self.player.rate;
+ rate -= 1.0f;
+ [self.player play];
+ self.player.rate = rate;
+ }
+ else if (event.modifierFlags & NSAlternateKeyMask && key == NSLeftArrowFunctionKey)
+ {
+ [self.player gotoBeginning];
+ }
+ else if (event.modifierFlags & NSAlternateKeyMask && key == NSRightArrowFunctionKey)
+ {
+ [self.player gotoEnd];
+ }
+ else if (key == NSLeftArrowFunctionKey)
+ {
+ [self.player stepBackward];
+ }
+ else if (key == NSRightArrowFunctionKey)
+ {
+ [self.player stepForward];
+ }
+ else
+ {
+ return NO;
+ }
+ }
+ else
+ {
+ return NO;
+ }
+
+ return YES;
+}
+
+- (BOOL)HB_scrollWheel:(NSEvent *)theEvent;
+{
+ if (theEvent.deltaY < 0)
+ {
+ self.player.currentTime = self.player.currentTime + 0.5;
+ }
+ else if (theEvent.deltaY > 0)
+ {
+ self.player.currentTime = self.player.currentTime - 0.5;
+ }
+ return YES;
+}
+
+@end
diff --git a/macosx/HBPlayerHUDController.xib b/macosx/HBPlayerHUDController.xib
new file mode 100644
index 000000000..812c83c90
--- /dev/null
+++ b/macosx/HBPlayerHUDController.xib
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="15F28b" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+ <dependencies>
+ <deployment identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="HBPlayerHUDController">
+ <connections>
+ <outlet property="currentTimeLabel" destination="uYx-2C-8et" id="8fD-0Q-308"/>
+ <outlet property="playButton" destination="mLA-ei-4sK" id="Eag-8h-xCG"/>
+ <outlet property="remaingTimeLabel" destination="PVD-pq-1ZG" id="CFb-is-Tcd"/>
+ <outlet property="slider" destination="lBp-JT-ehn" id="cNv-P0-agY"/>
+ <outlet property="tracksSelection" destination="Vj1-Za-AUV" id="8Se-0H-ILD"/>
+ <outlet property="view" destination="xT7-Bx-eCV" id="GXR-ZH-hT6"/>
+ <outlet property="volumeSlider" destination="gzA-no-jdv" id="Yba-8g-L1Z"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+ <customView hidden="YES" id="xT7-Bx-eCV" userLabel="Playback Controls" customClass="HBHUDView">
+ <rect key="frame" x="0.0" y="0.0" width="460" height="100"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <subviews>
+ <slider verticalHuggingPriority="750" id="lBp-JT-ehn">
+ <rect key="frame" x="69" y="18" width="322" height="17"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+ <sliderCell key="cell" controlSize="small" continuous="YES" alignment="left" maxValue="100" tickMarkPosition="above" sliderType="linear" id="mMk-re-3u5"/>
+ <connections>
+ <action selector="sliderChanged:" target="-2" id="YM4-mh-fr5"/>
+ </connections>
+ </slider>
+ <button toolTip="Toggle Play/Pause" id="mLA-ei-4sK">
+ <rect key="frame" x="212" y="46" width="36" height="36"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="PlayTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" id="jG9-2O-OES">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="playPauseToggle:" target="-2" id="LLB-0k-P6K"/>
+ </connections>
+ </button>
+ <button toolTip="Go To Beginning" id="WuP-9l-8AN">
+ <rect key="frame" x="170" y="51" width="32" height="26"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="PrevTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" id="IBZ-MN-bJO">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="goToBeginning:" target="-2" id="m24-WZ-vGD"/>
+ </connections>
+ </button>
+ <button toolTip="Go To End" id="CQ0-pk-SFk">
+ <rect key="frame" x="258" y="51" width="32" height="26"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="NextTemplate" imagePosition="only" alignment="center" controlSize="mini" imageScaling="proportionallyDown" id="LUb-dY-8hG">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="miniSystem"/>
+ </buttonCell>
+ <connections>
+ <action selector="goToEnd:" target="-2" id="Rp0-53-4gw"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" id="PVD-pq-1ZG">
+ <rect key="frame" x="395" y="20" width="55" height="14"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
+ <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" alignment="right" title="00:00:00" id="6A0-9h-5UY">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" id="uYx-2C-8et">
+ <rect key="frame" x="10" y="20" width="55" height="14"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" alignment="left" title="00:00:00" id="dGi-LK-P1E">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <slider verticalHuggingPriority="750" id="gzA-no-jdv">
+ <rect key="frame" x="34" y="55" width="65" height="17"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <sliderCell key="cell" controlSize="small" continuous="YES" state="on" alignment="left" maxValue="1" doubleValue="1" tickMarkPosition="above" sliderType="linear" id="aQz-j6-bQi"/>
+ <connections>
+ <action selector="volumeSliderChanged:" target="-2" id="rLr-Ug-i8q"/>
+ </connections>
+ </slider>
+ <button toolTip="Return to still previews" id="84p-08-fGK" userLabel="Stop Button">
+ <rect key="frame" x="424" y="55" width="16" height="16"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
+ <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="NSStopProgressFreestandingTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" id="hWC-BU-ynp">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="showPicturesPreview:" target="-2" id="kCs-UI-Epb"/>
+ </connections>
+ </button>
+ <button toolTip="Go To Beginning" id="euL-Tg-dmT">
+ <rect key="frame" x="12" y="55" width="18" height="18"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="volLowTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" id="njB-22-thn">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="mute:" target="-2" id="CIm-ce-Lnf"/>
+ </connections>
+ </button>
+ <button id="Kiv-cL-wYI">
+ <rect key="frame" x="103" y="55" width="18" height="18"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" image="volHighTemplate" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" id="rgx-mB-Rva">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="maxVolume:" target="-2" id="89B-BN-U8S"/>
+ </connections>
+ </button>
+ <popUpButton id="Vj1-Za-AUV">
+ <rect key="frame" x="336" y="47" width="73" height="30"/>
+ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
+ <popUpButtonCell key="cell" type="push" title="Tracks" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="border" tag="1" imageScaling="proportionallyDown" inset="2" pullsDown="YES" autoenablesItems="NO" altersStateOfSelectedItem="NO" id="uwd-kr-YUM">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="smallSystem"/>
+ <menu key="menu" autoenablesItems="NO" id="J1o-jV-bDZ">
+ <items>
+ <menuItem title="Tracks" state="on" tag="1" hidden="YES" id="6BQ-wU-p2C">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES"/>
+ </menuItem>
+ </items>
+ </menu>
+ </popUpButtonCell>
+ </popUpButton>
+ </subviews>
+ <point key="canvasLocation" x="466" y="429"/>
+ </customView>
+ </objects>
+ <resources>
+ <image name="NSStopProgressFreestandingTemplate" width="14" height="14"/>
+ <image name="NextTemplate" width="48" height="48"/>
+ <image name="PlayTemplate" width="48" height="48"/>
+ <image name="PrevTemplate" width="48" height="48"/>
+ <image name="volHighTemplate" width="48" height="48"/>
+ <image name="volLowTemplate" width="48" height="48"/>
+ </resources>
+</document>
diff --git a/macosx/HBPlayerTrack.h b/macosx/HBPlayerTrack.h
new file mode 100644
index 000000000..950fdfdda
--- /dev/null
+++ b/macosx/HBPlayerTrack.h
@@ -0,0 +1,21 @@
+/* HBPlayerTrack.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface HBPlayerTrack : NSObject
+
+- (instancetype)initWithTrackName:(NSString *)name object:(id)representedObject enabled:(BOOL)enabled;
+
+@property (nonatomic, readonly) NSString *name;
+@property (nonatomic, readwrite) BOOL enabled;
+@property (nonatomic, readonly) id representedObject;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/macosx/HBPlayerTrack.m b/macosx/HBPlayerTrack.m
new file mode 100644
index 000000000..1be7bc6d5
--- /dev/null
+++ b/macosx/HBPlayerTrack.m
@@ -0,0 +1,22 @@
+/* HBPlayerTrack.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import "HBPlayerTrack.h"
+
+@implementation HBPlayerTrack
+
+- (instancetype)initWithTrackName:(NSString *)name object:(id)representedObject enabled:(BOOL)enabled
+{
+ self = [super init];
+ if (self) {
+ _name = name;
+ _enabled = enabled;
+ _representedObject = representedObject;
+ }
+ return self;
+}
+
+@end
diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m
index 4e7d259e2..1db48cdcd 100644
--- a/macosx/HBPreviewController.m
+++ b/macosx/HBPreviewController.m
@@ -1,4 +1,4 @@
-/* $Id: HBPreviewController.mm,v 1.11 2005/08/01 15:10:44 titer Exp $
+/* $Id: HBPreviewController.m $
This file is part of the HandBrake source code.
Homepage: <http://handbrake.fr/>.
@@ -8,65 +8,42 @@
#import "HBPreviewGenerator.h"
#import "HBPictureController.h"
+#import "HBController.h"
#import "HBPreviewView.h"
-#import "HBController.h"
+#import "HBPlayer.h"
+#import "HBQTKitPlayer.h"
+#import "HBAVPlayer.h"
-#import <QTKit/QTKit.h>
-#import "QTKit+HBQTMovieExtensions.h"
+#import "HBPictureHUDController.h"
+#import "HBEncodingProgressHUDController.h"
+#import "HBPlayerHUDController.h"
+
+#import "NSWindow+HBAdditions.h"
#define ANIMATION_DUR 0.15
+#define HUD_FADEOUT_TIME 4.0
-// make min width and height of preview window large enough for hud
+// Make min width and height of preview window large enough for hud.
#define MIN_WIDTH 480.0
#define MIN_HEIGHT 360.0
-typedef enum ViewMode : NSUInteger {
- ViewModePicturePreview,
- ViewModeEncoding,
- ViewModeMoviePreview
-} ViewMode;
+@interface HBPreviewController () <HBPreviewGeneratorDelegate, HBPictureHUDControllerDelegate, HBEncodingProgressHUDControllerDelegate, HBPlayerHUDControllerDelegate>
-@interface HBPreviewController () <HBPreviewGeneratorDelegate>
-{
- /* HUD boxes */
- IBOutlet NSView * fPictureControlBox;
- IBOutlet NSView * fEncodingControlBox;
- IBOutlet NSView * fMoviePlaybackControlBox;
+@property (nonatomic, readonly) HBPictureHUDController *pictureHUD;
+@property (nonatomic, readonly) HBEncodingProgressHUDController *encodingHUD;
+@property (nonatomic, readonly) HBPlayerHUDController *playerHUD;
- IBOutlet NSSlider * fPictureSlider;
- IBOutlet NSTextField * fInfoField;
- IBOutlet NSTextField * fscaleInfoField;
+@property (nonatomic, readwrite) NSViewController<HBHUD> *currentHUD;
- /* Full Screen Mode Toggle */
- IBOutlet NSButton * fScaleToScreenToggleButton;
+@property (nonatomic) NSTimer *hudTimer;
+@property (nonatomic) BOOL mouseInWindow;
- /* Movie Previews */
- IBOutlet QTMovieView * fMovieView;
- /* Playback Panel Controls */
- IBOutlet NSButton * fPlayPauseButton;
- IBOutlet NSSlider * fMovieScrubberSlider;
- IBOutlet NSTextField * fMovieInfoField;
-
- IBOutlet NSProgressIndicator * fMovieCreationProgressIndicator;
- IBOutlet NSTextField * fPreviewMovieStatusField;
-
- /* Popup of choices for length of preview in seconds */
- IBOutlet NSPopUpButton * fPreviewMovieLengthPopUp;
-}
+@property (nonatomic) id<HBPlayer> player;
-@property (nonatomic, readwrite) HBPictureController *pictureSettingsWindow;
+@property (nonatomic) HBPictureController *pictureSettingsWindow;
-@property (nonatomic) ViewMode currentViewMode;
@property (nonatomic) NSPoint windowCenterPoint;
-
-@property (nonatomic, strong) NSTimer *hudTimer;
-
-@property (nonatomic) NSUInteger pictureIndex;
-
-@property (nonatomic, strong) QTMovie *movie;
-@property (nonatomic, strong) NSTimer *movieTimer;
-
@property (weak) IBOutlet HBPreviewView *previewView;
@end
@@ -92,51 +69,48 @@ typedef enum ViewMode : NSUInteger {
{
NSPoint center = NSPointFromString(centerString);
self.windowCenterPoint = center;
- [self resizeWindowForViewSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT) animate:NO];
+ [self.window HB_resizeToBestSizeForViewSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT) center:self.windowCenterPoint animate:NO];
}
else
{
- self.windowCenterPoint = [self centerPoint];
+ self.windowCenterPoint = [self.window HB_centerPoint];
}
self.window.excludedFromWindowsMenu = YES;
self.window.acceptsMouseMovedEvents = YES;
- // we set the preview length popup in seconds
- [fPreviewMovieLengthPopUp removeAllItems];
- [fPreviewMovieLengthPopUp addItemsWithTitles:@[@"15", @"30", @"45", @"60", @"90",
- @"120", @"150", @"180", @"210", @"240"]];
+ _pictureHUD = [[HBPictureHUDController alloc] init];
+ self.pictureHUD.delegate = self;
+ _encodingHUD = [[HBEncodingProgressHUDController alloc] init];
+ self.encodingHUD.delegate = self;
+ _playerHUD = [[HBPlayerHUDController alloc] init];
+ self.playerHUD.delegate = self;
- if ([[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"])
- {
- [fPreviewMovieLengthPopUp selectItemWithTitle:[[NSUserDefaults standardUserDefaults]
- objectForKey:@"PreviewLength"]];
- }
- if (!fPreviewMovieLengthPopUp.selectedItem)
- {
- // currently hard set default to 15 seconds
- [fPreviewMovieLengthPopUp selectItemAtIndex: 0];
- }
+ [self.window.contentView addSubview:self.pictureHUD.view];
+ [self.window.contentView addSubview:self.encodingHUD.view];
+ [self.window.contentView addSubview:self.playerHUD.view];
// Relocate our hud origins.
- NSPoint hudControlBoxOrigin = fMoviePlaybackControlBox.frame.origin;
- fPictureControlBox.frameOrigin = hudControlBoxOrigin;
- fEncodingControlBox.frameOrigin = hudControlBoxOrigin;
- fMoviePlaybackControlBox.frameOrigin = hudControlBoxOrigin;
+ CGPoint origin = CGPointMake(floor((MIN_WIDTH - _pictureHUD.view.bounds.size.width) / 2), MIN_HEIGHT / 10);
+
+ [self.pictureHUD.view setFrameOrigin:origin];
+ [self.encodingHUD.view setFrameOrigin:origin];
+ [self.playerHUD.view setFrameOrigin:origin];
- [self hideHud];
+ self.currentHUD = self.pictureHUD;
+ self.currentHUD.view.hidden = YES;
- fMovieView.hidden = YES;
- fMovieView.delegate = self;
- [fMovieView setControllerVisible:NO];
+ NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:self.window.contentView.frame
+ options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways
+ owner:self
+ userInfo:nil];
+ [self.window.contentView addTrackingArea:trackingArea];
}
- (void)dealloc
{
- [self removeMovieObservers];
-
[_hudTimer invalidate];
- [_movieTimer invalidate];
+ _generator.delegate = nil;
[_generator cancel];
}
@@ -188,21 +162,13 @@ typedef enum ViewMode : NSUInteger {
generator.delegate = self;
// adjust the preview slider length
- [fPictureSlider setMaxValue: generator.imagesCount - 1.0];
- [fPictureSlider setNumberOfTickMarks: generator.imagesCount];
-
- if (self.pictureIndex > generator.imagesCount)
- {
- self.pictureIndex = generator.imagesCount - 1;
- }
-
- [self switchViewToMode:ViewModePicturePreview];
- [self displayPreviewAtIndex:self.pictureIndex];
+ self.pictureHUD.pictureCount = generator.imagesCount;
+ [self switchStateToHUD:self.pictureHUD];
}
else
{
self.previewView.image = nil;
- [self hideHud];
+ self.currentHUD.view.hidden = YES;
self.window.title = NSLocalizedString(@"Preview", nil);
}
}
@@ -212,8 +178,7 @@ typedef enum ViewMode : NSUInteger {
if (self.generator)
{
[self.generator cancel];
- [self switchViewToMode:ViewModePicturePreview];
- [self displayPreviewAtIndex:self.pictureIndex];
+ [self switchStateToHUD:self.pictureHUD];
}
}
@@ -221,11 +186,7 @@ typedef enum ViewMode : NSUInteger {
{
[super showWindow:sender];
- if (self.currentViewMode == ViewModeMoviePreview)
- {
- [self startMovieTimer];
- }
- else if (self.currentViewMode == ViewModePicturePreview)
+ if (self.currentHUD == self.pictureHUD)
{
[self reloadPreviews];
}
@@ -233,14 +194,13 @@ typedef enum ViewMode : NSUInteger {
- (void)windowWillClose:(NSNotification *)aNotification
{
- if (self.currentViewMode == ViewModeEncoding)
+ if (self.currentHUD == self.encodingHUD)
{
- [self cancelCreateMoviePreview:self];
+ [self cancelEncoding];
}
- else if (self.currentViewMode == ViewModeMoviePreview)
+ else if (self.currentHUD == self.playerHUD)
{
- [fMovieView pause:self];
- [self stopMovieTimer];
+ [self.player pause];
}
[self.pictureSettingsWindow close];
@@ -249,11 +209,10 @@ typedef enum ViewMode : NSUInteger {
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
{
- NSWindow *theWindow = (NSWindow *)[notification object];
+ NSWindow *theWindow = (NSWindow *)notification.object;
- CGFloat newBackingScaleFactor = [theWindow backingScaleFactor];
- CGFloat oldBackingScaleFactor = [[notification userInfo][@"NSBackingPropertyOldScaleFactorKey"]
- doubleValue];
+ CGFloat newBackingScaleFactor = theWindow.backingScaleFactor;
+ CGFloat oldBackingScaleFactor = [notification.userInfo[@"NSBackingPropertyOldScaleFactorKey"] doubleValue];
if (newBackingScaleFactor != oldBackingScaleFactor)
{
@@ -268,20 +227,11 @@ typedef enum ViewMode : NSUInteger {
#pragma mark - Window sizing
-/**
- * Calculates and returns the center point of the window
- */
-- (NSPoint)centerPoint {
- NSPoint center = NSMakePoint(floor(self.window.frame.origin.x + self.window.frame.size.width / 2),
- floor(self.window.frame.origin.y + self.window.frame.size.height / 2));
- return center;
-}
-
- (void)windowDidMove:(NSNotification *)notification
{
if (self.previewView.fitToView == NO)
{
- self.windowCenterPoint = [self centerPoint];
+ self.windowCenterPoint = [self.window HB_centerPoint];
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromPoint(self.windowCenterPoint) forKey:@"HBPreviewWindowCenter"];
}
}
@@ -291,68 +241,6 @@ typedef enum ViewMode : NSUInteger {
[self updateSizeLabels];
}
-/**
- * Resizes the entire window to accomodate a view of a particular size.
- */
-- (void)resizeWindowForViewSize:(NSSize)viewSize animate:(BOOL)performAnimation
-{
- NSWindow *window = self.window;
- NSSize currentSize = [window.contentView frame].size;
- NSRect frame = window.frame;
-
- // Calculate border around content region of the frame
- int borderX = (int)(frame.size.width - currentSize.width);
- int borderY = (int)(frame.size.height - currentSize.height);
-
- // Make sure the frame is smaller than the screen
- NSSize maxSize = window.screen.visibleFrame.size;
-
- // if we are not Scale To Screen, put an 10% of visible screen on the window
- maxSize.width = maxSize.width * 0.90;
- maxSize.height = maxSize.height * 0.90;
-
- // Set the new frame size
- // Add the border to the new frame size so that the content region
- // of the frame is large enough to accomodate the preview image
- frame.size.width = viewSize.width + borderX;
- frame.size.height = viewSize.height + borderY;
-
- // compare frame to max size of screen
- if (frame.size.width > maxSize.width)
- {
- frame.size.width = maxSize.width;
- }
- if (frame.size.height > maxSize.height)
- {
- frame.size.height = maxSize.height;
- }
-
- // Since upon launch we can open up the preview window if it was open
- // the last time we quit (and at the size it was) we want to make
- // sure that upon resize we do not have the window off the screen
- // So check the origin against the screen origin and adjust if
- // necessary.
- NSSize screenSize = window.screen.visibleFrame.size;
- NSPoint screenOrigin = window.screen.visibleFrame.origin;
-
- frame.origin.x = self.windowCenterPoint.x - floor(frame.size.width / 2);
- frame.origin.y = self.windowCenterPoint.y - floor(frame.size.height / 2);
-
- // our origin is off the screen to the left
- if (frame.origin.x < screenOrigin.x)
- {
- // so shift our origin to the right
- frame.origin.x = screenOrigin.x;
- }
- else if ((frame.origin.x + frame.size.width) > (screenOrigin.x + screenSize.width))
- {
- // the right side of the preview is off the screen, so shift to the left
- frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width;
- }
-
- [window setFrame:frame display:YES animate:performAnimation];
-}
-
- (void)updateSizeLabels
{
if (self.generator)
@@ -375,8 +263,8 @@ typedef enum ViewMode : NSUInteger {
}
// Set the info fields in the hud controller
- fInfoField.stringValue = self.generator.info;
- fscaleInfoField.stringValue = scaleString;
+ self.pictureHUD.info = self.generator.info;
+ self.pictureHUD.scale = scaleString;
// Set the info field in the window title bar
self.window.title = [NSString stringWithFormat:NSLocalizedString(@"Preview - %@ %@", nil),
@@ -384,138 +272,86 @@ typedef enum ViewMode : NSUInteger {
}
}
-#pragma mark - Hud mode
+#pragma mark - Hud State
/**
- * Enable/Disable an arbitrary number of UI elements.
- * @param boxes an array of UI elements
- * @param indexes a set of indexes of the elements in boxes to be enabled
- */
-- (void) toggleBoxes: (NSArray *) boxes usingIndexes: (NSIndexSet *) indexes
-{
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:ANIMATION_DUR];
-
- [boxes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- BOOL hide = [indexes containsIndex:idx] ? NO : YES;
- if (hide)
- {
- [self hideHudWithAnimation:obj];
- }
- else
- {
- [self showHudWithAnimation:obj];
- }
- }];
-
- [NSAnimationContext endGrouping];
-}
-
-/**
- * Switch the preview controller to one of his view mode:
- * ViewModePicturePreview, ViewModeEncoding, ViewModeMoviePreview
+ * Switch the preview controller to one of his hud mode:
* This methods is the only way to change the mode, do not try otherwise.
- * @param mode ViewMode mode
+ * @param hud NSViewController<HBHUD> the hud to show
*/
-- (void) switchViewToMode: (ViewMode) mode
+- (void)switchStateToHUD:(NSViewController<HBHUD> *)hud
{
- switch (mode) {
- case ViewModePicturePreview:
- {
- if (self.currentViewMode == ViewModeEncoding)
- {
- [self toggleBoxes:@[fPictureControlBox, fEncodingControlBox]
- usingIndexes:[NSIndexSet indexSetWithIndex:0]];
- [fMovieCreationProgressIndicator stopAnimation:self];
- }
- else if (self.currentViewMode == ViewModeMoviePreview)
- {
- // Stop playback and remove the observers
- [fMovieView pause:self];
- [self stopMovieTimer];
- [self removeMovieObservers];
-
- [self toggleBoxes:@[fPictureControlBox, fMoviePlaybackControlBox, fMovieView]
- usingIndexes:[NSIndexSet indexSetWithIndex:0]];
-
- /* Release the movie */
- [fMovieView setMovie:nil];
- self.movie = nil;
- }
-
- break;
- }
+ if (self.currentHUD == self.playerHUD)
+ {
+ [self exitPlayerState];
+ }
- case ViewModeEncoding:
- {
- [fMovieCreationProgressIndicator setDoubleValue:0];
- [fMovieCreationProgressIndicator startAnimation:self];
- [self toggleBoxes:@[fEncodingControlBox, fPictureControlBox, fMoviePlaybackControlBox]
- usingIndexes:[NSIndexSet indexSetWithIndex:0]];
+ if (hud == self.pictureHUD)
+ {
+ [self enterPictureState];
+ }
+ else if (hud == self.encodingHUD)
+ {
+ [self enterEncodingState];
+ }
+ else if (hud == self.playerHUD)
+ {
+ [self enterPlayerState];
+ }
- break;
- }
+ // Show the current hud
+ NSMutableArray *huds = [@[self.pictureHUD, self.encodingHUD, self.playerHUD] mutableCopy];
+ [huds removeObject:hud];
+ for (NSViewController *controller in huds) {
+ controller.view.hidden = YES;
+ }
+ hud.view.hidden = NO;
+ hud.view.layer.opacity = 1.0;
- case ViewModeMoviePreview:
- {
- [self toggleBoxes:@[fMovieView, fMoviePlaybackControlBox, fEncodingControlBox, fPictureControlBox]
- usingIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)]];
+ [self.window makeFirstResponder:hud.view];
+ [self startHudTimer];
+ self.currentHUD = hud;
+}
- [fMovieCreationProgressIndicator stopAnimation:self];
- [self initPreviewScrubberForMovie];
- [self startMovieTimer];
+#pragma mark - HUD Control Overlay
- // Install movie notifications
- [self addMovieObservers];
- }
- break;
+- (void)mouseEntered:(NSEvent *)theEvent
+{
+ if (self.generator)
+ {
+ NSView *hud = self.currentHUD.view;
- default:
- break;
+ [self showHudWithAnimation:hud];
+ [self startHudTimer];
}
-
- self.currentViewMode = mode;
+ self.mouseInWindow = YES;
}
-#pragma mark -
-#pragma mark Hud Control Overlay
+- (void)mouseExited:(NSEvent *)theEvent
+{
+ [self hudTimerFired:nil];
+ self.mouseInWindow = NO;
+}
- (void)mouseMoved:(NSEvent *)theEvent
{
[super mouseMoved:theEvent];
- NSPoint mouseLoc = [theEvent locationInWindow];
- /* Test for mouse location to show/hide hud controls */
- if (self.currentViewMode != ViewModeEncoding && self.generator)
+ // Test for mouse location to show/hide hud controls
+ if (self.generator && self.mouseInWindow)
{
- /* Since we are not encoding, verify which control hud to show
- * or hide based on aMovie ( aMovie indicates we need movie controls )
- */
- NSView *hud;
- if (self.currentViewMode == !ViewModeMoviePreview) // No movie loaded up
- {
- hud = fPictureControlBox;
- }
- else // We have a movie
- {
- hud = fMoviePlaybackControlBox;
- }
+ NSView *hud = self.currentHUD.view;
+ NSPoint mouseLoc = theEvent.locationInWindow;
- if (NSPointInRect(mouseLoc, [hud frame]))
+ if (NSPointInRect(mouseLoc, hud.frame))
{
- [self showHudWithAnimation:hud];
[self stopHudTimer];
}
- else if (NSPointInRect(mouseLoc, [[[self window] contentView] frame]))
+ else
{
[self showHudWithAnimation:hud];
[self startHudTimer];
}
- else
- {
- [self hideHudWithAnimation:hud];
- [self stopHudTimer];
- }
}
}
@@ -524,13 +360,13 @@ typedef enum ViewMode : NSUInteger {
// The standard view animator doesn't play
// nicely with the Yosemite visual effects yet.
// So let's do the fade ourself.
- if (hud.layer.opacity == 0 || [hud isHidden])
+ if (hud.layer.opacity == 0 || hud.isHidden)
{
[hud setHidden:NO];
[CATransaction begin];
CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
- fadeInAnimation.fromValue = @(0.0);
+ fadeInAnimation.fromValue = @([hud.layer.presentationLayer opacity]);
fadeInAnimation.toValue = @(1.0);
fadeInAnimation.beginTime = 0.0;
fadeInAnimation.duration = ANIMATION_DUR;
@@ -547,41 +383,28 @@ typedef enum ViewMode : NSUInteger {
if (hud.layer.opacity != 0)
{
[CATransaction begin];
- [CATransaction setCompletionBlock:^{
- if (hud.layer.opacity == 0)
- {
- [hud setHidden:YES];
- }
- }];
- CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
- fadeInAnimation.fromValue = @([hud.layer.presentationLayer opacity]);
- fadeInAnimation.toValue = @(0.0);
- fadeInAnimation.beginTime = 0.0;
- fadeInAnimation.duration = ANIMATION_DUR;
+ CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ fadeOutAnimation.fromValue = @([hud.layer.presentationLayer opacity]);
+ fadeOutAnimation.toValue = @(0.0);
+ fadeOutAnimation.beginTime = 0.0;
+ fadeOutAnimation.duration = ANIMATION_DUR;
- [hud.layer addAnimation:fadeInAnimation forKey:nil];
+ [hud.layer addAnimation:fadeOutAnimation forKey:nil];
[hud.layer setOpacity:0];
[CATransaction commit];
}
}
-- (void)hideHud
-{
- [fPictureControlBox setHidden:YES];
- [fMoviePlaybackControlBox setHidden:YES];
- [fEncodingControlBox setHidden:YES];
-}
-
- (void)startHudTimer
{
if (self.hudTimer)
{
- [self.hudTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:8.0]];
+ [self.hudTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:HUD_FADEOUT_TIME]];
}
else
{
- self.hudTimer = [NSTimer scheduledTimerWithTimeInterval:8.0 target:self selector:@selector(hudTimerFired:)
+ self.hudTimer = [NSTimer scheduledTimerWithTimeInterval:HUD_FADEOUT_TIME target:self selector:@selector(hudTimerFired:)
userInfo:nil repeats:YES];
}
}
@@ -592,18 +415,21 @@ typedef enum ViewMode : NSUInteger {
self.hudTimer = nil;
}
-- (void)hudTimerFired: (NSTimer *)theTimer
+- (void)hudTimerFired:(NSTimer *)theTimer
{
- // Regardless which control box is active, after the timer
- // period we want either one to fade to hidden.
- [self hideHudWithAnimation:fPictureControlBox];
- [self hideHudWithAnimation:fMoviePlaybackControlBox];
-
+ if (self.currentHUD.canBeHidden)
+ {
+ [self hideHudWithAnimation:self.currentHUD.view];
+ }
[self stopHudTimer];
}
-#pragma mark -
-#pragma mark Still previews mode
+#pragma mark - Still previews mode
+
+- (void)enterPictureState
+{
+ [self displayPreviewAtIndex:self.pictureHUD.selectedIndex];
+}
/**
* Adjusts the window to draw the current picture (fPicture) adjusting its size as
@@ -611,6 +437,11 @@ typedef enum ViewMode : NSUInteger {
*/
- (void)displayPreviewAtIndex:(NSUInteger)idx
{
+ if (!self.generator)
+ {
+ return;
+ }
+
if (self.window.isVisible)
{
CGImageRef fPreviewImage = [self.generator copyImageAtIndex:idx shouldCache:YES];
@@ -625,33 +456,18 @@ typedef enum ViewMode : NSUInteger {
// Scale the window to the image size
NSSize windowSize = [self.previewView optimalViewSizeForImageSize:imageScaledSize minSize:NSMakeSize(MIN_WIDTH, MIN_HEIGHT)];
- [self resizeWindowForViewSize:windowSize animate:self.window.isVisible];
+ [self.window HB_resizeToBestSizeForViewSize:windowSize center:self.windowCenterPoint animate:self.window.isVisible];
}
[self updateSizeLabels];
}
-- (IBAction)previewDurationPopUpChanged:(id)sender
-{
- [[NSUserDefaults standardUserDefaults] setObject:[fPreviewMovieLengthPopUp titleOfSelectedItem] forKey:@"PreviewLength"];
-}
-
-- (IBAction)pictureSliderChanged:(id)sender
-{
- if ((self.pictureIndex != [fPictureSlider intValue] || !sender) && self.generator) {
- self.pictureIndex = [fPictureSlider intValue];
- [self displayPreviewAtIndex:self.pictureIndex];
- }
-}
-
-- (IBAction)toggleScaleToScreen:(id)sender
+- (void)toggleScaleToScreen
{
if (self.previewView.fitToView == YES)
{
self.previewView.fitToView = NO;
- fScaleToScreenToggleButton.title = NSLocalizedString(@"Scale To Screen", nil);
-
- [self displayPreviewAtIndex:self.pictureIndex];
+ [self displayPreviewAtIndex:self.pictureHUD.selectedIndex];
}
else
{
@@ -660,11 +476,10 @@ typedef enum ViewMode : NSUInteger {
{
[self.window setFrame:self.window.screen.visibleFrame display:YES animate:YES];
}
- fScaleToScreenToggleButton.title = NSLocalizedString(@"Actual Scale", nil);
}
}
-- (IBAction) showPictureSettings: (id) sender
+- (void)showPictureSettings
{
if (self.pictureSettingsWindow == nil)
{
@@ -676,299 +491,137 @@ typedef enum ViewMode : NSUInteger {
[self.pictureSettingsWindow showWindow:self];
}
-#pragma mark -
-#pragma mark Movie preview mode
-
-- (void) updateProgress: (double) progress info: (NSString *) progressInfo {
- [fPreviewMovieStatusField setStringValue: progressInfo];
+#pragma mark - Encoding mode
- [fMovieCreationProgressIndicator setIndeterminate: NO];
- [fMovieCreationProgressIndicator setDoubleValue: progress];
-}
-
-- (void)didCancelMovieCreation
-{
- [self switchViewToMode:ViewModePicturePreview];
-}
-
-- (void) didCreateMovieAtURL: (NSURL *) fileURL
+- (void)enterEncodingState
{
- /* Load the new movie into fMovieView */
- if (fileURL)
- {
- NSError *outError;
- NSDictionary *movieAttributes = @{QTMovieURLAttribute: fileURL,
- QTMovieAskUnresolvedDataRefsAttribute: @NO,
- @"QTMovieOpenForPlaybackAttribute": @YES,
- @"QTMovieOpenAsyncRequiredAttribute": @NO,
- @"QTMovieOpenAsyncOKAttribute": @NO,
- @"QTMovieIsSteppableAttribute": @YES,
- QTMovieApertureModeAttribute: QTMovieApertureModeClean};
-
- QTMovie *movie = [[QTMovie alloc] initWithAttributes:movieAttributes error:&outError];
-
- if (!movie)
- {
- NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"HandBrake can't open the preview.", nil)
- defaultButton:NSLocalizedString(@"Open in external player", nil)
- alternateButton:NSLocalizedString(@"Cancel", nil)
- otherButton:nil
- informativeTextWithFormat:NSLocalizedString(@"HandBrake can't playback this combination of video/audio/container format. Do you want to open it in an external player?", nil)];
- [alert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
- if (returnCode == NSModalResponseOK)
- {
- [[NSWorkspace sharedWorkspace] openURL:fileURL];
- }
- }];
- [self switchViewToMode:ViewModePicturePreview];
- }
- else
- {
- // Scale the fMovieView to the picture player size
- [fMovieView setFrame:self.previewView.pictureFrame];
-
- [fMovieView setMovie:movie];
- [movie setDelegate:self];
-
- // get and enable subtitles
- NSArray *subtitlesArray = [movie tracksOfMediaType:QTMediaTypeSubtitle];
- if (subtitlesArray.count)
- {
- // enable the first tx3g subtitle track
- [subtitlesArray[0] setEnabled:YES];
- }
- else
- {
- // Perian subtitles
- subtitlesArray = [movie tracksOfMediaType: QTMediaTypeVideo];
- if (subtitlesArray.count >= 2)
- {
- // track 0 should be video, other video tracks should
- // be subtitles; force-enable the first subs track
- [subtitlesArray[1] setEnabled:YES];
- }
- }
-
- // to actually play the movie
- self.movie = movie;
-
- [self switchViewToMode:ViewModeMoviePreview];
-
- [fMovieView play:movie];
- }
- }
+ self.encodingHUD.progress = 0;
}
-- (IBAction) cancelCreateMoviePreview: (id) sender
+- (void)cancelEncoding
{
[self.generator cancel];
}
-- (IBAction) createMoviePreview: (id) sender
+- (void)createMoviePreviewWithPictureIndex:(NSUInteger)index duration:(NSUInteger)duration
{
- if (!self.generator)
- return;
-
- if ([self.generator createMovieAsyncWithImageAtIndex:self.pictureIndex
- duration:[[fPreviewMovieLengthPopUp titleOfSelectedItem] intValue]])
+ if ([self.generator createMovieAsyncWithImageAtIndex:index duration:duration])
{
- [self switchViewToMode:ViewModeEncoding];
+ [self switchStateToHUD:self.encodingHUD];
}
}
-- (IBAction) toggleMoviePreviewPlayPause: (id) sender
+- (void)updateProgress:(double)progress info:(NSString *)progressInfo
{
- // make sure a movie is even loaded up
- if (self.movie)
- {
- if ([self.movie isPlaying]) // we are playing
- {
- [fMovieView pause:self.movie];
- [fPlayPauseButton setState: NSOnState];
- }
- else // we are paused or stopped
- {
- [fMovieView play:self.movie];
- [fPlayPauseButton setState: NSOffState];
- }
- }
+ self.encodingHUD.progress = progress;
+ self.encodingHUD.info = progressInfo;
}
-- (IBAction) moviePlaybackGoToBeginning: (id) sender
+- (void)didCancelMovieCreation
{
- [fMovieView gotoBeginning:self.movie];
+ [self switchStateToHUD:self.pictureHUD];
}
-- (IBAction) moviePlaybackGoToEnd: (id) sender
+- (void)showAlert:(NSURL *)fileURL;
{
- [fMovieView gotoEnd:self.movie];
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"HandBrake can't open the preview.", nil)
+ defaultButton:NSLocalizedString(@"Open in external player", nil)
+ alternateButton:NSLocalizedString(@"Cancel", nil)
+ otherButton:nil
+ informativeTextWithFormat:NSLocalizedString(@"HandBrake can't playback this combination of video/audio/container format. Do you want to open it in an external player?", nil)];
+
+ [alert beginSheetModalForWindow:self.window modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:(void *)CFBridgingRetain(fileURL)];
}
-- (void) startMovieTimer
+- (void)alertDidEnd:(NSAlert *)alert
+ returnCode:(NSInteger)returnCode
+ contextInfo:(void *)contextInfo
{
- if (!self.movieTimer)
+ NSURL *fileURL = CFBridgingRelease(contextInfo);
+ if (returnCode == NSModalResponseOK)
{
- self.movieTimer = [NSTimer scheduledTimerWithTimeInterval:0.09 target:self
- selector:@selector(movieTimerFired:)
- userInfo:nil repeats:YES];
+ [[NSWorkspace sharedWorkspace] openURL:fileURL];
}
}
-- (void) stopMovieTimer
-{
- [self.movieTimer invalidate];
- self.movieTimer = nil;
-}
-
-- (void) movieTimerFired: (NSTimer *)theTimer
+- (void)setUpPlaybackOfURL:(NSURL *)fileURL;
{
- if (self.movie != nil)
+ if (self.player.isPlayable && self.currentHUD == self.encodingHUD)
{
- [self adjustPreviewScrubberForCurrentMovieTime];
- [fMovieInfoField setStringValue: [self.movie timecode]];
+ [self switchStateToHUD:self.playerHUD];
+ }
+ else
+ {
+ [self showAlert:fileURL];
+ [self switchStateToHUD:self.pictureHUD];
}
}
-- (IBAction) showPicturesPreview: (id) sender
+- (void)didCreateMovieAtURL:(NSURL *)fileURL
{
- [self switchViewToMode:ViewModePicturePreview];
-}
+ if (fileURL)
+ {
+ self.player = [[HBAVPlayer alloc] initWithURL:fileURL];
-#pragma mark -
-#pragma mark Movie Playback Scrubber
+ if (self.player)
+ {
+ [self.player loadPlayableValueAsynchronouslyWithCompletionHandler:^{
-// Initialize the preview scrubber min/max to appropriate values for the current movie
-- (void) initPreviewScrubberForMovie
-{
- QTTime duration = [self.movie duration];
- CGFloat result = duration.timeValue / duration.timeScale;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self setUpPlaybackOfURL:fileURL];
+ });
- [fMovieScrubberSlider setMinValue:0.0];
- [fMovieScrubberSlider setMaxValue: result];
- [fMovieScrubberSlider setDoubleValue: 0.0];
+ }];
+ }
+ else
+ {
+ [self showAlert:fileURL];
+ [self switchStateToHUD:self.pictureHUD];
+ }
+ }
}
-- (void) adjustPreviewScrubberForCurrentMovieTime
-{
- QTTime time = [self.movie currentTime];
-
- CGFloat result = (CGFloat)time.timeValue / (CGFloat)time.timeScale;;
- [fMovieScrubberSlider setDoubleValue:result];
-}
+#pragma mark - Player mode
-- (IBAction) previewScrubberChanged: (id) sender
+- (void)enterPlayerState
{
- [fMovieView pause:self.movie];
- [self.movie setCurrentTimeDouble:[fMovieScrubberSlider doubleValue]];
- [fMovieInfoField setStringValue: [self.movie timecode]];
-}
+ // Scale the layer to the picture player size
+ CALayer *playerLayer = self.player.layer;
+ playerLayer.frame = self.previewView.pictureFrame;
-#pragma mark -
-#pragma mark Movie Notifications
+ [self.window.contentView.layer insertSublayer:playerLayer atIndex:1];
-- (void) addMovieObservers
-{
- // Notification for any time the movie rate changes
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(movieRateDidChange:)
- name:@"QTMovieRateDidChangeNotification"
- object:self.movie];
+ self.playerHUD.player = self.player;
}
-- (void) removeMovieObservers
+- (void)exitPlayerState
{
- // Notification for any time the movie rate changes
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:@"QTMovieRateDidChangeNotification"
- object:self.movie];
+ self.playerHUD.player = nil;
+ [self.player pause];
+ [self.player.layer removeFromSuperlayer];
+ self.player = nil;
}
-- (void) movieRateDidChange: (NSNotification *) notification
+- (void)stopPlayer
{
- if (self.movie.isPlaying)
- [fPlayPauseButton setState: NSOnState];
- else
- [fPlayPauseButton setState: NSOffState];
+ [self switchStateToHUD:self.pictureHUD];
}
-#pragma mark -
-#pragma mark Keyboard and mouse wheel control
+#pragma mark - Scroll
-/* fMovieView Keyboard controls */
-- (void) keyDown: (NSEvent *) event
+- (void)keyDown:(NSEvent *)event
{
- unichar key = [[event charactersIgnoringModifiers] characterAtIndex:0];
- QTMovie *movie = self.movie;
-
- if (movie)
- {
- if (key == 32)
- {
- if ([movie isPlaying])
- [fMovieView pause:movie];
- else
- [fMovieView play:movie];
- }
- else if (key == 'k')
- [fMovieView pause:movie];
- else if (key == 'l')
- {
- float rate = [movie rate];
- rate += 1.0f;
- [fMovieView play:movie];
- [movie setRate:rate];
- }
- else if (key == 'j')
- {
- float rate = [movie rate];
- rate -= 1.0f;
- [fMovieView play:movie];
- [movie setRate:rate];
- }
- else if ([event modifierFlags] & NSAlternateKeyMask && key == NSLeftArrowFunctionKey)
- [fMovieView gotoBeginning:self];
- else if ([event modifierFlags] & NSAlternateKeyMask && key == NSRightArrowFunctionKey)
- [fMovieView gotoEnd:self];
- else if (key == NSLeftArrowFunctionKey)
- [fMovieView stepBackward:self];
- else if (key == NSRightArrowFunctionKey)
- [fMovieView stepForward:self];
- else
- [super keyDown:event];
- }
- else if (self.currentViewMode != ViewModeEncoding)
+ if ([self.currentHUD HB_keyDown:event] == NO)
{
- if (key == NSLeftArrowFunctionKey)
- {
- [fPictureSlider setIntegerValue:self.pictureIndex > [fPictureSlider minValue] ? self.pictureIndex - 1 : self.pictureIndex];
- [self pictureSliderChanged:self];
- }
- else if (key == NSRightArrowFunctionKey)
- {
- [fPictureSlider setIntegerValue:self.pictureIndex < [fPictureSlider maxValue] ? self.pictureIndex + 1 : self.pictureIndex];
- [self pictureSliderChanged:self];
- }
- else
- [super keyDown:event];
- }
- else
[super keyDown:event];
+ }
}
-- (void)scrollWheel:(NSEvent *)theEvent
+- (void)scrollWheel:(NSEvent *)event
{
- if (self.currentViewMode != ViewModeEncoding)
+ if ([self.currentHUD HB_scrollWheel:event] == NO)
{
- if (theEvent.deltaY < 0)
- {
- [fPictureSlider setIntegerValue:self.pictureIndex < [fPictureSlider maxValue] ? self.pictureIndex + 1 : self.pictureIndex];
- [self pictureSliderChanged:self];
- }
- else if (theEvent.deltaY > 0)
- {
- [fPictureSlider setIntegerValue:self.pictureIndex > [fPictureSlider minValue] ? self.pictureIndex - 1 : self.pictureIndex];
- [self pictureSliderChanged:self];
- }
+ [super scrollWheel:event];
}
}
diff --git a/macosx/HBQTKitPlayer.h b/macosx/HBQTKitPlayer.h
new file mode 100644
index 000000000..a9a9de54a
--- /dev/null
+++ b/macosx/HBQTKitPlayer.h
@@ -0,0 +1,28 @@
+/* HBQTKitPlayer.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Foundation/Foundation.h>
+#import <QuartzCore/QuartzCore.h>
+
+#import "HBPlayer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface HBQTKitPlayer : NSObject <HBPlayer>
+
+@property (nonatomic, readonly) CALayer *layer;
+
+@property (nonatomic, readonly) NSTimeInterval duration;
+@property (nonatomic) NSTimeInterval currentTime;
+
+@property (nonatomic) float rate;
+@property (nonatomic) float volume;
+
+@property (nonatomic, readonly, getter=isPlayable) BOOL playable;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/macosx/HBQTKitPlayer.m b/macosx/HBQTKitPlayer.m
new file mode 100644
index 000000000..012edc01b
--- /dev/null
+++ b/macosx/HBQTKitPlayer.m
@@ -0,0 +1,404 @@
+/* HBQTKitPlayer.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import "HBQTKitPlayer.h"
+#import <QTKit/QTKit.h>
+
+@import HandBrakeKit;
+
+@interface QTTrack (HBAdditions)
+- (id)isoLanguageCodeAsString;
+@end
+
+typedef void (^HBPeriodicObverser)(NSTimeInterval time);
+typedef void (^HBRateObverser)(void);
+typedef void (^HBPlayableObverser)(void);
+
+@interface HBQTKitPlayerPeriodicObserver : NSObject
+
+@property (nonatomic) HBPeriodicObverser block;
+
+- (void)postNotification:(NSTimeInterval)time;
+
+@end
+
+@implementation HBQTKitPlayerPeriodicObserver
+
+- (void)postNotification:(NSTimeInterval)time
+{
+ self.block(time);
+}
+
+@end
+
+@interface HBQTKitPlayerRateObserver : NSObject
+
+@property (nonatomic) HBRateObverser block;
+
+- (void)postNotification;
+
+@end
+
+@implementation HBQTKitPlayerRateObserver
+
+- (void)postNotification;
+{
+ self.block();
+}
+
+@end
+
+@interface HBQTKitPlayer ()
+
+@property (nonatomic, strong) QTMovie *movie;
+@property (nonatomic, strong) NSTimer *timer;
+
+@property (nonatomic, readwrite, getter=isPlayable) BOOL playable;
+
+@property (nonatomic, strong) NSMutableSet<HBQTKitPlayerPeriodicObserver *> *periodicObservers;
+@property (nonatomic, strong) NSMutableSet<HBQTKitPlayerRateObserver *> *rateObservers;
+
+@property (nonatomic, strong) NSMutableSet<HBPlayableObverser> *playableObservers;
+
+@end
+
+@implementation HBQTKitPlayer
+
+- (instancetype)initWithURL:(NSURL *)url
+{
+ self = [super init];
+
+ if (self)
+ {
+ NSError *outError;
+ NSDictionary *attributes = @{ QTMovieURLAttribute: url,
+ QTMovieAskUnresolvedDataRefsAttribute: @NO,
+ QTMovieOpenForPlaybackAttribute: @YES,
+ QTMovieIsSteppableAttribute: @YES,
+ QTMovieOpenAsyncRequiredAttribute: @YES,
+ QTMovieApertureModeAttribute: QTMovieApertureModeClean };
+
+ _movie = [[QTMovie alloc] initWithAttributes:attributes error:&outError];
+
+ if (!_movie)
+ {
+ return nil;
+ }
+
+ _movie.delegate = self;
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(_movieRateDidChange:)
+ name:QTMovieRateDidChangeNotification
+ object:_movie];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(_loadStateChanged:)
+ name:QTMovieLoadStateDidChangeNotification
+ object:_movie];
+
+ _layer = [QTMovieLayer layerWithMovie:_movie];
+
+ if (!_layer)
+ {
+ return nil;
+ }
+
+ _periodicObservers = [NSMutableSet set];
+ _rateObservers = [NSMutableSet set];
+ _playableObservers = [NSMutableSet set];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [self _stopMovieTimer];
+}
+
+- (void)setPlayable:(BOOL)playable
+{
+ _playable = playable;
+
+ for (HBPlayableObverser block in self.playableObservers)
+ {
+ block();
+ }
+ [self.playableObservers removeAllObjects];
+}
+
+- (void)_loadStateChanged:(NSNotification *)notification
+{
+ int loadState = [[self.movie attributeForKey:QTMovieLoadStateAttribute] intValue];
+
+ if (loadState >= QTMovieLoadStateLoaded)
+ {
+ [self _enableSubtitles];
+ self.playable = YES;
+ }
+}
+
+- (void)_movieRateDidChange:(NSNotification *)notification
+{
+ for (HBQTKitPlayerRateObserver *observer in self.rateObservers)
+ {
+ [observer postNotification];
+ }
+}
+
+- (void)_enableSubtitles
+{
+ // Get and enable subtitles
+ NSArray<QTTrack *> *subtitlesArray = [self.movie tracksOfMediaType:QTMediaTypeSubtitle];
+ if (subtitlesArray.count)
+ {
+ // enable the first tx3g subtitle track
+ [subtitlesArray.firstObject setEnabled:YES];
+ }
+ else
+ {
+ // Perian subtitles
+ subtitlesArray = [self.movie tracksOfMediaType:QTMediaTypeVideo];
+ if (subtitlesArray.count >= 2)
+ {
+ // track 0 should be video, other video tracks should
+ // be subtitles; force-enable the first subs track
+ [subtitlesArray[1] setEnabled:YES];
+ }
+ }
+}
+
+- (void)_startMovieTimer
+{
+ if (!self.timer)
+ {
+ self.timer = [NSTimer scheduledTimerWithTimeInterval:0.09 target:self
+ selector:@selector(_timerFired:)
+ userInfo:nil repeats:YES];
+ }
+}
+
+- (void)_stopMovieTimer
+{
+ [self.timer invalidate];
+ self.timer = nil;
+}
+
+- (void)_timerFired:(NSTimer *)timer
+{
+ for (HBQTKitPlayerPeriodicObserver *observer in self.periodicObservers)
+ {
+ [observer postNotification:self.currentTime];
+ }
+}
+
+#pragma mark Public properties
+
+- (NSArray<HBPlayerTrack *> *)tracksWithMediaType:(NSString *)mediaType
+{
+ NSMutableArray *result = [NSMutableArray array];
+ NSArray<QTTrack *> *tracks = [self.movie tracksOfMediaType:mediaType];
+ for (QTTrack *track in tracks)
+ {
+ NSNumber *trackID = [track attributeForKey:QTTrackIDAttribute];
+ NSString *name = NSLocalizedString(@"Unknown", nil);
+
+ if ([track respondsToSelector:@selector(isoLanguageCodeAsString)])
+ {
+ NSString *language = [track isoLanguageCodeAsString];
+ name = [HBUtilities languageCodeForIso6392Code:language];
+ }
+ BOOL enabled = [[track attributeForKey:QTTrackEnabledAttribute] boolValue];
+
+ HBPlayerTrack *playerTrack = [[HBPlayerTrack alloc] initWithTrackName:name object:trackID enabled:enabled];
+
+ [result addObject:playerTrack];
+ }
+ return result;
+}
+
+@synthesize audioTracks = _audioTracks;
+
+- (NSArray<HBPlayerTrack *> *)audioTracks
+{
+ if (_audioTracks == nil)
+ {
+ _audioTracks = [self tracksWithMediaType:QTMediaTypeSound];
+ }
+ return _audioTracks;
+}
+
+@synthesize subtitlesTracks = _subtitlesTracks;
+
+- (NSArray<HBPlayerTrack *> *)subtitlesTracks
+{
+ if (_subtitlesTracks == nil)
+ {
+ _subtitlesTracks = [self tracksWithMediaType:QTMediaTypeSubtitle];
+ }
+ return _subtitlesTracks;
+}
+
+- (void)_enableTrack:(HBPlayerTrack *)playerTrack mediaType:(NSString *)mediaType
+{
+ NSArray<QTTrack *> *tracks = [self.movie tracksOfMediaType:mediaType];
+ for (QTTrack *track in tracks)
+ {
+ NSNumber *trackID = [track attributeForKey:QTTrackIDAttribute];
+
+ if ([trackID isEqualTo:playerTrack.representedObject])
+ {
+ [track setEnabled:YES];
+ }
+ else
+ {
+ [track setEnabled:NO];
+ }
+ }
+}
+
+- (void)enableAudioTrack:(HBPlayerTrack *)playerTrack
+{
+ for (HBPlayerTrack *track in self.audioTracks)
+ {
+ track.enabled = NO;
+ }
+ playerTrack.enabled = YES;
+ [self _enableTrack:playerTrack mediaType:QTMediaTypeSound];
+}
+
+- (void)enableSubtitlesTrack:(HBPlayerTrack *)playerTrack
+{
+ for (HBPlayerTrack *track in self.subtitlesTracks)
+ {
+ track.enabled = NO;
+ }
+ playerTrack.enabled = YES;
+ [self _enableTrack:playerTrack mediaType:QTMediaTypeSubtitle];
+}
+
+- (NSTimeInterval)duration
+{
+ QTTime duration = [self.movie duration];
+ return (double)duration.timeValue / (double)duration.timeScale;;
+}
+
+- (NSTimeInterval)currentTime
+{
+ QTTime time = [self.movie currentTime];
+ return (double)time.timeValue / (double)time.timeScale;;
+}
+
+- (void)setCurrentTime:(NSTimeInterval)value
+{
+ long timeScale = [[self.movie attributeForKey:QTMovieTimeScaleAttribute] longValue];
+ [self.movie setCurrentTime:QTMakeTime((long long)value * timeScale, timeScale)];
+ [self _timerFired:nil];
+}
+
+- (void)setRate:(float)rate
+{
+ self.movie.rate = rate;
+}
+
+- (float)rate
+{
+ return self.movie.rate;
+}
+
+- (float)volume
+{
+ return self.movie.volume;
+}
+
+- (void)setVolume:(float)volume
+{
+ self.movie.volume = volume;
+}
+
+#pragma mark public methods
+
+- (void)loadPlayableValueAsynchronouslyWithCompletionHandler:(nullable void (^)(void))handler;
+{
+ if (self.playable)
+ {
+ handler();
+ }
+ else
+ {
+ [self.playableObservers addObject:handler];
+ }
+}
+
+- (id)addPeriodicTimeObserverUsingBlock:(void (^)(NSTimeInterval time))block
+{
+ HBQTKitPlayerPeriodicObserver *observer = [[HBQTKitPlayerPeriodicObserver alloc] init];
+ observer.block = block;
+ [self.periodicObservers addObject:observer];
+
+ [self _startMovieTimer];
+
+ return observer;
+}
+
+- (void)removeTimeObserver:(id)observer
+{
+ [self.periodicObservers removeObject:observer];
+}
+
+- (id)addRateObserverUsingBlock:(void (^)(void))block
+{
+ HBQTKitPlayerRateObserver *observer = [[HBQTKitPlayerRateObserver alloc] init];
+ observer.block = block;
+ [self.rateObservers addObject:observer];
+
+ return observer;
+}
+
+- (void)removeRateObserver:(id)observer
+{
+ [self.rateObservers removeObject:observer];
+}
+
+- (void)play
+{
+ [self.movie play];
+ [self _startMovieTimer];
+}
+
+- (void)pause
+{
+ [self.movie stop];
+ [self _stopMovieTimer];
+}
+
+- (void)gotoBeginning
+{
+ [self.movie gotoBeginning];
+ [self _timerFired:nil];
+}
+
+- (void)gotoEnd
+{
+ [self.movie gotoEnd];
+ [self _timerFired:nil];
+}
+
+- (void)stepForward
+{
+ [self.movie stepForward];
+ [self _timerFired:nil];
+}
+
+- (void)stepBackward
+{
+ [self.movie stepBackward];
+ [self _timerFired:nil];
+}
+
+@end
diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj
index e83fe377d..1deb670c4 100644
--- a/macosx/HandBrake.xcodeproj/project.pbxproj
+++ b/macosx/HandBrake.xcodeproj/project.pbxproj
@@ -63,13 +63,13 @@
27D6C77314B102DA00B785E4 /* libxml2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C74014B102DA00B785E4 /* libxml2.a */; };
3490BCB41614CF8D002A5AD7 /* HandBrake.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3490BCB31614CF8D002A5AD7 /* HandBrake.icns */; };
6F0D69A91AD0683100A39DCA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273F204014ADBC210021BE6D /* Foundation.framework */; };
+ A903C5601CCE78060026B0ED /* NSWindow+HBAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A903C55F1CCE78060026B0ED /* NSWindow+HBAdditions.m */; };
A91119A21C7DD58B001C463C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273F203B14ADBC210021BE6D /* Cocoa.framework */; };
A91119A31C7DD591001C463C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273F202214ADB8650021BE6D /* IOKit.framework */; };
A91119A41C7DD614001C463C /* HBSubtitlesDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F4728B1976BAA70009EC65 /* HBSubtitlesDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; };
A91119A51C7DD644001C463C /* HBDistributedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E66D6E1A67A2A8007B641D /* HBDistributedArray.h */; settings = {ATTRIBUTES = (Public, ); }; };
A91119A61C7DD64A001C463C /* HBDistributedArray.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E66D6F1A67A2A8007B641D /* HBDistributedArray.m */; };
A914BCB31BC441C700157917 /* HBPreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = A914BCB21BC441C700157917 /* HBPreviewView.m */; };
- A914BCB61BC441D100157917 /* QTKit+HBQTMovieExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = A914BCB51BC441D100157917 /* QTKit+HBQTMovieExtensions.m */; };
A916180E1C845161000556C6 /* NSDictionary+HBAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A93B0DF71C804CF50051A3FA /* NSDictionary+HBAdditions.m */; };
A916C9921C84498F00C7B560 /* DockTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 46AB433415F98A2B009C0961 /* DockTextField.m */; };
A916C9931C8449A100C7B560 /* HBAddPresetController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E2FD251A21BC4A000E8D3F /* HBAddPresetController.m */; };
@@ -170,12 +170,21 @@
A92268781A6E555500A8D5C5 /* HBAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A92268771A6E555500A8D5C5 /* HBAppDelegate.m */; };
A922687B1A6E569B00A8D5C5 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = A92268791A6E569B00A8D5C5 /* MainWindow.xib */; };
A932E26C1988334B0047D13E /* AudioDefaults.xib in Resources */ = {isa = PBXBuildFile; fileRef = A932E26A1988334B0047D13E /* AudioDefaults.xib */; };
+ A9350F501CCA7F490089F970 /* HBQTKitPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = A9350F4E1CCA7C3B0089F970 /* HBQTKitPlayer.m */; };
A937EECB1C6C7C0300EEAE6D /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = A937EECA1C6C7C0300EEAE6D /* dsa_pub.pem */; };
A93E0ED31972957000FD67FB /* HBVideoController.m in Sources */ = {isa = PBXBuildFile; fileRef = A93E0ED11972957000FD67FB /* HBVideoController.m */; };
A93E0ED71972958C00FD67FB /* Video.xib in Resources */ = {isa = PBXBuildFile; fileRef = A93E0ED51972958C00FD67FB /* Video.xib */; };
A94A98F51C858EFB004BA9BA /* HBDictTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A94A98F41C858EFB004BA9BA /* HBDictTests.m */; };
A95121E61B5F7BE700FD773D /* NSArray+HBAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A95121E51B5F7BE700FD773D /* NSArray+HBAdditions.m */; };
A955128B1A320B02001BFC6F /* libjansson.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A95512881A320A12001BFC6F /* libjansson.a */; };
+ A95BC1E71CD2548A008D6A33 /* volHighTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A95BC1E51CD2548A008D6A33 /* volHighTemplate.pdf */; };
+ A95BC1E81CD2548A008D6A33 /* volLowTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A95BC1E61CD2548A008D6A33 /* volLowTemplate.pdf */; };
+ A96664B01CCE45BF00DA4A57 /* HBPlayerHUDController.m in Sources */ = {isa = PBXBuildFile; fileRef = A96664AE1CCE45BF00DA4A57 /* HBPlayerHUDController.m */; };
+ A96664B11CCE45BF00DA4A57 /* HBPlayerHUDController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A96664AF1CCE45BF00DA4A57 /* HBPlayerHUDController.xib */; };
+ A96664B51CCE48F700DA4A57 /* HBPictureHUDController.m in Sources */ = {isa = PBXBuildFile; fileRef = A96664B31CCE48F700DA4A57 /* HBPictureHUDController.m */; };
+ A96664B61CCE48F700DA4A57 /* HBPictureHUDController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A96664B41CCE48F700DA4A57 /* HBPictureHUDController.xib */; };
+ A96664BA1CCE493D00DA4A57 /* HBEncodingProgressHUDController.m in Sources */ = {isa = PBXBuildFile; fileRef = A96664B81CCE493D00DA4A57 /* HBEncodingProgressHUDController.m */; };
+ A96664BB1CCE493D00DA4A57 /* HBEncodingProgressHUDController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A96664B91CCE493D00DA4A57 /* HBEncodingProgressHUDController.xib */; };
A9706CB41AC1436F00BAEAA8 /* HBApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = A9706CB31AC1436F00BAEAA8 /* HBApplication.m */; };
A9706CB71AC1437800BAEAA8 /* HBExceptionAlertController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9706CB61AC1437800BAEAA8 /* HBExceptionAlertController.m */; };
A9706CBA1AC1452800BAEAA8 /* ExceptionAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9706CB81AC1452800BAEAA8 /* ExceptionAlert.xib */; };
@@ -184,6 +193,7 @@
A9736F171C7DA5FE008F1D18 /* HandBrakeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9736F021C7DA5FE008F1D18 /* HandBrakeKit.framework */; };
A9736F181C7DA5FE008F1D18 /* HandBrakeKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = A9736F021C7DA5FE008F1D18 /* HandBrakeKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
A9736F1F1C7DA667008F1D18 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 273F204014ADBC210021BE6D /* Foundation.framework */; };
+ A98036CD1CCA91DD007661AA /* HBAVPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = A98036CC1CCA91DD007661AA /* HBAVPlayer.m */; };
A98B8E241C7DD2A200B810C9 /* HBPresetCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = A997D8EB1A4ABB0900E19B6F /* HBPresetCoding.h */; settings = {ATTRIBUTES = (Public, ); }; };
A98C29C41977B10600AF5DED /* HBLanguagesSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */; };
A98F38071C7DCA7E00E469C8 /* HBStateFormatter+Private.m in Sources */ = {isa = PBXBuildFile; fileRef = A98F38051C7DCA7E00E469C8 /* HBStateFormatter+Private.m */; };
@@ -191,6 +201,7 @@
A9935213196F38A70069C6B7 /* ChaptersTitles.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9935211196F38A70069C6B7 /* ChaptersTitles.xib */; };
A99F40CF1B624E7E00750170 /* HBPictureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A99F40CD1B624E7E00750170 /* HBPictureViewController.m */; };
A99F40D31B624EA500750170 /* HBPictureViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A99F40D11B624EA500750170 /* HBPictureViewController.xib */; };
+ A9A0CBE81CCEA3670045B3DF /* HBPlayerTrack.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A0CBE61CCEA1D10045B3DF /* HBPlayerTrack.m */; };
A9BB0F2719A0ECE40079F1C1 /* HBHUDButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A9BB0F2619A0ECE40079F1C1 /* HBHUDButtonCell.m */; };
A9BC24C91A69293E007DC41A /* HBAttributedStringAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A9BC24C81A69293E007DC41A /* HBAttributedStringAdditions.m */; };
A9C0DB85197E7B0000DF55B3 /* SubtitlesDefaults.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9C0DB83197E7B0000DF55B3 /* SubtitlesDefaults.xib */; };
@@ -207,10 +218,10 @@
A9DF49291C884C4E008AC14A /* HBMockTitle.m in Sources */ = {isa = PBXBuildFile; fileRef = A9DF49251C884C4E008AC14A /* HBMockTitle.m */; };
A9DF492A1C884C4E008AC14A /* HBPresetsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A9DF49261C884C4E008AC14A /* HBPresetsTests.m */; };
A9E1467B16BC2ABD00C307BC /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E1467A16BC2ABD00C307BC /* QuartzCore.framework */; };
- A9E1468016BC2AD800C307BC /* next-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467C16BC2AD800C307BC /* next-p.pdf */; };
- A9E1468116BC2AD800C307BC /* pause-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467D16BC2AD800C307BC /* pause-p.pdf */; };
- A9E1468216BC2AD800C307BC /* play-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467E16BC2AD800C307BC /* play-p.pdf */; };
- A9E1468316BC2AD800C307BC /* prev-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467F16BC2AD800C307BC /* prev-p.pdf */; };
+ A9E1468016BC2AD800C307BC /* NextTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467C16BC2AD800C307BC /* NextTemplate.pdf */; };
+ A9E1468116BC2AD800C307BC /* PauseTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467D16BC2AD800C307BC /* PauseTemplate.pdf */; };
+ A9E1468216BC2AD800C307BC /* PlayTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467E16BC2AD800C307BC /* PlayTemplate.pdf */; };
+ A9E1468316BC2AD800C307BC /* PrevTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467F16BC2AD800C307BC /* PrevTemplate.pdf */; };
A9E165521C523016003EF30E /* libavfilter.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E165511C523016003EF30E /* libavfilter.a */; };
A9E2FD2B1A21BC6F000E8D3F /* AddPreset.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9E2FD291A21BC6F000E8D3F /* AddPreset.xib */; };
A9F2EB6F196F12C800066546 /* Audio.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9F2EB6D196F12C800066546 /* Audio.xib */; };
@@ -371,14 +382,14 @@
3490BCB31614CF8D002A5AD7 /* HandBrake.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = HandBrake.icns; sourceTree = "<group>"; };
46AB433315F98A2B009C0961 /* DockTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DockTextField.h; sourceTree = "<group>"; };
46AB433415F98A2B009C0961 /* DockTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DockTextField.m; sourceTree = "<group>"; };
+ A903C55E1CCE78060026B0ED /* NSWindow+HBAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSWindow+HBAdditions.h"; sourceTree = "<group>"; };
+ A903C55F1CCE78060026B0ED /* NSWindow+HBAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSWindow+HBAdditions.m"; sourceTree = "<group>"; };
A90A0CAD1988D57200DA65CE /* HBAudioTrackPreset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAudioTrackPreset.h; sourceTree = "<group>"; };
A90A0CAE1988D57200DA65CE /* HBAudioTrackPreset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAudioTrackPreset.m; sourceTree = "<group>"; };
A91017B21A64440A00039BFB /* HBSubtitles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitles.h; sourceTree = "<group>"; };
A91017B31A64440A00039BFB /* HBSubtitles.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitles.m; sourceTree = "<group>"; };
A914BCB11BC441C700157917 /* HBPreviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPreviewView.h; sourceTree = "<group>"; };
A914BCB21BC441C700157917 /* HBPreviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPreviewView.m; sourceTree = "<group>"; };
- A914BCB41BC441D100157917 /* QTKit+HBQTMovieExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "QTKit+HBQTMovieExtensions.h"; sourceTree = "<group>"; };
- A914BCB51BC441D100157917 /* QTKit+HBQTMovieExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "QTKit+HBQTMovieExtensions.m"; sourceTree = "<group>"; };
A9160A331AE7A165009A7818 /* HBCodingUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBCodingUtilities.h; sourceTree = "<group>"; };
A9160A341AE7A165009A7818 /* HBCodingUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBCodingUtilities.m; sourceTree = "<group>"; };
A91726E5197291BC00D1AFEF /* HBChapterTitlesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBChapterTitlesController.h; sourceTree = "<group>"; };
@@ -403,6 +414,8 @@
A932E26E198833920047D13E /* HBAudioDefaultsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAudioDefaultsController.m; sourceTree = "<group>"; };
A932E271198834130047D13E /* HBAudioDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAudioDefaults.h; sourceTree = "<group>"; };
A932E272198834130047D13E /* HBAudioDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAudioDefaults.m; sourceTree = "<group>"; };
+ A9350F4D1CCA7C3B0089F970 /* HBQTKitPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBQTKitPlayer.h; sourceTree = "<group>"; };
+ A9350F4E1CCA7C3B0089F970 /* HBQTKitPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBQTKitPlayer.m; sourceTree = "<group>"; };
A937EECA1C6C7C0300EEAE6D /* dsa_pub.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = dsa_pub.pem; sourceTree = "<group>"; };
A93B0DF61C804CF50051A3FA /* NSDictionary+HBAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+HBAdditions.h"; sourceTree = "<group>"; };
A93B0DF71C804CF50051A3FA /* NSDictionary+HBAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+HBAdditions.m"; sourceTree = "<group>"; };
@@ -411,6 +424,7 @@
A93E0ED61972958C00FD67FB /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Video.xib; sourceTree = "<group>"; };
A93FD4731A62ABE800A6AC43 /* HBAudio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAudio.h; sourceTree = "<group>"; };
A93FD4741A62ABE800A6AC43 /* HBAudio.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAudio.m; sourceTree = "<group>"; };
+ A941ACB91CD75B4E0029D06A /* HBHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBHUD.h; sourceTree = "<group>"; };
A94A98F41C858EFB004BA9BA /* HBDictTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBDictTests.m; sourceTree = "<group>"; };
A95121E41B5F7BE700FD773D /* NSArray+HBAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+HBAdditions.h"; sourceTree = "<group>"; };
A95121E51B5F7BE700FD773D /* NSArray+HBAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+HBAdditions.m"; sourceTree = "<group>"; };
@@ -427,6 +441,17 @@
A95512881A320A12001BFC6F /* libjansson.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjansson.a; path = external/contrib/lib/libjansson.a; sourceTree = BUILT_PRODUCTS_DIR; };
A9597A281A49749D00007771 /* HBRange+UIAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "HBRange+UIAdditions.h"; sourceTree = "<group>"; };
A9597A291A49749D00007771 /* HBRange+UIAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "HBRange+UIAdditions.m"; sourceTree = "<group>"; };
+ A95BC1E51CD2548A008D6A33 /* volHighTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = volHighTemplate.pdf; sourceTree = "<group>"; };
+ A95BC1E61CD2548A008D6A33 /* volLowTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = volLowTemplate.pdf; sourceTree = "<group>"; };
+ A96664AD1CCE45BF00DA4A57 /* HBPlayerHUDController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPlayerHUDController.h; sourceTree = "<group>"; };
+ A96664AE1CCE45BF00DA4A57 /* HBPlayerHUDController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPlayerHUDController.m; sourceTree = "<group>"; };
+ A96664AF1CCE45BF00DA4A57 /* HBPlayerHUDController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HBPlayerHUDController.xib; sourceTree = "<group>"; };
+ A96664B21CCE48F700DA4A57 /* HBPictureHUDController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPictureHUDController.h; sourceTree = "<group>"; };
+ A96664B31CCE48F700DA4A57 /* HBPictureHUDController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPictureHUDController.m; sourceTree = "<group>"; };
+ A96664B41CCE48F700DA4A57 /* HBPictureHUDController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HBPictureHUDController.xib; sourceTree = "<group>"; };
+ A96664B71CCE493D00DA4A57 /* HBEncodingProgressHUDController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBEncodingProgressHUDController.h; sourceTree = "<group>"; };
+ A96664B81CCE493D00DA4A57 /* HBEncodingProgressHUDController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBEncodingProgressHUDController.m; sourceTree = "<group>"; };
+ A96664B91CCE493D00DA4A57 /* HBEncodingProgressHUDController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HBEncodingProgressHUDController.xib; sourceTree = "<group>"; };
A96CD1741BCC5F9100F372F1 /* HBMutablePreset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBMutablePreset.h; sourceTree = "<group>"; };
A96CD1751BCC5F9100F372F1 /* HBMutablePreset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBMutablePreset.m; sourceTree = "<group>"; };
A9706CB21AC1436F00BAEAA8 /* HBApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBApplication.h; sourceTree = "<group>"; };
@@ -443,6 +468,8 @@
A9736F141C7DA5FE008F1D18 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A975C08C1AE8C5270061870D /* HBStateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBStateFormatter.h; sourceTree = "<group>"; };
A975C08D1AE8C5270061870D /* HBStateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBStateFormatter.m; sourceTree = "<group>"; };
+ A98036CB1CCA91DD007661AA /* HBAVPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAVPlayer.h; sourceTree = "<group>"; };
+ A98036CC1CCA91DD007661AA /* HBAVPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAVPlayer.m; sourceTree = "<group>"; };
A988AF9B1BC7C35F00932543 /* HBChapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBChapter.h; sourceTree = "<group>"; };
A988AF9C1BC7C35F00932543 /* HBChapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBChapter.m; sourceTree = "<group>"; };
A98C29C21977B10600AF5DED /* HBLanguagesSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBLanguagesSelection.h; sourceTree = "<group>"; };
@@ -460,6 +487,8 @@
A99F40CC1B624E7E00750170 /* HBPictureViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPictureViewController.h; sourceTree = "<group>"; };
A99F40CD1B624E7E00750170 /* HBPictureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPictureViewController.m; sourceTree = "<group>"; };
A99F40D21B624EA500750170 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = HBPictureViewController.xib; sourceTree = "<group>"; };
+ A9A0CBE51CCEA1D10045B3DF /* HBPlayerTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPlayerTrack.h; sourceTree = "<group>"; };
+ A9A0CBE61CCEA1D10045B3DF /* HBPlayerTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPlayerTrack.m; sourceTree = "<group>"; };
A9AA44781970664A00D7DEFC /* HBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HBUtilities.h; path = ../HBUtilities.h; sourceTree = "<group>"; };
A9AA44791970664A00D7DEFC /* HBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HBUtilities.m; path = ../HBUtilities.m; sourceTree = "<group>"; };
A9AA447B1970724D00D7DEFC /* HBAdvancedController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBAdvancedController.h; sourceTree = "<group>"; };
@@ -476,6 +505,7 @@
A9C1839C1A716BCC00C897C2 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = HBTitleSelection.xib; sourceTree = "<group>"; };
A9C9F88719A733FE00DC8923 /* HBHUDView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBHUDView.h; sourceTree = "<group>"; };
A9C9F88819A733FE00DC8923 /* HBHUDView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBHUDView.m; sourceTree = "<group>"; };
+ A9CAC26E1CCB6B0F00A39E72 /* HBPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPlayer.h; sourceTree = "<group>"; };
A9CF25F01990D62C0023F727 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Presets.xib; sourceTree = "<group>"; };
A9CF25F21990D64E0023F727 /* HBPreset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPreset.h; sourceTree = "<group>"; };
A9CF25F31990D64E0023F727 /* HBPreset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPreset.m; sourceTree = "<group>"; };
@@ -505,10 +535,10 @@
A9DF49251C884C4E008AC14A /* HBMockTitle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBMockTitle.m; sourceTree = "<group>"; };
A9DF49261C884C4E008AC14A /* HBPresetsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPresetsTests.m; sourceTree = "<group>"; };
A9E1467A16BC2ABD00C307BC /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
- A9E1467C16BC2AD800C307BC /* next-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "next-p.pdf"; sourceTree = "<group>"; };
- A9E1467D16BC2AD800C307BC /* pause-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "pause-p.pdf"; sourceTree = "<group>"; };
- A9E1467E16BC2AD800C307BC /* play-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "play-p.pdf"; sourceTree = "<group>"; };
- A9E1467F16BC2AD800C307BC /* prev-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "prev-p.pdf"; sourceTree = "<group>"; };
+ A9E1467C16BC2AD800C307BC /* NextTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = NextTemplate.pdf; sourceTree = "<group>"; };
+ A9E1467D16BC2AD800C307BC /* PauseTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = PauseTemplate.pdf; sourceTree = "<group>"; };
+ A9E1467E16BC2AD800C307BC /* PlayTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = PlayTemplate.pdf; sourceTree = "<group>"; };
+ A9E1467F16BC2AD800C307BC /* PrevTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = PrevTemplate.pdf; sourceTree = "<group>"; };
A9E165511C523016003EF30E /* libavfilter.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavfilter.a; path = external/contrib/lib/libavfilter.a; sourceTree = BUILT_PRODUCTS_DIR; };
A9E2FD241A21BC4A000E8D3F /* HBAddPresetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAddPresetController.h; sourceTree = "<group>"; };
A9E2FD251A21BC4A000E8D3F /* HBAddPresetController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBAddPresetController.m; sourceTree = "<group>"; };
@@ -775,10 +805,12 @@
273F212014ADCBF70021BE6D /* pdf icons */ = {
isa = PBXGroup;
children = (
- A9E1467C16BC2AD800C307BC /* next-p.pdf */,
- A9E1467D16BC2AD800C307BC /* pause-p.pdf */,
- A9E1467E16BC2AD800C307BC /* play-p.pdf */,
- A9E1467F16BC2AD800C307BC /* prev-p.pdf */,
+ A9E1467C16BC2AD800C307BC /* NextTemplate.pdf */,
+ A9E1467D16BC2AD800C307BC /* PauseTemplate.pdf */,
+ A9E1467E16BC2AD800C307BC /* PlayTemplate.pdf */,
+ A9E1467F16BC2AD800C307BC /* PrevTemplate.pdf */,
+ A95BC1E51CD2548A008D6A33 /* volHighTemplate.pdf */,
+ A95BC1E61CD2548A008D6A33 /* volLowTemplate.pdf */,
);
name = "pdf icons";
path = icons;
@@ -873,10 +905,8 @@
A901C2411BC7CFFD00D77735 /* Preview */ = {
isa = PBXGroup;
children = (
- A9BB0F2519A0ECE40079F1C1 /* HBHUDButtonCell.h */,
- A9BB0F2619A0ECE40079F1C1 /* HBHUDButtonCell.m */,
- A9C9F88719A733FE00DC8923 /* HBHUDView.h */,
- A9C9F88819A733FE00DC8923 /* HBHUDView.m */,
+ A903C55E1CCE78060026B0ED /* NSWindow+HBAdditions.h */,
+ A903C55F1CCE78060026B0ED /* NSWindow+HBAdditions.m */,
A914BCB11BC441C700157917 /* HBPreviewView.h */,
A914BCB21BC441C700157917 /* HBPreviewView.m */,
273F20A914ADBE670021BE6D /* HBPictureController.h */,
@@ -885,6 +915,8 @@
273F20A414ADBE670021BE6D /* HBPreviewController.m */,
A9AA447D1970729300D7DEFC /* HBPreviewGenerator.h */,
A9D1E41618262364002F6424 /* HBPreviewGenerator.m */,
+ A93E6F2E1CD774960096C0DE /* Player */,
+ A9CAC26D1CCB6AE500A39E72 /* HUD */,
);
name = Preview;
sourceTree = "<group>";
@@ -916,8 +948,6 @@
A9706CB61AC1437800BAEAA8 /* HBExceptionAlertController.m */,
A95121E41B5F7BE700FD773D /* NSArray+HBAdditions.h */,
A95121E51B5F7BE700FD773D /* NSArray+HBAdditions.m */,
- A914BCB41BC441D100157917 /* QTKit+HBQTMovieExtensions.h */,
- A914BCB51BC441D100157917 /* QTKit+HBQTMovieExtensions.m */,
273F20BD14ADC09F0021BE6D /* main.mm */,
);
name = Others;
@@ -945,6 +975,20 @@
name = "Audio Defaults";
sourceTree = "<group>";
};
+ A93E6F2E1CD774960096C0DE /* Player */ = {
+ isa = PBXGroup;
+ children = (
+ A9CAC26E1CCB6B0F00A39E72 /* HBPlayer.h */,
+ A9A0CBE51CCEA1D10045B3DF /* HBPlayerTrack.h */,
+ A9A0CBE61CCEA1D10045B3DF /* HBPlayerTrack.m */,
+ A9350F4D1CCA7C3B0089F970 /* HBQTKitPlayer.h */,
+ A9350F4E1CCA7C3B0089F970 /* HBQTKitPlayer.m */,
+ A98036CB1CCA91DD007661AA /* HBAVPlayer.h */,
+ A98036CC1CCA91DD007661AA /* HBAVPlayer.m */,
+ );
+ name = Player;
+ sourceTree = "<group>";
+ };
A952392E199A647F00588AEF /* Presets */ = {
isa = PBXGroup;
children = (
@@ -1130,6 +1174,27 @@
name = "UI Views";
sourceTree = "<group>";
};
+ A9CAC26D1CCB6AE500A39E72 /* HUD */ = {
+ isa = PBXGroup;
+ children = (
+ A941ACB91CD75B4E0029D06A /* HBHUD.h */,
+ A9BB0F2519A0ECE40079F1C1 /* HBHUDButtonCell.h */,
+ A9BB0F2619A0ECE40079F1C1 /* HBHUDButtonCell.m */,
+ A9C9F88719A733FE00DC8923 /* HBHUDView.h */,
+ A9C9F88819A733FE00DC8923 /* HBHUDView.m */,
+ A96664B21CCE48F700DA4A57 /* HBPictureHUDController.h */,
+ A96664B31CCE48F700DA4A57 /* HBPictureHUDController.m */,
+ A96664B41CCE48F700DA4A57 /* HBPictureHUDController.xib */,
+ A96664B71CCE493D00DA4A57 /* HBEncodingProgressHUDController.h */,
+ A96664B81CCE493D00DA4A57 /* HBEncodingProgressHUDController.m */,
+ A96664B91CCE493D00DA4A57 /* HBEncodingProgressHUDController.xib */,
+ A96664AD1CCE45BF00DA4A57 /* HBPlayerHUDController.h */,
+ A96664AE1CCE45BF00DA4A57 /* HBPlayerHUDController.m */,
+ A96664AF1CCE45BF00DA4A57 /* HBPlayerHUDController.xib */,
+ );
+ name = HUD;
+ sourceTree = "<group>";
+ };
A9F472851976B7AA0009EC65 /* Subtitles Defaults */ = {
isa = PBXGroup;
children = (
@@ -1319,6 +1384,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ A96664B61CCE48F700DA4A57 /* HBPictureHUDController.xib in Resources */,
A9F2EB6F196F12C800066546 /* Audio.xib in Resources */,
A9CF25F11990D62C0023F727 /* Presets.xib in Resources */,
A9C1839D1A716BCC00C897C2 /* HBTitleSelection.xib in Resources */,
@@ -1332,14 +1398,18 @@
D86C9DD51C6D372500F06F1B /* Assets.xcassets in Resources */,
273F218F14ADDDA10021BE6D /* PictureSettings.xib in Resources */,
273F219014ADDDA10021BE6D /* Preferences.xib in Resources */,
+ A95BC1E71CD2548A008D6A33 /* volHighTemplate.pdf in Resources */,
A922687B1A6E569B00A8D5C5 /* MainWindow.xib in Resources */,
+ A96664B11CCE45BF00DA4A57 /* HBPlayerHUDController.xib in Resources */,
273F219114ADDDA10021BE6D /* Queue.xib in Resources */,
3490BCB41614CF8D002A5AD7 /* HandBrake.icns in Resources */,
- A9E1468016BC2AD800C307BC /* next-p.pdf in Resources */,
- A9E1468116BC2AD800C307BC /* pause-p.pdf in Resources */,
- A9E1468216BC2AD800C307BC /* play-p.pdf in Resources */,
- A9E1468316BC2AD800C307BC /* prev-p.pdf in Resources */,
+ A9E1468016BC2AD800C307BC /* NextTemplate.pdf in Resources */,
+ A9E1468116BC2AD800C307BC /* PauseTemplate.pdf in Resources */,
+ A9E1468216BC2AD800C307BC /* PlayTemplate.pdf in Resources */,
+ A96664BB1CCE493D00DA4A57 /* HBEncodingProgressHUDController.xib in Resources */,
+ A9E1468316BC2AD800C307BC /* PrevTemplate.pdf in Resources */,
A937EECB1C6C7C0300EEAE6D /* dsa_pub.pem in Resources */,
+ A95BC1E81CD2548A008D6A33 /* volLowTemplate.pdf in Resources */,
A9C0DB85197E7B0000DF55B3 /* SubtitlesDefaults.xib in Resources */,
A9DC6C56196F0517002AE6B4 /* Subtitles.xib in Resources */,
A99F40D31B624EA500750170 /* HBPictureViewController.xib in Resources */,
@@ -1382,8 +1452,11 @@
files = (
A916C99B1C844A0800C7B560 /* HBQueueOutlineView.m in Sources */,
A916C99A1C8449FB00C7B560 /* HBHUDView.m in Sources */,
+ A9350F501CCA7F490089F970 /* HBQTKitPlayer.m in Sources */,
A916C9991C8449E200C7B560 /* main.mm in Sources */,
A916C9981C8449DB00C7B560 /* HBTitleSelectionController.m in Sources */,
+ A903C5601CCE78060026B0ED /* NSWindow+HBAdditions.m in Sources */,
+ A9A0CBE81CCEA3670045B3DF /* HBPlayerTrack.m in Sources */,
A916C9971C8449CA00C7B560 /* HBAudioDefaultsController.m in Sources */,
A916C9961C8449BE00C7B560 /* HBJobOutputFileWriter.m in Sources */,
A916C9951C8449B000C7B560 /* HBChapterTitlesController.m in Sources */,
@@ -1393,6 +1466,7 @@
273F20B514ADBE670021BE6D /* HBPreferencesController.m in Sources */,
273F20AC14ADBE670021BE6D /* HBController.m in Sources */,
A93E0ED31972957000FD67FB /* HBVideoController.m in Sources */,
+ A96664B01CCE45BF00DA4A57 /* HBPlayerHUDController.m in Sources */,
A99F40CF1B624E7E00750170 /* HBPictureViewController.m in Sources */,
273F20AF14ADBE670021BE6D /* HBAudioController.m in Sources */,
A9DC6C52196F04F6002AE6B4 /* HBSubtitlesController.m in Sources */,
@@ -1401,11 +1475,12 @@
A9906B2C1A710920001D82D5 /* HBQueueController.m in Sources */,
A9F7102619A475EC00F61301 /* HBDockTile.m in Sources */,
A98C29C41977B10600AF5DED /* HBLanguagesSelection.m in Sources */,
+ A96664BA1CCE493D00DA4A57 /* HBEncodingProgressHUDController.m in Sources */,
A9BB0F2719A0ECE40079F1C1 /* HBHUDButtonCell.m in Sources */,
A9706CB71AC1437800BAEAA8 /* HBExceptionAlertController.m in Sources */,
A92268781A6E555500A8D5C5 /* HBAppDelegate.m in Sources */,
+ A98036CD1CCA91DD007661AA /* HBAVPlayer.m in Sources */,
A9BC24C91A69293E007DC41A /* HBAttributedStringAdditions.m in Sources */,
- A914BCB61BC441D100157917 /* QTKit+HBQTMovieExtensions.m in Sources */,
273F20B214ADBE670021BE6D /* HBImageAndTextCell.m in Sources */,
273F20B314ADBE670021BE6D /* HBOutputPanelController.m in Sources */,
273F20B414ADBE670021BE6D /* HBOutputRedirect.m in Sources */,
@@ -1413,6 +1488,7 @@
A9D0FA7A1C1C36820003F2A9 /* HBTabView.m in Sources */,
A91AFD0C1A948827009BECED /* HBOutputFileWriter.m in Sources */,
A95121E61B5F7BE700FD773D /* NSArray+HBAdditions.m in Sources */,
+ A96664B51CCE48F700DA4A57 /* HBPictureHUDController.m in Sources */,
A914BCB31BC441C700157917 /* HBPreviewView.m in Sources */,
273F20B714ADBE670021BE6D /* HBPreviewController.m in Sources */,
A9D1E41718262364002F6424 /* HBPreviewGenerator.m in Sources */,
diff --git a/macosx/NSWindow+HBAdditions.h b/macosx/NSWindow+HBAdditions.h
new file mode 100644
index 000000000..e8ceb3c04
--- /dev/null
+++ b/macosx/NSWindow+HBAdditions.h
@@ -0,0 +1,25 @@
+//
+// NSWindow+HBAdditions.h
+// HandBrake
+//
+// Created by Damiano Galassi on 25/04/16.
+//
+//
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSWindow (HBAdditions)
+
+/**
+ * Resizes the entire window to accomodate a view of a particular size.
+ */
+- (void)HB_resizeToBestSizeForViewSize:(NSSize)viewSize center:(NSPoint)center animate:(BOOL)performAnimation;
+
+
+/**
+ * Calculates and returns the center point of the window
+ */
+- (NSPoint)HB_centerPoint;
+
+
+@end
diff --git a/macosx/NSWindow+HBAdditions.m b/macosx/NSWindow+HBAdditions.m
new file mode 100644
index 000000000..2951d7a1f
--- /dev/null
+++ b/macosx/NSWindow+HBAdditions.m
@@ -0,0 +1,79 @@
+//
+// NSWindow+HBAdditions.m
+// HandBrake
+//
+// Created by Damiano Galassi on 25/04/16.
+//
+//
+
+#import "NSWindow+HBAdditions.h"
+
+@implementation NSWindow (HBAdditions)
+
+- (void)HB_resizeToBestSizeForViewSize:(NSSize)viewSize center:(NSPoint)center animate:(BOOL)animateFlag
+{
+ NSSize currentSize = self.contentView.frame.size;
+ NSRect frame = self.frame;
+
+ // Calculate border around content region of the frame
+ int borderX = (int)(frame.size.width - currentSize.width);
+ int borderY = (int)(frame.size.height - currentSize.height);
+
+ // Make sure the frame is smaller than the screen
+ NSSize maxSize = self.screen.visibleFrame.size;
+
+ // if we are not Scale To Screen, put an 10% of visible screen on the window
+ maxSize.width = maxSize.width * 0.90;
+ maxSize.height = maxSize.height * 0.90;
+
+ // Set the new frame size
+ // Add the border to the new frame size so that the content region
+ // of the frame is large enough to accomodate the preview image
+ frame.size.width = viewSize.width + borderX;
+ frame.size.height = viewSize.height + borderY;
+
+ // compare frame to max size of screen
+ if (frame.size.width > maxSize.width)
+ {
+ frame.size.width = maxSize.width;
+ }
+ if (frame.size.height > maxSize.height)
+ {
+ frame.size.height = maxSize.height;
+ }
+
+ // Since upon launch we can open up the preview window if it was open
+ // the last time we quit (and at the size it was) we want to make
+ // sure that upon resize we do not have the window off the screen
+ // So check the origin against the screen origin and adjust if
+ // necessary.
+ NSSize screenSize = self.screen.visibleFrame.size;
+ NSPoint screenOrigin = self.screen.visibleFrame.origin;
+
+ frame.origin.x = center.x - floor(frame.size.width / 2);
+ frame.origin.y = center.y - floor(frame.size.height / 2);
+
+ // our origin is off the screen to the left
+ if (frame.origin.x < screenOrigin.x)
+ {
+ // so shift our origin to the right
+ frame.origin.x = screenOrigin.x;
+ }
+ else if ((frame.origin.x + frame.size.width) > (screenOrigin.x + screenSize.width))
+ {
+ // the right side of the preview is off the screen, so shift to the left
+ frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width;
+ }
+
+ [self setFrame:frame display:YES animate:animateFlag];
+}
+
+- (NSPoint)HB_centerPoint
+{
+ NSPoint center = NSMakePoint(floor(self.frame.origin.x + self.frame.size.width / 2),
+ floor(self.frame.origin.y + self.frame.size.height / 2));
+ return center;
+}
+
+
+@end
diff --git a/macosx/QTKit+HBQTMovieExtensions.h b/macosx/QTKit+HBQTMovieExtensions.h
deleted file mode 100644
index dadea3d1d..000000000
--- a/macosx/QTKit+HBQTMovieExtensions.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* QTKit+HBQTMovieExtensions.h
-
- This file is part of the HandBrake source code.
- Homepage: <http://handbrake.fr/>.
- It may be used under the terms of the GNU General Public License. */
-
-#import <Cocoa/Cocoa.h>
-#import <QTKit/QTKit.h>
-
-@interface QTMovieView (HBQTMovieViewExtensions)
-
-- (void)mouseMoved:(NSEvent *)theEvent;
-
-@end
-
-@interface QTMovie (HBQTMovieExtensions)
-
-- (BOOL)isPlaying;
-- (NSString *)timecode;
-- (void)setCurrentTimeDouble:(double)value;
-
-@end
diff --git a/macosx/QTKit+HBQTMovieExtensions.m b/macosx/QTKit+HBQTMovieExtensions.m
deleted file mode 100644
index 903659ec9..000000000
--- a/macosx/QTKit+HBQTMovieExtensions.m
+++ /dev/null
@@ -1,49 +0,0 @@
-/* QTKit+HBQTMovieExtensions.m
-
- This file is part of the HandBrake source code.
- Homepage: <http://handbrake.fr/>.
- It may be used under the terms of the GNU General Public License. */
-
-#import "QTKit+HBQTMovieExtensions.h"
-
-@implementation QTMovieView (HBQTMovieViewExtensions)
-
-- (void)mouseMoved:(NSEvent *)theEvent
-{
- [super mouseMoved:theEvent];
-}
-
-@end
-
-@implementation QTMovie (HBQTMovieExtensions)
-
-- (BOOL)isPlaying
-{
- if (self.rate > 0)
- {
- return YES;
- }
- else
- {
- return NO;
- }
-}
-
-- (NSString *)timecode
-{
- QTTime time = [self currentTime];
- double timeInSeconds = (double)time.timeValue / time.timeScale;
- UInt16 seconds = (UInt16)fmod(timeInSeconds, 60.0);
- UInt16 minutes = (UInt16)fmod(timeInSeconds / 60.0, 60.0);
- UInt16 hours = (UInt16)(timeInSeconds / (60.0 * 60.0));
- UInt16 milliseconds = (UInt16)(timeInSeconds - (int) timeInSeconds) * 1000;
- return [NSString stringWithFormat:@"%02d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds];
-}
-
-- (void)setCurrentTimeDouble:(double)value
-{
- long timeScale = [[self attributeForKey:QTMovieTimeScaleAttribute] longValue];
- [self setCurrentTime:QTMakeTime((long long)value * timeScale, timeScale)];
-}
-
-@end \ No newline at end of file
diff --git a/macosx/icons/next-p.pdf b/macosx/icons/NextTemplate.pdf
index bb11381cd..bb11381cd 100644
--- a/macosx/icons/next-p.pdf
+++ b/macosx/icons/NextTemplate.pdf
Binary files differ
diff --git a/macosx/icons/pause-p.pdf b/macosx/icons/PauseTemplate.pdf
index 6a6224a75..6a6224a75 100644
--- a/macosx/icons/pause-p.pdf
+++ b/macosx/icons/PauseTemplate.pdf
Binary files differ
diff --git a/macosx/icons/play-p.pdf b/macosx/icons/PlayTemplate.pdf
index 028feb270..028feb270 100644
--- a/macosx/icons/play-p.pdf
+++ b/macosx/icons/PlayTemplate.pdf
Binary files differ
diff --git a/macosx/icons/prev-p.pdf b/macosx/icons/PrevTemplate.pdf
index 7f37c9af7..7f37c9af7 100644
--- a/macosx/icons/prev-p.pdf
+++ b/macosx/icons/PrevTemplate.pdf
Binary files differ
diff --git a/macosx/icons/volHighTemplate.pdf b/macosx/icons/volHighTemplate.pdf
new file mode 100644
index 000000000..ee1f4e674
--- /dev/null
+++ b/macosx/icons/volHighTemplate.pdf
Binary files differ
diff --git a/macosx/icons/volLowTemplate.pdf b/macosx/icons/volLowTemplate.pdf
new file mode 100644
index 000000000..8a9b97274
--- /dev/null
+++ b/macosx/icons/volLowTemplate.pdf
Binary files differ