diff options
173 files changed, 17554 insertions, 11149 deletions
@@ -1,14 +1,15 @@ -$Id: AUTHORS,v 1.3 2004/03/08 11:32:48 titer Exp $ +$Id: AUTHORS,v 1.5 2005/03/23 13:14:50 titer Exp $ AUTHORS file for HandBrake <http://handbrake.m0k.org/> Eric Petit <[email protected]> + Core (construct, multithreading, BeOS/OS X/Linux ports) + MPEG demuxer - + MPEG-2 and AC3 decoders (w/ libmpeg2/liba52) + + MPEG-2, AC3 and MPGA decoders (w/ libmpeg2/liba52/libavcodec) + LPCM "decoder" + MPEG-4, MP3 and AAC encoders (w/ libavcodec/libxvidcore/libmp3lame/ libfaac) + + AC-3 pass-through + AVI muxer + MP4 muxer (w/ libmp4v2) + BeOS interface @@ -19,4 +20,5 @@ Laurent Aimar <[email protected]> + H264 and Vorbis encoders (w/ libx264/libvorbis) + OGG/OGM muxer (w/ libogg) + Gtk2 interface + + wxWidgets interface @@ -1,4 +1,4 @@ -$Id: BUILD,v 1.5 2004/03/29 00:28:39 titer Exp $ +$Id: BUILD,v 1.11 2005/10/23 01:35:59 titer Exp $ BUILD file for HandBrake <http://handbrake.m0k.org/> @@ -8,31 +8,21 @@ Building HandBrake You can build HandBrake on BeOS, MacOS X and Linux. If you'd like to port it to another OS, email me ([email protected]). -Step 1: get jam -=============== - -Jam <http://www.perforce.com/jam/jam.html> is a make replacement. -Get it for your operating system: - + BeOS: get <http://tfs.cs.tu-berlin.de/~bonefish/download/jam/jam.zip> - (the jam used by OBOS). Also, gcc 2.95.3 is needed. - + OS X: get <http://handbrake.m0k.org/files/jam-2.5rc3-OSX.zip> and - copy jam to /usr/local/bin/. Do not use the modified jam shipped with - the developer tools (/Developer/Private/jam). - + Debian: `apt-get install jam' -Or get the sources from the link above and compile it yourself. - -Step 2 (optional): set custom compiler flags -============================================ - -If you want to optimize the build for a specific CPU, edit the Jamrules -file and modify the "OPTIM = ..." line by adding the needed flags. - -In case you modify this line later: `jam clean' does not remove the -compiled contrib librairies. Therefore, make sure you run -`jam clean-all; jam' or `jam -a' in order to force jam to rebuild -everything with the new flags. - -Step 3: build +Step 1: get needed tools +======================== + ++ gcc and g++ + There are usually included in your OS' dev tools. On BeOS/Zeta, the + default gcc isn't enough, gcc 2.95.3 is required. ++ jam + I use 2.5rc3, earlier versions might cause issues. + On BeOS, you can download it at <http://www.haiku-os.org/develop.php>. + On OS X, you cannot use the modified jam shipped with the developer + tools, use this one instead: + <http://handbrake.m0k.org/files/jam-2.5rc3-OSX.zip>. ++ nasm (except for OS X) + +Step 2: build ============= Run `jam'. This will build every library HandBrake requires, then @@ -1,4 +1,4 @@ -# $Id: Jamfile,v 1.46 2004/04/26 09:02:07 titer Exp $ +# $Id: Jamfile,v 1.86 2005/11/04 13:09:40 titer Exp $ # # This file is part of the HandBrake source code. # Homepage: <http://handbrake.m0k.org/>. @@ -7,40 +7,49 @@ SubDir TOP ; # libhb + contrib libraries -HB_LIBS = libhb.a liba52.a libavcodec.a libdvdread.a - libdvdcss.a libfaac.a libmp3lame.a libmp4v2.a libmpeg2.a - libvorbis.a libvorbisenc.a libogg.a libsamplerate.a - libx264.a libxvidcore.a ; +HB_LIBS = libhb.a + contrib/lib/liba52.a contrib/lib/libavcodec.a + contrib/lib/libavutil.a contrib/lib/libdvdread.a + contrib/lib/libdvdcss.a contrib/lib/libfaac.a + contrib/lib/libmp3lame.a contrib/lib/libmp4v2.a + contrib/lib/libmpeg2.a contrib/lib/libvorbis.a + contrib/lib/libvorbisenc.a contrib/lib/libogg.a + contrib/lib/libsamplerate.a contrib/lib/libx264.a + contrib/lib/libxvidcore.a ; # Interfaces TEST_BIN = HBTest ; TEST_SRC = test/test.c ; BEOS_BIN = HandBrake ; -BEOS_SRC = beos/HBApp.cpp beos/HBWindow.cpp ; -GTK2_BIN = gtk2HB ; -GTK2_SRC = gtk2/main.c gtk2/callbacks.c gtk2/interface.c gtk2/support.c ; -GUI_BIN = $(TEST_BIN) $(BEOS_BIN) $(GTK2_BIN) ; -GUI_SRC = $(TEST_SRC) $(BEOS_SRC) $(GTK2_SRC) ; +BEOS_SRC = beos/HBApp.cpp beos/MainWindow.cpp beos/ScanWindow.cpp + beos/PicWindow.cpp beos/Stepper.cpp beos/QueueWindow.cpp ; +WX_BIN = wxHB ; +WX_SRC = wx/hbWizard.cpp wx/wxHB.cpp ; +UI_BIN = $(TEST_BIN) $(BEOS_BIN) $(WX_BIN) ; +UI_SRC = $(TEST_SRC) $(BEOS_SRC) $(WX_SRC) ; # CLI app Main $(TEST_BIN) : $(TEST_SRC) ; if $(OS) = BEOS { - SystemLibraries HandBrake : -lbe ; - # BeOS GUI is broken at the moment - # Main HandBrake : $(SRC_BEOS) ; + Main HandBrake : $(BEOS_SRC) ; + + BeOSPackage HandBrake-$(HB_VERSION)-BeOS.zip : HandBrake ; + HB_PACKAGES += HandBrake-$(HB_VERSION)-BeOS.zip ; } if $(OS) = MACOSX { - # Needed to clean HandBrake.app - RM = rm -rf ; - - OSX_SRC = macosx/Controller.h macosx/Controller.mm + OSX_SRC = macosx/main.mm macosx/Controller.h macosx/Controller.mm + macosx/ScanController.h macosx/ScanController.mm + macosx/PictureController.h macosx/PictureController.mm macosx/PictureGLView.h macosx/PictureGLView.mm - macosx/TargetSizeField.h macosx/TargetSizeField.mm - macosx/main.mm ; - + macosx/QueueController.h macosx/QueueController.mm + macosx/PrefsController.h macosx/PrefsController.m + macosx/English.lproj/InfoPlist.strings + macosx/English.lproj/MainMenu.nib/classes.nib + macosx/English.lproj/MainMenu.nib/info.nib + macosx/English.lproj/MainMenu.nib/keyedobjects.nib ; OSXApp HandBrake.app : $(OSX_SRC) $(HB_LIBS) ; # Package @@ -49,25 +58,19 @@ if $(OS) = MACOSX } if $(OS) = LINUX { - SystemLibraries $(TEST_BIN) : -lpthread ; - SystemLibraries $(GTK2_BIN) : -lpthread `pkg-config gtk+-2.0 --libs` ; - ObjectCcFlags $(GTK2_SRC) : `pkg-config gtk+-2.0 --cflags` ; - Main $(GTK2_BIN) : $(GTK2_SRC) ; -} -if $(OS) = CYGWIN -{ - SystemLibraries $(TEST_BIN) : -lws2_32 ; + # WX UI outdated + #SystemLibraries $(WX_BIN) : -lpthread `wx-config --libs` ; + #ObjectC++Flags $(WX_SRC) : `wx-config --cflags` ; + #Main $(WX_BIN) : $(WX_SRC) ; } -ObjectHdrs $(GUI_SRC) : $(TOP)/core ; -ObjectCcFlags $(GUI_SRC) : -g -Wall ; -ObjectC++Flags $(GUI_SRC) : -g -Wall ; -LinkLibraries $(GUI_BIN) : $(HB_LIBS) ; +ObjectHdrs $(UI_SRC) : $(TOP)/libhb ; +LinkLibraries $(UI_BIN) : $(HB_LIBS) ; # Packages NotFile package ; Depends package : $(HB_PACKAGES) ; SubInclude TOP contrib ; -SubInclude TOP core ; +SubInclude TOP libhb ; @@ -1,116 +1,21 @@ -# $Id: Jamrules,v 1.38 2004/05/25 17:50:12 titer Exp $ +# $Id: Jamrules,v 1.59 2005/11/04 16:06:21 titer Exp $ # # This file is part of the HandBrake source code. # Homepage: <http://handbrake.m0k.org/>. # It may be used under the terms of the GNU General Public License. -HB_VERSION = 0.6.2 ; -LANGUAGES = fr de it pl ru nl es pt ja ; +include config.jam ; -# Compilers & flags -CC = gcc ; -C++ = g++ ; -AS = nasm ; -LINK = g++ ; -OPTIM = -O3 -funroll-loops ; -DEFINES = HB_$(OS) HB_VERSION=\\\"$(HB_VERSION)\\\" ; - -if $(OS) = BEOS -{ - # Avoid multichar warnings caused by BeOS system headers - CCFLAGS = -Wno-multichar ; - C++FLAGS = -Wno-multichar ; - # BeOS' gcc tends to crash with -funroll-loops - OPTIM = -O3 ; - ASFLAGS = -f elf ; -} -if $(OS) = MACOSX -{ - # For libdvdread - DEFINES += WORDS_BIGENDIAN ; -} -if $(OS) = LINUX +if ! $(DEFINES) { - ASFLAGS = -f elf ; -} -if $(OS) = CYGWIN -{ - # Build under cygwin but without the emulation layer - CCFLAGS = -mno-cygwin ; - C++FLAGS = -mno-cygwin ; - LINKFLAGS = -mno-cygwin ; - ASFLAGS = -f win32 ; + Exit "Please run ./configure first." ; } -NotFile clean-contrib clean-all ; -Always clean-contrib ; -Depends clean-all : clean clean-contrib ; - -# _Object: same as Jambase's Object, except -# * those aren't cleaned by 'jam clean' (to prevent from deleting -# every contrib library by accident) -# * it handles *.asm files -rule _Object -{ - MakeLocate $(<) : $(LOCATE_TARGET) ; - SEARCH on $(>) = $(SEARCH_SOURCE) ; - HDRS on $(<) = $(SEARCH_SOURCE) $(SUBDIRHDRS) $(HDRS) ; - HDRRULE on $(>) = HdrRule ; - HDRSCAN on $(>) = $(HDRPATTERN) ; - HDRSEARCH on $(>) = - $(SEARCH_SOURCE:E) $(SUBDIRHDRS) $(HDRS) $(STDHDRS) ; - HDRGRIST on $(>) = $(HDRGRIST) ; - DEFINES on $(<) += $(DEFINES) ; - switch $(>:S) - { - case .asm : As $(<) : $(>) ; - case .nas : As $(<) : $(>) ; - case .c : Cc $(<) : $(>) ; - case .cpp : C++ $(<) : $(>) ; - } -} -# _Objects: use _Object -rule _Objects -{ - local _i ; - for _i in [ FGristFiles $(<) ] - { - _Object $(_i:S=$(SUFOBJ)) : $(_i) ; - Depends obj : $(_i:S=$(SUFOBJ)) ; - } -} - -# Simplified LibraryFromObjects which doesn't clean the target library -# nor the temporary .o files -rule _Library -{ - local _l _s ; - _s = [ FGristFiles $(>:S=$(SUFOBJ)) ] ; - _l = $(<:S=$(SUFLIB)) ; - _Objects $(>) ; - Depends obj : $(_s) ; - MakeLocate $(_l) $(_l)($(_s:BS)) : $(LOCATE_TARGET) ; - Depends $(_l) : $(_s) ; - Archive $(_l) : $(_s) ; - if $(RANLIB) { Ranlib $(_l) ; } - Depends lib : $(_l) ; -} - -# ContribLibrary: library cleaned by 'jam clean-contrib' -rule ContribLibrary -{ - _Library $(<) : $(>) ; - Clean clean-contrib : [ FGristFiles $(>:S=$(SUFOBJ)) ] ; - Clean clean-contrib : $(<:S=$(SUFLIB)) ; -} - -# Library: library cleaned by 'jam clean' -rule Library -{ - _Library $(<) : $(>) ; - Clean clean : [ FGristFiles $(>:S=$(SUFOBJ)) ] ; - Clean clean : $(<:S=$(SUFLIB)) ; -} +HB_VERSION = 0.7.0 ; +HB_BUILD = 2005110400 ; +DEFINES += HB_VERSION=\\\"$(HB_VERSION)\\\" HB_BUILD=$(HB_BUILD) ; +LANGUAGES = fr de it pl ru nl es pt ja ; +RM = rm -rf ; # Build HandBrake.app using Xcode rule OSXApp @@ -118,13 +23,12 @@ rule OSXApp Depends exe : $(<) ; Depends $(<) : $(>) ; Clean clean : $(1) macosx/build ; - BuildOSXApp $(<) ; } -actions BuildOSXApp +actions OSXApp { $(RM) $(<) macosx/build/HandBrake.app && \ ( cd macosx && xcodebuild ) && \ - cp -r macosx/build/HandBrake.app $(<) && \ + mv macosx/build/Default/HandBrake.app $(<) && \ for i in $(LANGUAGES) ; do \ ( cd $(<)/Contents/Resources && \ cp -r English.lproj $i.lproj && \ @@ -134,10 +38,9 @@ actions BuildOSXApp } rule OSXPackage { - Depends $(<) : $(>) ; - BuildOSXPackage $(<) ; + Depends $(<) : $(>) ; } -actions BuildOSXPackage +actions OSXPackage { rm -rf $(<) "HandBrake $(HB_VERSION)" && \ mkdir "HandBrake $(HB_VERSION)" && \ @@ -145,26 +48,35 @@ actions BuildOSXPackage cp COPYING "HandBrake $(HB_VERSION)/COPYING.txt" && \ cp CREDITS "HandBrake $(HB_VERSION)/CREDITS.txt" && \ cp THANKS "HandBrake $(HB_VERSION)/THANKS.txt" && \ - ( cd doc && ./genhtml.sh ) && \ - cp doc/faq.html "HandBrake $(HB_VERSION)/FAQ.html" && \ + ( echo "[InternetShortcut]" && \ + echo "URL=http://handbrake.m0k.org/" ) > \ + "HandBrake $(HB_VERSION)/HandBrake Homepage.url" && \ + ( echo "[InternetShortcut]" && \ + echo "URL=http://handbrake.m0k.org/forum/" ) > \ + "HandBrake $(HB_VERSION)/HandBrake Forums.url" && \ + ( echo "[InternetShortcut]" && \ + echo "URL=http://handbrake.m0k.org/contribute.php" ) > \ + "HandBrake $(HB_VERSION)/Contribute.url" && \ cp -r HandBrake.app "HandBrake $(HB_VERSION)" && \ zip -9 -r $(<) "HandBrake $(HB_VERSION)" && \ rm -rf "HandBrake $(HB_VERSION)" } -rule SystemLibraries +rule BeOSPackage { - LINKLIBS on [ FAppendSuffix $(<) : $(SUFEXE) ] += $(>) ; -} - -# Jambase's ObjectHdrs doesn't seem to work when ObjectHdrs is called -# several times on a file, and it doesn't works for asm files. Fixed -# here. -rule ObjectHdrs -{ - local s = [ FGristFiles $(<:S=$(SUFOBJ)) ] ; - HDRS on $(s) += $(>) ; - ASHDRS on $(s) += [ FIncludes $(>) ] ; - CCHDRS on $(s) += [ FIncludes $(>) ] ; + Depends $(<) : $(>) ; + BuildBeOSPackage $(<) ; +} +actions BuildBeOSPackage +{ + rm -rf $(<) "HandBrake $(HB_VERSION)" && \ + mkdir "HandBrake $(HB_VERSION)" && \ + cp AUTHORS "HandBrake $(HB_VERSION)/AUTHORS.txt" && \ + cp COPYING "HandBrake $(HB_VERSION)/COPYING.txt" && \ + cp CREDITS "HandBrake $(HB_VERSION)/CREDITS.txt" && \ + cp THANKS "HandBrake $(HB_VERSION)/THANKS.txt" && \ + xres -o HandBrake beos/HandBrake.rsrc && \ + cp HandBrake "HandBrake $(HB_VERSION)" && \ + zip -9 -r $(<) "HandBrake $(HB_VERSION)" && \ + rm -rf "HandBrake $(HB_VERSION)" } - @@ -1,7 +1,30 @@ -$Id: NEWS,v 1.15 2004/05/25 17:48:52 titer Exp $ +$Id: NEWS,v 1.28 2005/11/04 16:01:19 titer Exp $ NEWS file for HandBrake <http://handbrake.m0k.org/> +Changed between 0.7.0-beta3 and 0.7.0 + + Multithreaded H.264 encoding with x264 + + Added option for H.264 Baseline (suitable for iPods) + + (Very) experimental queue support + + Fixes for some DVD titles HandBrake would not recognize + + Fixes audio gliches when encoding from LPCM tracks + +Changed between 0.6.2 and 0.7.0-beta3 + + Chapters selection + + Custom framerate + + Subtitle support + + Check for updates + + Custom aspect ratio + + Audio samplerate selection + + mp4/H.264 output + + Proper NTSC support + + AC3 pass-through + + Progress bar in the dock icon (OS X) + + 2-pass H.264 encoding + + Constant quality encoding + + Grayscale encoding + + Up-to-date BeOS UI + Changes between 0.6.1 and 0.6.2 + Support for DVDs with MPEG audio tracks + Rewrote the DVD navigation code @@ -1,4 +1,4 @@ -$Id: THANKS,v 1.13 2004/04/22 22:49:07 titer Exp $ +$Id: THANKS,v 1.16 2004/08/05 17:03:05 titer Exp $ THANKS file for HandBrake <http://handbrake.m0k.org/> @@ -31,7 +31,7 @@ Leendert + Dutch translation Eric Kornblum - + Sent me a sample DVD with LPCM tracks so I could add support for it + + Sent me a sample DVD with LPCM tracks migol Superkid + Spanish translation @@ -42,3 +42,14 @@ pgjw cygma + Japanese translation +Michelle De Sio + + Sent me a sample DVD with MPEG audio tracks + +Ian Rickard + + Enhanced icon + +S�bastien No�l + + Debian packages (http://www.twolife.org/debian/repository.php) + +People who sent me an iTunes gift certificate: a BIG thanks! + @@ -1,45 +0,0 @@ -$Id: TODO,v 1.36 2004/05/25 17:48:52 titer Exp $ - -TODO file for HandBrake <http://handbrake.m0k.org/> - -This is a roadmap for future releases of HandBrake. It has to be taken -as an indication, as it may change as any time. - -0.6.x - + Up-to-date BeOS GUI - -0.7.x - + Audio volume normalizing - + AC3 pass-through - + Subtitle support - + Rip only a few chapters or rip X seconds from a given starting point - + Allow to launch rips of several titles - -Maybe in 0.7.x - + B-frames, bla bla - + MKV muxing support - + Manual aspect ratio - + Better remaining time calculation - + Nice 'About...' box with link to homepage & faq - + [OSX] Progress bar in the dock icon - + Custom framerate - -After 0.7.0 - + Preview the latest encoded picture in GUI - + Split output file in x parts - + Picture rotation - + Network shared processing (using RendezVous?) - + VCD/DVD-R output - + Theora encoding - + Raw MPEG/AC3 output - + DVD folder output - + Use the DVD name in popup and for the name of the created file - + Send a mail when rip is done - + Turn the computer off when done - + Collapse interface when rip starts - + MJPEG output, or something - -Misc known bugs: - + [OSX] crash when trying to encode a DVD from mounted toast image - + [OSX] opengl effects somtimes mess up the picture's brightness - diff --git a/beos/HBApp.cpp b/beos/HBApp.cpp index add6259f2..702c74d94 100644 --- a/beos/HBApp.cpp +++ b/beos/HBApp.cpp @@ -1,5 +1,8 @@ #include "HBApp.h" -#include "HBWindow.h" +#include "MainWindow.h" +#include "ScanWindow.h" + +#include "hb.h" int main() { @@ -10,9 +13,18 @@ int main() } HBApp::HBApp() - : MApplication( "application/x-vnd.titer-handbrake" ) + : BApplication( "application/x-vnd.titer-handbrake" ) { - fWindow = new HBWindow(); + fHandle = hb_init( HB_DEBUG_ALL, 0 ); + + fMainWin = new MainWindow( fHandle ); + fScanWin = new ScanWindow( fHandle ); + fScanWin->AddToSubset( fMainWin ); + + fMainWin->Show(); + fScanWin->Show(); + + SetPulseRate( 200000 ); /* 0.2 second */ } void HBApp::MessageReceived( BMessage * message ) @@ -20,7 +32,7 @@ void HBApp::MessageReceived( BMessage * message ) switch( message->what ) { default: - MApplication::MessageReceived( message ); + BApplication::MessageReceived( message ); break; } } @@ -29,3 +41,45 @@ void HBApp::RefsReceived( BMessage * message ) { } +void HBApp::Pulse() +{ + hb_state_t s; + hb_get_state( fHandle, &s ); + + switch( s.state ) + { + case HB_STATE_IDLE: + break; + + case HB_STATE_SCANNING: + fScanWin->Update( &s ); + break; + + case HB_STATE_SCANDONE: + if( hb_list_count( hb_get_titles( fHandle ) ) ) + { + /* Success */ + fScanWin->Hide(); + fMainWin->Update( &s ); + } + else + { + /* Invalid volume */ + fScanWin->Update( &s ); + } + break; + + case HB_STATE_WORKING: + case HB_STATE_PAUSED: + case HB_STATE_WORKDONE: + fMainWin->Update( &s ); + break; + } +} + +bool HBApp::QuitRequested() +{ + hb_close( &fHandle ); + return BApplication::QuitRequested(); +} + diff --git a/beos/HBApp.h b/beos/HBApp.h index 75f3fc173..042a791b9 100644 --- a/beos/HBApp.h +++ b/beos/HBApp.h @@ -1,19 +1,27 @@ -#ifndef HB_HB_APP_H -#define HB_HB_APP_H +#ifndef HB_APP_H +#define HB_APP_H -#include "layout-all.h" +#include <Application.h> -class HBWindow; +#include "hb.h" -class HBApp : public MApplication +class MainWindow; +class ScanWindow; + +class HBApp : public BApplication { public: - HBApp(); - void MessageReceived( BMessage * message ); - void RefsReceived( BMessage * message ); + HBApp(); + void MessageReceived( BMessage * message ); + void RefsReceived( BMessage * message ); + void Pulse(); + bool QuitRequested(); private: - HBWindow * fWindow; + MainWindow * fMainWin; + ScanWindow * fScanWin; + + hb_handle_t * fHandle; }; #endif diff --git a/beos/HBWindow.cpp b/beos/HBWindow.cpp deleted file mode 100644 index 4bb51d61f..000000000 --- a/beos/HBWindow.cpp +++ /dev/null @@ -1,283 +0,0 @@ -#include "HBWindow.h" - -#include <MenuItem.h> -#include <Screen.h> - -#define SCAN_OPEN 'scop' -#define RIP_RIP 'riri' - -static void _Scanning( void * data, int title, int titleCount ) -{ - ((HBWindow*)data)->Scanning( title, titleCount ); -} -static void _ScanDone( void * data, HBList * titleList ) -{ - ((HBWindow*)data)->ScanDone( titleList ); -} -static void _Encoding( void * data, float position, int pass, - int passCount, float frameRate, - float avgFrameRate, int remainingTime ) -{ - ((HBWindow*)data)->Encoding( position, pass, passCount, frameRate, - avgFrameRate, remainingTime ); -} -static void _RipDone( void * data, int result ) -{ - ((HBWindow*)data)->RipDone( result ); -} - -HBWindow::HBWindow() - : MWindow( BRect( 0,0,10,10 ), "HandBrake " HB_VERSION, - B_TITLED_WINDOW, 0 ) -{ - /* Init libhb */ - HBCallbacks callbacks; - callbacks.data = this; - callbacks.scanning = _Scanning; - callbacks.scanDone = _ScanDone; - callbacks.encoding = _Encoding; - callbacks.ripDone = _RipDone; - - fHandle = HBInit( 1, 0 ); - HBSetCallbacks( fHandle, callbacks ); - - fScanView = new HGroup( - new Space( minimax( 10,-1,10,-1 ) ), - new VGroup( - new Space( minimax( -1,10,-1,10 ) ), - new MStringView( "Welcome to HandBrake. Select a DVD to open:" ), - new Space( minimax( -1,5,-1,5 ) ), - new HGroup( - fScanRadio = new MRadioGroup( "Detected volume:", - "DVD Folder:", 0 ), - new VGroup( - fScanDetectedPopup = new MPopup( NULL, - "/Bulk/ANGEL_SEASON2_DISC6", 0 ), - fScanFolderControl = new MTextControl( NULL, NULL ), - 0 ), - 0 ), - fScanBrowseButton = new MButton( "Browse", 12 ), - fScanStatusString = new MStringView( "" ), - fScanProgress = new MProgressBar( this ), - fScanOpenButton = new MButton( "Open", - new BMessage( SCAN_OPEN ) ), - new Space( minimax( -1,10,-1,10000 ) ), - 0 ), - new Space( minimax( 10,-1,10,-1 ) ), - 0 ); - - fScanDetectedPopup->Menu()->ItemAt(0)->SetMarked(true); - fScanProgress->ct_mpm = minimax( 0,12,10000,12 ); - - fRipView = new HGroup( - new Space( minimax( 10,-1,10,-1 ) ), - new VGroup( - new Space( minimax( -1,10,-1,10 ) ), - new MBorder( - M_LABELED_BORDER, 15, "General", - new VGroup( - fRipTitlePopup = new MPopup( "DVD title:", "dummy", 0 ), - new MPopup( "Output format:", - "MP4 file / MPEG-4 video / AAC audio", - "OGM file / MPEG-4 video / Vorbis audio", - "AVI file / MPEG-4 video / MP3 audio", - "AVI file / H264 video / MP3 audio", 0 ), - new MTextControl( "File:", "/boot/home/Desktop/Movie.mp4" ), - new MButton( "Browse" ), - 0 ) - ), - new MBorder( - M_LABELED_BORDER, 15, "Video", - new VGroup( - new MPopup( "MPEG-4 encoder:", "FFmpeg", "XviD", 0 ), - new HGroup( - new MStringView( "Bitrate:" ), - new MRadioGroup( "Custom (kbps)", "Target size (MB)", 0 ), - new VGroup( - new MTextControl( NULL, NULL ), - new MTextControl( NULL, NULL ), - 0 ), - 0 ), - new MSplitter(), - new HGroup( - new MCheckBox( "2-pass encoding" ), - new MButton( "Crop & Scale..." ), - 0 ), - 0 ) - ), - new MBorder( - M_LABELED_BORDER, 15, "Audio", - new VGroup( - fRipLanguage1Popup = new MPopup( "Language 1:", - "dummy", 0 ), - fRipLanguage2Popup = new MPopup( "Language 2 (optional):", - "dummy", 0 ), - fRipBitratePopup = new MPopup( "Bitrate (kbps):", "32", - "64", "96", "128", "160", "192", "224", "256", "288", - "320", 0 ), - 0 ) - ), - new MProgressBar( this ), - new HGroup( - new MButton( "Pause" ), - new MButton( "Rip!", new BMessage( RIP_RIP ) ), - 0 ), - new Space( minimax( -1,10,-1,10 ) ), - 0 ), - new Space( minimax( 10,-1,10,-1 ) ), - 0 ); - - fRipBitratePopup->Menu()->ItemAt(3)->SetMarked( true ); - - fLayers = new LayeredGroup( fScanView, fRipView, 0 ); - AddChild( dynamic_cast<BView*>(fLayers) ); - - /* Center the window */ - BScreen screen; - MoveTo( ( screen.Frame().Width() ) / 2, - ( screen.Frame().Height() ) / 2 ); - - Show(); -} - -bool HBWindow::QuitRequested() -{ - HBClose( &fHandle ); - be_app->PostMessage( B_QUIT_REQUESTED ); - return true; -} - -void HBWindow::MessageReceived( BMessage * message ) -{ - switch( message->what ) - { - case SCAN_OPEN: - Lock(); - /* That's ugly, but there doesn't seem to be another way */ - ((BRadioButton*)fScanRadio->ChildAt(0))->SetEnabled( false ); - ((BRadioButton*)fScanRadio->ChildAt(1))->SetEnabled( false ); - fScanDetectedPopup->SetEnabled( false ); - fScanFolderControl->SetEnabled( false ); - fScanBrowseButton->SetEnabled( false ); - fScanOpenButton->SetEnabled( false ); - fScanStatusString->SetText( "Opening device..." ); - Unlock(); - HBScanDVD( fHandle, - fScanDetectedPopup->Menu()->FindMarked()->Label(), 0 ); - break; - - case RIP_RIP: - { - HBTitle * title = (HBTitle*) HBListItemAt( fTitleList, - fRipTitlePopup->Menu()->IndexOf( - fRipTitlePopup->Menu()->FindMarked() ) ); - title->file = strdup( "/boot/home/Desktop/Movie.mp4" ); - title->twoPass = 0; - title->deinterlace = 0; - title->topCrop = title->autoTopCrop; - title->bottomCrop = title->autoBottomCrop; - title->leftCrop = title->autoLeftCrop; - title->rightCrop = title->autoRightCrop; - title->bitrate = 1024; - title->codec = HB_CODEC_FFMPEG; - title->mux = HB_MUX_MP4; - HBAudio * audio = (HBAudio*) HBListItemAt( - title->audioList, 0 ); - audio->codec = HB_CODEC_AAC; - audio->outBitrate = 128; - HBListAdd( title->ripAudioList, audio ); - HBStartRip( fHandle, title ); - break; - } - - default: - MWindow::MessageReceived( message ); - break; - } -} - -void HBWindow::Scanning( int title, int titleCount ) -{ - Lock(); - char string[1024]; memset( string, 0, 1024 ); - snprintf( string, 1023, "Scanning title %d of %d...", - title, titleCount ); - fScanStatusString->SetText( string ); - fScanProgress->SetValue( (float) title / titleCount ); - Unlock(); -} - -void HBWindow::ScanDone( HBList * titleList ) -{ -#define menu fRipTitlePopup->Menu() - Lock(); - BMenuItem * item; - while( ( item = menu->ItemAt(0) ) ) - { - menu->RemoveItem( item ); - delete item; - } - HBTitle * title; - char label[1024]; - for( int i = 0; i < HBListCount( titleList ); i++ ) - { - memset( label, 0, 1024 ); - title = (HBTitle*) HBListItemAt( titleList, i ); - snprintf( label, 1023, "%d - %02dh%02dm%02ds", title->index, - title->length / 3600, ( title->length % 3600 ) / 60, - title->length % 60 ); - menu->AddItem( new BMenuItem( label, NULL ) ); - } - menu->ItemAt(0)->SetMarked( true ); - fTitleList = titleList; - UpdateLanguages(); - fLayers->ActivateLayer( 1 ); - Unlock(); -#undef menu -} - -void HBWindow::Encoding( float position, int pass, int passCount, - float frameRate, float avgFrameRate, - int remainingTime ) -{ -} - -void HBWindow::RipDone( int result ) -{ -} - -void HBWindow::UpdateLanguages() -{ -#define menu fRipTitlePopup->Menu() - HBTitle * title = (HBTitle*) HBListItemAt( fTitleList, - menu->IndexOf( menu->FindMarked() ) ); -#undef menu - -#define menu1 fRipLanguage1Popup->Menu() -#define menu2 fRipLanguage2Popup->Menu() - BMenuItem * item; - while( ( item = menu1->ItemAt(0) ) ) - { - menu1->RemoveItem( item ); - delete item; - } - while( ( item = menu2->ItemAt(0) ) ) - { - menu2->RemoveItem( item ); - delete item; - } - - HBAudio * audio; - for( int i = 0; i < HBListCount( title->audioList ); i++ ) - { - audio = (HBAudio*) HBListItemAt( title->audioList, i ); - menu1->AddItem( new BMenuItem( audio->language, NULL ) ); - menu2->AddItem( new BMenuItem( audio->language, NULL ) ); - } - menu1->ItemAt(0)->SetMarked( true ); - menu2->AddItem( new BMenuItem( "None", NULL ) ); - menu2->ItemAt( menu2->CountItems() - 1 )->SetMarked( true ); -#undef menu1 -#undef menu2 -} - diff --git a/beos/HBWindow.h b/beos/HBWindow.h deleted file mode 100644 index 52ddfbf1b..000000000 --- a/beos/HBWindow.h +++ /dev/null @@ -1,41 +0,0 @@ -#include "layout-all.h" -#include "HandBrake.h" - -class HBWindow : public MWindow -{ - public: - HBWindow(); - bool QuitRequested(); - void MessageReceived( BMessage * message ); - - void Scanning( int title, int titleCount ); - void ScanDone( HBList * titleList ); - void Encoding( float position, int pass, int passCount, - float frameRate, float avgFrameRate, - int remainingTime ); - void RipDone( int result ); - - private: - void UpdateLanguages(); - - HBHandle * fHandle; - HBList * fTitleList; - - LayeredGroup * fLayers; - - MView * fScanView; - MRadioGroup * fScanRadio; - MPopup * fScanDetectedPopup; - MTextControl * fScanFolderControl; - MButton * fScanBrowseButton; - MStringView * fScanStatusString; - MProgressBar * fScanProgress; - MButton * fScanOpenButton; - - MView * fRipView; - MPopup * fRipTitlePopup; - MPopup * fRipLanguage1Popup; - MPopup * fRipLanguage2Popup; - MPopup * fRipBitratePopup; -}; - diff --git a/beos/MainWindow.cpp b/beos/MainWindow.cpp new file mode 100644 index 000000000..5b2741bb9 --- /dev/null +++ b/beos/MainWindow.cpp @@ -0,0 +1,986 @@ +#include <app/Application.h> +#include <interface/Box.h> +#include <interface/Button.h> +#include <interface/CheckBox.h> +#include <interface/MenuField.h> +#include <interface/MenuItem.h> +#include <interface/PopUpMenu.h> +#include <interface/RadioButton.h> +#include <interface/Screen.h> +#include <interface/Slider.h> +#include <interface/StatusBar.h> +#include <interface/StringView.h> +#include <interface/TextControl.h> +#include <storage/FilePanel.h> +#include <storage/Path.h> +#include <support/String.h> + +#include "MainWindow.h" +#include "PicWindow.h" +#include "QueueWindow.h" + +#define MSG_TITLEPOPUP 'titl' +#define MSG_CHAPTERPOPUP 'chap' +#define MSG_FORMATPOPUP 'form' +#define MSG_CODECSPOPUP 'code' +#define MSG_BROWSE 'brow' +#define MSG_QUALITYRADIO 'radi' +#define MSG_SLIDER 'slid' +#define MSG_PICSETTINGS 'pise' +#define MSG_QUEUE_ENABLE 'quen' +#define MSG_QUEUE_ADD 'quad' +#define MSG_QUEUE_SHOW 'qush' +#define MSG_PAUSE 'paus' +#define MSG_START 'star' + +static int FormatSettings[3][4] = + { { HB_MUX_MP4 | HB_VCODEC_FFMPEG | HB_ACODEC_FAAC, + HB_MUX_MP4 | HB_VCODEC_X264 | HB_ACODEC_FAAC, + 0, + 0 }, + { HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_LAME, + HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_AC3, + HB_MUX_AVI | HB_VCODEC_X264 | HB_ACODEC_LAME, + HB_MUX_AVI | HB_VCODEC_X264 | HB_ACODEC_AC3 }, + { HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_VORBIS, + HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_LAME, + 0, + 0 } }; + +MainView::MainView( hb_handle_t * handle ) + : BView( BRect( 0,0,700,475 ), NULL, B_FOLLOW_NONE, B_WILL_DRAW ) +{ + fHandle = handle; + + BRect r, b; + BBox * box; + + SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) ); + + /* Source box */ + b = Bounds(); + r = BRect( 10,10,b.right/2-5,135 ); + box = new BBox( r ); + box->SetLabel( "Source" ); + AddChild( box ); + + b = box->Bounds(); + + r = BRect( 10,15,b.right/4,35 ); + fSrcDVD1String = new BStringView( r, NULL, "DVD:" ); + box->AddChild( fSrcDVD1String ); + + r = BRect( b.right/4+1,15,b.right-10,35 ); + fSrcDVD2String = new BStringView( r, NULL, "" ); + fSrcDVD2String->SetAlignment( B_ALIGN_RIGHT ); + box->AddChild( fSrcDVD2String ); + + r = BRect( 10,40,b.right-10,60 ); + fSrcTitlePopUp = new BPopUpMenu( "" ); + fSrcTitleMenu = new BMenuField( r, NULL, "Title:", fSrcTitlePopUp, + true ); + fSrcTitleMenu->SetDivider( b.right-130 ); + box->AddChild( fSrcTitleMenu ); + + r = BRect( 10,65,b.right-120,85 ); + fSrcChapString = new BStringView( r, NULL, "Chapters:" ); + box->AddChild( fSrcChapString ); + + r = BRect( b.right-119,65,b.right-80,85 ); + fSrcChapStartPopUp = new BPopUpMenu( "" ); + fSrcChapStartMenu = new BMenuField( r, NULL, "", + fSrcChapStartPopUp, true ); + fSrcChapStartMenu->SetDivider( 0.0 ); + box->AddChild( fSrcChapStartMenu ); + + r = BRect( b.right-79,65,b.right-50,85 ); + fSrcChapToString = new BStringView( r, NULL, "to" ); + fSrcChapToString->SetAlignment( B_ALIGN_CENTER ); + box->AddChild( fSrcChapToString ); + + r = BRect( b.right-49,65,b.right-10,85 ); + fSrcChapEndPopUp = new BPopUpMenu( "" ); + fSrcChapEndMenu = new BMenuField( r, NULL, "", fSrcChapEndPopUp, + true ); + fSrcChapEndMenu->SetDivider( 0.0 ); + box->AddChild( fSrcChapEndMenu ); + + r = BRect( 10,90,b.right/2,110 ); + fSrcDur1String = new BStringView( r, NULL, "Duration:" ); + box->AddChild( fSrcDur1String ); + + r = BRect( b.right/2+1,90,b.right-10,110 ); + fSrcDur2String = new BStringView( r, NULL, "00:00:00" ); + fSrcDur2String->SetAlignment( B_ALIGN_RIGHT ); + box->AddChild( fSrcDur2String ); + + /* Destination box */ + b = Bounds(); + r = BRect( b.right/2+5,10,b.right-10,135 ); + box = new BBox( r ); + box->SetLabel( "Destination" ); + AddChild( box ); + + b = box->Bounds(); + + r = BRect( 10,15,b.right-10,35 ); + fDstFormatPopUp = new BPopUpMenu( "" ); +#define ADDITEM(a) fDstFormatPopUp->AddItem( new BMenuItem( a, \ + new BMessage( MSG_FORMATPOPUP ) ) ) + ADDITEM( "MP4 file" ); + ADDITEM( "AVI file" ); + ADDITEM( "OGM file" ); +#undef ADDITEM + fDstFormatPopUp->ItemAt( 0 )->SetMarked( true ); + fDstFormat = -1; + fDstFormatMenu = new BMenuField( r, NULL, "File format:", + fDstFormatPopUp, true ); + fDstFormatMenu->SetDivider( b.right/3 ); + box->AddChild( fDstFormatMenu ); + + r = BRect( 10,40,b.right-10,60 ); + fDstCodecsPopUp = new BPopUpMenu( "" ); + fDstCodecsMenu = new BMenuField( r, NULL, "Codecs:", + fDstCodecsPopUp, true ); + fDstCodecsMenu->SetDivider( b.right/3 ); + box->AddChild( fDstCodecsMenu ); + + r = BRect( 10,65,b.right-10,85 ); + fDstFileControl = new BTextControl( r, NULL, "File:", + "/boot/home/Desktop/Movie", new BMessage() ); + fDstFileControl->SetDivider( b.right/3 ); + box->AddChild( fDstFileControl ); + + r = BRect( b.right-90,90,b.right-10,115 ); + fBrowseButton = new BButton( r, NULL, "Browse", + new BMessage( MSG_BROWSE ) ); + box->AddChild( fBrowseButton ); + + /* Video box */ + b = Bounds(); + r = BRect( 10,145,b.right/2-5,395 ); + box = new BBox( r ); + box->SetLabel( "Video" ); + AddChild( box ); + + b = box->Bounds(); + + r = BRect( 10,15,b.right-10,35 ); + fVidRatePopUp = new BPopUpMenu( "" ); + fVidRatePopUp->AddItem( new BMenuItem( "Same as source", + new BMessage() ) ); + for( int i = 0; i < hb_video_rates_count; i++ ) + { + fVidRatePopUp->AddItem( new BMenuItem( hb_video_rates[i].string, + new BMessage() ) ); + } + fVidRatePopUp->ItemAt( 0 )->SetMarked( true ); + fVidRateMenu = new BMenuField( r, NULL, "Framerate (fps):", + fVidRatePopUp, true ); + box->AddChild( fVidRateMenu ); + + r = BRect( 10,40,b.right-10,60 ); + fVidEncoderPopUp = new BPopUpMenu( "" ); + fVidEncoderMenu = new BMenuField( r, NULL, "Encoder:", + fVidEncoderPopUp, true ); + box->AddChild( fVidEncoderMenu ); + + r = BRect( 10,65,b.right-10,85 ); + fVidQualityString = new BStringView( r, NULL, "Quality:" ); + box->AddChild( fVidQualityString ); + + r = BRect( 10,90,b.right*2/3,110); + fVidTargetRadio = new BRadioButton( r, NULL, "Target size (MB):", + new BMessage( MSG_QUALITYRADIO ) ); + box->AddChild( fVidTargetRadio ); + + r = BRect( b.right*2/3+1,90,b.right-10,110); + fVidTargetControl = new BTextControl( r, NULL, "", "700", + new BMessage() ); + fVidTargetControl->SetDivider( 0 ); + box->AddChild( fVidTargetControl ); + + r = BRect( 10,115,b.right/2,135); + fVidAverageRadio = new BRadioButton( r, NULL, "Average bitrate (kbps):", + new BMessage( MSG_QUALITYRADIO ) ); + fVidAverageRadio->SetValue( 1 ); + box->AddChild( fVidAverageRadio ); + + r = BRect( b.right*2/3+1,115,b.right-10,135); + fVidAverageControl = new BTextControl( r, NULL, "", "1000", + new BMessage() ); + fVidAverageControl->SetDivider( 0 ); + box->AddChild( fVidAverageControl ); + + r = BRect( 10,140,b.right/2,160); + fVidConstantRadio = new BRadioButton( r, NULL, "Constant quality:", + new BMessage( MSG_QUALITYRADIO ) ); + box->AddChild( fVidConstantRadio ); + + r = BRect( 20,165,b.right-10,195); + fVidConstantSlider = new BSlider( r, NULL, NULL, + new BMessage( MSG_SLIDER ), 0, 100 ); + fVidConstantSlider->SetValue( 50 ); + SliderChanged(); + box->AddChild( fVidConstantSlider ); + + r = BRect( 10,200,b.right-10,220); + fVidGrayCheck = new BCheckBox( r, NULL, "Grayscale encoding", new BMessage() ); + box->AddChild( fVidGrayCheck ); + r = BRect( 10,220,b.right-10,240); + fVidTwoPassCheck = new BCheckBox( r, NULL, "2-pass encoding", new BMessage() ); + box->AddChild( fVidTwoPassCheck ); + + /* Subtitles box */ + b = Bounds(); + r = BRect( b.right/2+5,145,b.right-10,190 ); + box = new BBox( r ); + box->SetLabel( "Subtitles" ); + AddChild( box ); + + b = box->Bounds(); + + r = BRect( 10,15,b.right-10,35 ); + fSubPopUp = new BPopUpMenu( "" ); + fSubMenu = new BMenuField( r, NULL, "Language:", + fSubPopUp, true ); + box->AddChild( fSubMenu ); + + /* Audio box */ + b = Bounds(); + r = BRect( b.right/2+5,200,b.right-10,320 ); + box = new BBox( r ); + box->SetLabel( "Audio" ); + AddChild( box ); + + b = box->Bounds(); + + r = BRect( 10,15,b.right-10,35 ); + fAudLang1PopUp = new BPopUpMenu( "" ); + fAudLang1Menu = new BMenuField( r, NULL, "Language 1:", + fAudLang1PopUp, true ); + box->AddChild( fAudLang1Menu ); + r = BRect( 10,40,b.right-10,60 ); + fAudLang2PopUp = new BPopUpMenu( "" ); + fAudLang2Menu = new BMenuField( r, NULL, "Language 2:", + fAudLang2PopUp, true ); + box->AddChild( fAudLang2Menu ); + r = BRect( 10,65,b.right-10,85 ); + fAudRatePopUp = new BPopUpMenu( "" ); + for( int i = 0; i < hb_audio_rates_count; i++ ) + { + fAudRatePopUp->AddItem( new BMenuItem( hb_audio_rates[i].string, + new BMessage ) ); + } + fAudRatePopUp->ItemAt( hb_audio_rates_default )->SetMarked( true ); + fAudRateMenu = new BMenuField( r, NULL, "Sample rate (Hz):", + fAudRatePopUp, true ); + box->AddChild( fAudRateMenu ); + r = BRect( 10,90,b.right-10,110 ); + fAudBitratePopUp = new BPopUpMenu( "" ); + for( int i = 0; i < hb_audio_bitrates_count; i++ ) + { + fAudBitratePopUp->AddItem( new BMenuItem( + hb_audio_bitrates[i].string, new BMessage ) ); + } + fAudBitratePopUp->ItemAt( + hb_audio_bitrates_default )->SetMarked( true ); + fAudBitrateMenu = new BMenuField( r, NULL, "Bitrate (kbps):", + fAudBitratePopUp, true ); + box->AddChild( fAudBitrateMenu ); + + /* Picture settings */ + b = Bounds(); + r = BRect( b.right-110,370,b.right-10,395 ); + fPictureButton = new BButton( r, NULL, "Picture settings...", + new BMessage( MSG_PICSETTINGS ) ); + AddChild( fPictureButton ); + + /* Bottom */ + r = BRect( 10,405,b.right-10,435 ); + fProgressBar = new BStatusBar( r, NULL ); + AddChild( fProgressBar ); + + r = BRect( 10,450,b.right-370,470); + fQueueCheck = new BCheckBox( r, NULL, "Enable Queue", + new BMessage( MSG_QUEUE_ENABLE ) ); + AddChild( fQueueCheck ); + + r = BRect( b.right-360,445,b.right-280,470 ); + fAddButton = new BButton( r, NULL, "Add to Queue", + new BMessage( MSG_QUEUE_ADD ) ); + + r = BRect( b.right-270,445,b.right-190,470 ); + fShowButton = new BButton( r, NULL, "Show queue", + new BMessage( MSG_QUEUE_SHOW ) ); + + r = BRect( b.right-180,445,b.right-100,470 ); + fPauseButton = new BButton( r, NULL, "Pause", + new BMessage( MSG_PAUSE ) ); + AddChild( fPauseButton ); + + r = BRect( b.right-90,445,b.right-10,470 ); + fRipButton = new BButton( r, NULL, "Rip", + new BMessage( MSG_START ) ); + AddChild( fRipButton ); + + EnableUI( false ); + fPauseButton->SetEnabled( false ); + fRipButton->SetEnabled( false ); + + FormatPopUpChanged(); + + fFilePanel = NULL; +} + +void MainView::HandleMessage( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_TITLEPOPUP: + TitlePopUpChanged(); + break; + + case MSG_CHAPTERPOPUP: + ChapterPopUpChanged(); + break; + + case MSG_FORMATPOPUP: + FormatPopUpChanged(); + break; + + case MSG_CODECSPOPUP: + CodecsPopUpChanged(); + break; + + case MSG_BROWSE: + if( !fFilePanel ) + { + fFilePanel = new BFilePanel( B_SAVE_PANEL, + new BMessenger( Window() ), NULL, 0, false ); + } + fFilePanel->Show(); + break; + + case B_SAVE_REQUESTED: + { + entry_ref ref; + BString string; + if( msg->FindRef( "directory", 0, &ref ) == B_OK && + msg->FindString( "name", &string ) == B_OK ) + { + BPath * path = new BPath( &ref ); + string.Prepend( "/" ); + string.Prepend( path->Path() ); + fDstFileControl->SetText( string.String() ); + CheckExtension(); + } + break; + } + + case MSG_QUALITYRADIO: + QualityRadioChanged(); + break; + + case MSG_SLIDER: + SliderChanged(); + break; + + case MSG_PICSETTINGS: + fPicWin = new PicWindow( fHandle, fSrcTitlePopUp->IndexOf( + fSrcTitlePopUp->FindMarked() ) ); + fPicWin->Show(); + break; + + case MSG_QUEUE_ENABLE: + if( fQueueCheck->Value() ) + { + AddChild( fAddButton ); + AddChild( fShowButton ); + } + else + { + RemoveChild( fAddButton ); + RemoveChild( fShowButton ); + } + break; + + case MSG_QUEUE_ADD: + AddJob(); + break; + + case MSG_QUEUE_SHOW: + fQueueWin = new QueueWindow( fHandle ); + fQueueWin->Show(); + break; + + case MSG_PAUSE: + fPauseButton->SetEnabled( false ); + fRipButton->SetEnabled( false ); + if( !strcmp( fPauseButton->Label(), "Resume" ) ) + { + hb_resume( fHandle ); + } + else + { + hb_pause( fHandle ); + } + break; + + case MSG_START: + { + if( !strcmp( fRipButton->Label(), "Cancel" ) ) + { + fPauseButton->SetEnabled( false ); + fRipButton->SetEnabled( false ); + hb_stop( fHandle ); + break; + } + + EnableUI( false ); + fPauseButton->SetEnabled( false ); + fRipButton->SetEnabled( false ); + + if( !fQueueCheck->Value() ) + { + AddJob(); + } + + hb_start( fHandle ); + break; + } + } +} + +void MainView::Update( hb_state_t * s ) +{ + if( !LockLooper() ) + { + fprintf( stderr, "LockLooper failed\n" ); + return; + } + + switch( s->state ) + { +#define p s->param.scandone + case HB_STATE_SCANDONE: + { + hb_list_t * list; + hb_title_t * title; + char string[1024]; + + list = hb_get_titles( fHandle ); + for( int i = 0; i < hb_list_count( list ); i++ ) + { + title = (hb_title_t *) hb_list_item( list, i ); + fSrcDVD2String->SetText( title->dvd ); + snprintf( string, 1024, "%d - %02dh%02dm%02ds", + title->index, title->hours, title->minutes, + title->seconds ); + fSrcTitlePopUp->AddItem( new BMenuItem( string, + new BMessage( MSG_TITLEPOPUP ) ) ); + } + fSrcTitlePopUp->ItemAt( 0 )->SetMarked( true ); + fSrcTitle = -1; + TitlePopUpChanged(); + + EnableUI( true ); + fRipButton->SetEnabled( true ); + fPauseButton->SetEnabled( false ); + break; + } +#undef p + +#define p s->param.working + case HB_STATE_WORKING: + { + float progress_total; + char text[1024]; + progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count; + snprintf( text, 1024, "Encoding: task %d of %d, %.2f %%", + p.job_cur, p.job_count, 100.0 * p.progress ); + if( p.seconds > -1 ) + { + snprintf( text + strlen( text ), 1024 - strlen( text ), + " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", + p.rate_cur, p.rate_avg, p.hours, p.minutes, + p.seconds ); + } + fProgressBar->Update( fProgressBar->MaxValue() * + progress_total - fProgressBar->CurrentValue(), text ); + + fPauseButton->SetLabel( "Pause" ); + fPauseButton->SetEnabled( true ); + fRipButton->SetLabel( "Cancel" ); + fRipButton->SetEnabled( true ); + break; + } +#undef p + + case HB_STATE_PAUSED: + fProgressBar->Update( 0, "Paused" ); + fPauseButton->SetLabel( "Resume" ); + fPauseButton->SetEnabled( true ); + fRipButton->SetLabel( "Cancel" ); + fRipButton->SetEnabled( true ); + break; + +#define p s->param.workdone + case HB_STATE_WORKDONE: + fProgressBar->Update( - fProgressBar->CurrentValue(), + "Done." ); + EnableUI( true ); + fPauseButton->SetLabel( "Pause" ); + fPauseButton->SetEnabled( false ); + fRipButton->SetLabel( "Rip" ); + fRipButton->SetEnabled( true ); + + /* FIXME */ + hb_job_t * job; + while( ( job = hb_job( fHandle, 0 ) ) ) + { + hb_rem( fHandle, job ); + } + break; +#undef p + } + + UnlockLooper(); +} + +void MainView::EnableUI( bool b ) +{ + + rgb_color mycolor; + mycolor.red = mycolor.green = mycolor.blue = b ? 0 : 128; + mycolor.alpha = 255; + + BStringView * strings[] = + { fSrcDVD1String, fSrcDVD2String, fSrcChapString, + fSrcChapToString, fSrcDur1String, fSrcDur2String, + fVidQualityString }; + for( unsigned i = 0; i < sizeof( strings ) / sizeof( void * ); i++ ) + { + strings[i]->SetHighColor( mycolor ); + strings[i]->Invalidate(); /* Force redraw */ + } + + BMenuField * fields[] = + { fSrcTitleMenu, fSrcChapStartMenu, fSrcChapEndMenu, + fDstFormatMenu, fDstCodecsMenu, fVidRateMenu, fVidEncoderMenu, + fSubMenu, fAudLang1Menu, fAudLang2Menu, fAudRateMenu, + fAudBitrateMenu }; + for( unsigned i = 0; i < sizeof( fields ) / sizeof( void * ); i++ ) + { + fields[i]->SetEnabled( b ); + } + + BControl * controls[] = + { fDstFileControl, fBrowseButton, fVidTargetRadio, + fVidTargetControl, fVidAverageRadio, fVidAverageControl, + fVidConstantRadio, fVidConstantSlider, fVidGrayCheck, + fVidTwoPassCheck, fPictureButton }; + for( unsigned i = 0; i < sizeof( controls ) / sizeof( void * ); i++ ) + { + controls[i]->SetEnabled( b ); + } + + if( b ) + { + QualityRadioChanged(); + } +} + +void MainView::TitlePopUpChanged() +{ + int index = fSrcTitlePopUp->IndexOf( fSrcTitlePopUp->FindMarked() ); + if( index == fSrcTitle ) + { + /* No change actually */ + return; + } + fSrcTitle = index; + + /* Get a pointer to the title */ + hb_list_t * list; + hb_title_t * title; + list = hb_get_titles( fHandle ); + title = (hb_title_t *) hb_list_item( list, index ); + + char text[1024]; + BMenuItem * item; + + /* Update chapters popups */ + while( ( item = fSrcChapStartPopUp->RemoveItem( 0L ) ) ) + { + delete item; + } + while( ( item = fSrcChapEndPopUp->RemoveItem( 0L ) ) ) + { + delete item; + } + for( int i = 0; i < hb_list_count( title->list_chapter ); i++ ) + { + snprintf( text, 1024, "%d", i + 1 ); + fSrcChapStartPopUp->AddItem( new BMenuItem( text, + new BMessage( MSG_CHAPTERPOPUP ) ) ); + fSrcChapEndPopUp->AddItem( new BMenuItem( text, + new BMessage( MSG_CHAPTERPOPUP ) ) ); + } + fSrcChapStartPopUp->ItemAt( 0 )->SetMarked( true ); + fSrcChapEndPopUp->ItemAt( hb_list_count( title->list_chapter ) + - 1 )->SetMarked( true ); + ChapterPopUpChanged(); + + /* Update subtitles popup */ + hb_subtitle_t * sub; + while( ( item = fSubPopUp->RemoveItem( 0L ) ) ) + { + delete item; + } + fSubPopUp->AddItem( new BMenuItem( "None", new BMessage() ) ); + for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + { + sub = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i ); + fSubPopUp->AddItem( new BMenuItem( sub->lang, new BMessage() ) ); + } + fSubPopUp->ItemAt( 0 )->SetMarked( true ); + + /* Update audio popups */ + hb_audio_t * audio; + while( ( item = fAudLang1PopUp->RemoveItem( 0L ) ) ) + { + delete item; + } + while( ( item = fAudLang2PopUp->RemoveItem( 0L ) ) ) + { + delete item; + } + fAudLang1PopUp->AddItem( new BMenuItem( "None", new BMessage() ) ); + fAudLang2PopUp->AddItem( new BMenuItem( "None", new BMessage() ) ); + for( int i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = (hb_audio_t *) hb_list_item( title->list_audio, i ); + fAudLang1PopUp->AddItem( new BMenuItem( audio->lang, new BMessage() ) ); + fAudLang2PopUp->AddItem( new BMenuItem( audio->lang, new BMessage() ) ); + } + fAudLang1PopUp->ItemAt( 1 )->SetMarked( true ); + fAudLang2PopUp->ItemAt( 0 )->SetMarked( true ); +} + +void MainView::ChapterPopUpChanged() +{ + /* Get a pointer to the title */ + hb_list_t * list; + hb_title_t * title; + list = hb_get_titles( fHandle ); + title = (hb_title_t *) hb_list_item( list, + fSrcTitlePopUp->IndexOf( fSrcTitlePopUp->FindMarked() ) ); + + hb_chapter_t * chapter; + int64_t duration = 0; + for( int i = fSrcChapStartPopUp->IndexOf( + fSrcChapStartPopUp->FindMarked() ); + i <= fSrcChapEndPopUp->IndexOf( + fSrcChapEndPopUp->FindMarked() ); + i++ ) + { + chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i ); + duration += chapter->duration; + } + duration /= 90000; /* pts -> seconds */ + + char text[1024]; + snprintf( text, sizeof(text), "%02lld:%02lld:%02lld", + duration / 3600, ( duration / 60 ) % 60, duration % 60 ); + fSrcDur2String->SetText( text ); +} + +void MainView::FormatPopUpChanged() +{ + int format; + BMenuItem * item; + + format = fDstFormatPopUp->IndexOf( fDstFormatPopUp->FindMarked() ); + if( format == fDstFormat ) + { + /* No change actually */ + CheckExtension(); + return; + } + fDstFormat = format; + + /* Empty codecs popup */ + while( ( item = fDstCodecsPopUp->RemoveItem( 0L ) ) ) + { + delete item; + } + + /* Add acceptable video codec / audio codec combinations */ +#define ADDITEM(a) \ + fDstCodecsPopUp->AddItem( new BMenuItem( a, new BMessage( MSG_CODECSPOPUP ) ) ) + switch( format ) + { + case 0: + ADDITEM( "MPEG-4 Video / AAC Audio" ); + ADDITEM( "AVC/H.264 Video / AAC Audio" ); + break; + case 1: + ADDITEM( "MPEG-4 Video / MP3 Audio" ); + ADDITEM( "MPEG-4 Video / AC-3 Audio" ); + ADDITEM( "AVC/H.264 Video / MP3 Audio" ); + ADDITEM( "AVC/H.264 Video / AC-3 Audio" ); + break; + case 2: + ADDITEM( "MPEG-4 Video / Vorbis Audio" ); + ADDITEM( "MPEG-4 Video / MP3 Audio" ); + break; + } +#undef ADDITEM + + fDstCodecsPopUp->ItemAt( 0 )->SetMarked( true ); + + CheckExtension(); + CodecsPopUpChanged(); +} + +void MainView::CodecsPopUpChanged() +{ + int format = fDstFormatPopUp->IndexOf( fDstFormatPopUp->FindMarked() ); + int codecs = fDstCodecsPopUp->IndexOf( fDstCodecsPopUp->FindMarked() ); + + BMenuItem * item; + + /* Update the encoder popup if necessary */ + if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) && + fVidEncoderPopUp->CountItems() > 1 ) + { + /* MPEG-4 -> H.264 */ + while( ( item = fVidEncoderPopUp->RemoveItem( 0L ) ) ) + delete item; + fVidEncoderPopUp->AddItem( new BMenuItem( "x264", new BMessage() ) ); + fVidEncoderPopUp->ItemAt( 0 )->SetMarked( true ); + } + else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) && + fVidEncoderPopUp->CountItems() < 2 ) + { + /* H.264 -> MPEG-4 */ + while( ( item = fVidEncoderPopUp->RemoveItem( 0L ) ) ) + delete item; + fVidEncoderPopUp->AddItem( new BMenuItem( "FFmpeg", new BMessage() ) ); + fVidEncoderPopUp->AddItem( new BMenuItem( "XviD", new BMessage() ) ); + fVidEncoderPopUp->ItemAt( 0 )->SetMarked( true ); + } + + if( FormatSettings[format][codecs] & HB_ACODEC_AC3 ) + { + /* AC-3 pass-through: disable samplerate and bitrate */ + fAudRatePopUp->SetEnabled( false ); + fAudBitratePopUp->SetEnabled( false ); + } + else if( fVidEncoderPopUp->IsEnabled() ) + { + fAudRatePopUp->SetEnabled( true ); + fAudBitratePopUp->SetEnabled( true ); + } +} + +void MainView::CheckExtension() +{ + char * ext = NULL; + switch( fDstFormat ) + { + case 0: + ext = ".mp4"; + break; + case 1: + ext = ".avi"; + break; + case 2: + ext = ".ogm"; + break; + } + + char newname[1024]; + const char * oldname = fDstFileControl->Text(); + memcpy( newname, oldname, strlen( oldname ) ); + if( strlen( oldname ) > 4 && + oldname[strlen( oldname ) - 4] == '.' ) + { + /* Replace extension */ + memcpy( &newname[strlen( oldname ) - 4], ext, 5 ); + } + else + { + /* Add extension */ + memcpy( &newname[strlen( oldname )], ext, 5 ); + } + fDstFileControl->SetText( newname ); +} + +void MainView::QualityRadioChanged() +{ + fVidTargetControl->SetEnabled( fVidTargetRadio->Value() ); + fVidAverageControl->SetEnabled( fVidAverageRadio->Value() ); + fVidConstantSlider->SetEnabled( fVidConstantRadio->Value() ); + fVidTwoPassCheck->SetEnabled( !fVidConstantRadio->Value() ); + if( fVidConstantRadio->Value() ) + fVidTwoPassCheck->SetValue( 0 ); +} + +void MainView::SliderChanged() +{ + char text[1024]; + snprintf( text, 1024, "Constant quality: %ld %%", + fVidConstantSlider->Value() ); + fVidConstantRadio->SetLabel( text ); +} + +void MainView::AddJob() +{ + hb_list_t * list; + hb_title_t * title; + hb_job_t * job; + list = hb_get_titles( fHandle ); + title = (hb_title_t *) hb_list_item( list, + fSrcTitlePopUp->IndexOf( fSrcTitlePopUp->FindMarked() ) ); + job = title->job; + + job->chapter_start = fSrcChapStartPopUp->IndexOf( + fSrcChapStartPopUp->FindMarked() ) + 1; + job->chapter_end = fSrcChapEndPopUp->IndexOf( + fSrcChapEndPopUp->FindMarked() ) + 1; + + int format = fDstFormatPopUp->IndexOf( + fDstFormatPopUp->FindMarked() ); + int codecs = fDstCodecsPopUp->IndexOf( + fDstCodecsPopUp->FindMarked() ); + + job->mux = FormatSettings[format][codecs] & HB_MUX_MASK; + job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK; + job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK; + + if( ( job->vcodec & HB_VCODEC_FFMPEG ) && + fVidEncoderPopUp->IndexOf( + fVidEncoderPopUp->FindMarked() ) > 0 ) + { + job->vcodec = HB_VCODEC_XVID; + } + + int index; + index = fVidRatePopUp->IndexOf( + fVidRatePopUp->FindMarked() ); + if( index > 0 ) + { + job->vrate_base = hb_video_rates[index-1].rate; + } + else + { + job->vrate_base = title->rate_base; + } + + job->grayscale = fVidGrayCheck->Value(); + + job->subtitle = fSubPopUp->IndexOf( + fSubPopUp->FindMarked() ) - 1; + + job->audios[0] = fAudLang1PopUp->IndexOf( + fAudLang1PopUp->FindMarked() ) - 1; + job->audios[1] = fAudLang2PopUp->IndexOf( + fAudLang2PopUp->FindMarked() ) - 1; + job->audios[2] = -1; + + job->arate = hb_audio_rates[fAudRatePopUp->IndexOf( + fAudRatePopUp->FindMarked() )].rate; + job->abitrate = hb_audio_bitrates[fAudBitratePopUp->IndexOf( + fAudBitratePopUp->FindMarked() )].rate; + + if( fVidConstantRadio->Value() ) + { + job->vquality = 0.01 * fVidConstantSlider->Value(); + job->vbitrate = 0; + } + else if( fVidTargetRadio->Value() ) + { + job->vquality = -1.0; + job->vbitrate = hb_calc_bitrate( job, + atoi( fVidTargetControl->Text() ) ); + } + else + { + job->vquality = -1.0; + job->vbitrate = atoi( fVidAverageControl->Text() ); + } + + job->file = strdup( fDstFileControl->Text() ); + + if( fVidTwoPassCheck->Value() ) + { + job->pass = 1; + hb_add( fHandle, job ); + job->pass = 2; + hb_add( fHandle, job ); + } + else + { + job->pass = 0; + hb_add( fHandle, job ); + } +} + +MainWindow::MainWindow( hb_handle_t * handle ) + : BWindow( BRect( 0,0,10,10 ), "HandBrake " HB_VERSION, + B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + fHandle = handle; + + /* Add the main view */ + fView = new MainView( fHandle ); + AddChild( fView ); + + /* Resize to fit */ + ResizeTo( fView->Bounds().Width(), fView->Bounds().Height() ); + + /* Center */ + BScreen screen; + MoveTo( ( screen.Frame().Width() - fView->Bounds().Width() ) / 2, + ( screen.Frame().Height() - fView->Bounds().Height() ) / 2 ); +} + +void MainWindow::MessageReceived( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_TITLEPOPUP: + case MSG_CHAPTERPOPUP: + case MSG_FORMATPOPUP: + case MSG_CODECSPOPUP: + case MSG_BROWSE: + case MSG_QUALITYRADIO: + case MSG_SLIDER: + case MSG_PICSETTINGS: + case MSG_QUEUE_ENABLE: + case MSG_QUEUE_ADD: + case MSG_QUEUE_SHOW: + case MSG_PAUSE: + case MSG_START: + case B_SAVE_REQUESTED: + fView->HandleMessage( msg ); + break; + + default: + BWindow::MessageReceived( msg ); + break; + } +} + +bool MainWindow::QuitRequested() +{ + be_app_messenger.SendMessage( B_QUIT_REQUESTED ); + return true; +} + +void MainWindow::Update( hb_state_t * s ) +{ + fView->Update( s ); +} diff --git a/beos/MainWindow.h b/beos/MainWindow.h new file mode 100644 index 000000000..1558556f0 --- /dev/null +++ b/beos/MainWindow.h @@ -0,0 +1,121 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <interface/Window.h> +#include <interface/View.h> + +#include "hb.h" + +class BButton; +class BCheckBox; +class BMenuField; +class BPopUpMenu; +class BRadioButton; +class BSlider; +class BStatusBar; +class BStringView; +class BTextControl; +class BFilePanel; + +class PicWindow; +class QueueWindow; + +class MainView : public BView +{ + public: + MainView( hb_handle_t * handle ); + + void HandleMessage( BMessage * msg ); + void Update( hb_state_t * s ); + + private: + void EnableUI( bool ); + void TitlePopUpChanged(); + void ChapterPopUpChanged(); + void FormatPopUpChanged(); + void CodecsPopUpChanged(); + void CheckExtension(); + void QualityRadioChanged(); + void SliderChanged(); + void AddJob(); + + hb_handle_t * fHandle; + + BStringView * fSrcDVD1String; + BStringView * fSrcDVD2String; + BPopUpMenu * fSrcTitlePopUp; + BMenuField * fSrcTitleMenu; + int fSrcTitle; + BStringView * fSrcChapString; + BPopUpMenu * fSrcChapStartPopUp; + BMenuField * fSrcChapStartMenu; + BStringView * fSrcChapToString; + BPopUpMenu * fSrcChapEndPopUp; + BMenuField * fSrcChapEndMenu; + BStringView * fSrcDur1String; + BStringView * fSrcDur2String; + + BPopUpMenu * fDstFormatPopUp; + BMenuField * fDstFormatMenu; + int fDstFormat; + BPopUpMenu * fDstCodecsPopUp; + BMenuField * fDstCodecsMenu; + BTextControl * fDstFileControl; + BButton * fBrowseButton; + + BPopUpMenu * fVidRatePopUp; + BMenuField * fVidRateMenu; + BPopUpMenu * fVidEncoderPopUp; + BMenuField * fVidEncoderMenu; + BStringView * fVidQualityString; + BRadioButton * fVidTargetRadio; + BTextControl * fVidTargetControl; + BRadioButton * fVidAverageRadio; + BTextControl * fVidAverageControl; + BRadioButton * fVidConstantRadio; + BSlider * fVidConstantSlider; + BCheckBox * fVidGrayCheck; + BCheckBox * fVidTwoPassCheck; + + BPopUpMenu * fSubPopUp; + BMenuField * fSubMenu; + + BPopUpMenu * fAudLang1PopUp; + BMenuField * fAudLang1Menu; + BPopUpMenu * fAudLang2PopUp; + BMenuField * fAudLang2Menu; + BPopUpMenu * fAudRatePopUp; + BMenuField * fAudRateMenu; + BPopUpMenu * fAudBitratePopUp; + BMenuField * fAudBitrateMenu; + + BButton * fPictureButton; + + BStatusBar * fProgressBar; + BCheckBox * fQueueCheck; + BButton * fAddButton; + BButton * fShowButton; + BButton * fPauseButton; + BButton * fRipButton; + + BFilePanel * fFilePanel; + PicWindow * fPicWin; + QueueWindow * fQueueWin; +}; + +class MainWindow : public BWindow +{ + public: + MainWindow( hb_handle_t * handle ); + void MessageReceived( BMessage * msg ); + bool QuitRequested(); + + void Update( hb_state_t * s ); + + private: + MainView * fView; + + hb_handle_t * fHandle; +}; + +#endif diff --git a/beos/PicWindow.cpp b/beos/PicWindow.cpp new file mode 100644 index 000000000..6b30f27c2 --- /dev/null +++ b/beos/PicWindow.cpp @@ -0,0 +1,369 @@ +#include <app/Application.h> +#include <interface/Bitmap.h> +#include <interface/Box.h> +#include <interface/Button.h> +#include <interface/CheckBox.h> +#include <interface/RadioButton.h> +#include <interface/Screen.h> +#include <interface/StringView.h> + +#include "PicWindow.h" +#include "Stepper.h" + +#define MSG_PREV 'prev' +#define MSG_NEXT 'next' +#define MSG_CLOSE 'clos' +#define MSG_WIDTH 'widt' +#define MSG_HEIGHT 'heig' +#define MSG_RADIO 'radi' + +PicView::PicView( hb_handle_t * handle, int index ) + : BView( BRect( 0,0,10,10 ), NULL, B_FOLLOW_NONE, B_WILL_DRAW ) +{ + fHandle = handle; + + /* Get the title and the job */ + hb_list_t * list; + list = hb_get_titles( fHandle ); + fTitle = (hb_title_t *) hb_list_item( list, index ); + fJob = fTitle->job; + + /* We'll start with the first picture */ + fIndex = 0; + + /* Allocate a buffer large enough to call hb_get_preview() later */ + fRawPic = (uint8_t *) malloc( ( fTitle->width + 2 ) * + ( fTitle->height + 2 ) * 4 ); + + /* Create the RGB BBitmap we'll use to display */ + fBitmap = new BBitmap( BRect( 0, 0, fTitle->width + 1, + fTitle->height + 1 ), 0, B_RGB32 ); + + /* Now build the interface */ + BRect r, b; + BBox * box; + BButton * button; + BStringView * stringView; + + /* Resize ourselves so the picture fits just fine */ + b = fBitmap->Bounds(); + ResizeTo( b.Width()+170, b.Height()+65 ); + + /* Now build the UI around the BBitmap */ + SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) ); + + /* "Size" box */ + b = Bounds(); + r = BRect( b.right-150,10,b.right-10,105 ); + box = new BBox( r ); + box->SetLabel( "Size" ); + AddChild( box ); + + b = box->Bounds(); + + /* Width */ + r = BRect( 10,15,b.right/2,35 ); + stringView = new BStringView( r, NULL, "Width:" ); + box->AddChild( stringView ); + r = BRect( b.right/2+1,15,b.right-10,35 ); + fWidthStepper = new HBStepper( r, 16, 16, fTitle->width, + fJob->width, new BMessage( MSG_WIDTH ) ); + box->AddChild( fWidthStepper ); + + /* Height */ + r = BRect( 10,40,b.right/2,60 ); + stringView = new BStringView( r, NULL, "Height:" ); + box->AddChild( stringView ); + r = BRect( b.right/2+1,40,b.right-10,60 ); + fHeightStepper = new HBStepper( r, 16, 16, fTitle->height, + fJob->height, new BMessage( MSG_HEIGHT ) ); + box->AddChild( fHeightStepper ); + + /* Aspect ratio */ + r = BRect( 10,65,b.right-10,85 ); + fRatioCheck = new BCheckBox( r, NULL, "Keep aspect ratio", + new BMessage( MSG_WIDTH ) ); + fRatioCheck->SetValue( fJob->keep_ratio ); + box->AddChild( fRatioCheck ); + + /* "Crop" box */ + b = Bounds(); + r = BRect( b.right-150,115,b.right-10,260 ); + box = new BBox( r ); + box->SetLabel( "Crop" ); + AddChild( box ); + + b = box->Bounds(); + + /* Automatic */ + r = BRect( 10,15,b.right-10,35 ); + fAutoRadio = new BRadioButton( r, NULL, "Automatic", + new BMessage( MSG_RADIO ) ); + box->AddChild( fAutoRadio ); + + /* Custom */ + r = BRect( 10,40,b.right-10,60 ); + fCustomRadio = new BRadioButton( r, NULL, "Custom:", + new BMessage( MSG_RADIO ) ); + box->AddChild( fCustomRadio ); + float width = ( b.Width() - 30 ) / 2; + r = BRect( (b.right-width)/2,65,(b.right+width)/2,85 ); + fCropSteppers[0] = new HBStepper( r, 2, 0, fTitle->height/2-2, + fJob->crop[0], new BMessage( MSG_WIDTH ) ); + box->AddChild( fCropSteppers[0] ); + r = BRect( (b.right-width)/2,115,(b.right+width)/2,135 ); + fCropSteppers[1] = new HBStepper( r, 2, 0, fTitle->height/2-2, + fJob->crop[1], new BMessage( MSG_WIDTH ) ); + box->AddChild( fCropSteppers[1] ); + r = BRect( 10,90,10+width,110 ); + fCropSteppers[2] = new HBStepper( r, 2, 0, fTitle->width/2-2, + fJob->crop[2], new BMessage( MSG_HEIGHT ) ); + box->AddChild( fCropSteppers[2] ); + r = BRect( width+20,90,b.right-10,110 ); + fCropSteppers[3] = new HBStepper( r, 2, 0, fTitle->width/2-2, + fJob->crop[3], new BMessage( MSG_HEIGHT ) ); + box->AddChild( fCropSteppers[3] ); + + if( memcmp( fTitle->crop, fJob->crop, 4 * sizeof( int ) ) ) + { + fCustomRadio->SetValue( 1 ); + } + else + { + fAutoRadio->SetValue( 1 ); + } + + /* "Misc" box */ + b = Bounds(); + r = BRect( b.right-150,270,b.right-10,315 ); + box = new BBox( r ); + box->SetLabel( "Misc" ); + AddChild( box ); + + b = box->Bounds(); + + /* Deinterlace */ + r = BRect( 10,15,b.right-10,35 ); + fDeintCheck = new BCheckBox( r, NULL, "Deinterlace picture", + new BMessage( MSG_WIDTH ) ); + fDeintCheck->SetValue( fJob->deinterlace ); + box->AddChild( fDeintCheck ); + + b = Bounds(); + + /* Next/Prev buttons */ + r = BRect( b.right-90,325,b.right-10,350 ); + fPrevButton = new BButton( r, NULL, "Previous", + new BMessage( MSG_PREV ) ); + AddChild( fPrevButton ); + r = BRect( b.right-90,355,b.right-10,380 ); + fNextButton = new BButton( r, NULL, "Next", + new BMessage( MSG_NEXT ) ); + AddChild( fNextButton ); + + /* Info string and OK button */ + r = BRect( 10,b.bottom-30,b.right-100,b.bottom-10 ); + fInfoString = new BStringView( r, NULL, "" ); + AddChild( fInfoString ); + r = BRect( b.right-90,b.bottom-35,b.right-10,b.bottom-10 ); + button = new BButton( r, NULL, "OK", new BMessage( MSG_CLOSE ) ); + AddChild( button ); + + /* Process and draw a first picture */ + RadioChanged(); + UpdateBitmap(); +} + +PicView::~PicView() +{ + free( fRawPic ); + delete fBitmap; +} + +/************************************************************************ + * PicView::Draw + ************************************************************************ + * Calls the inherited BView::Draw, plus draws the BBitmap preview + * and the horizontal line above the info string and OK button + ***********************************************************************/ +void PicView::Draw( BRect rect ) +{ + BRect b; + + BView::Draw( rect ); + + if( LockLooper() ) + { + b = fBitmap->Bounds(); + DrawBitmap( fBitmap, BRect( 10,10,b.Width()+10,b.Height()+10 ) ); + UnlockLooper(); + } + + b = Bounds(); + SetHighColor( 128,128,128 ); + StrokeLine( BPoint( 10,b.bottom-45 ), BPoint( b.right-10,b.bottom-45 ) ); + SetHighColor( 255,255,255 ); + StrokeLine( BPoint( 10,b.bottom-44 ), BPoint( b.right-10,b.bottom-44 ) ); +} + +void PicView::HandleMessage( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_PREV: + fIndex--; + UpdateBitmap(); + break; + + case MSG_NEXT: + fIndex++; + UpdateBitmap(); + break; + + case MSG_WIDTH: + case MSG_HEIGHT: + UpdateSettings( msg->what ); + UpdateBitmap(); + break; + + case MSG_RADIO: + RadioChanged(); + break; + + } +} + +void PicView::RadioChanged() +{ + int cus = fCustomRadio->Value(); + for( int i = 0; i < 4; i++ ) + { + fCropSteppers[i]->SetEnabled( cus ); + } + if( !cus ) + { + memcpy( fJob->crop, fTitle->crop, 4 * sizeof( int ) ); + for( int i = 0; i < 4; i++ ) + { + fCropSteppers[i]->SetValue( fJob->crop[i] ); + } + UpdateSettings( MSG_WIDTH ); + UpdateBitmap(); + } +} + +void PicView::UpdateSettings( uint32 what ) +{ + fJob->width = fWidthStepper->Value(); + fJob->height = fHeightStepper->Value(); + fJob->keep_ratio = fRatioCheck->Value(); + fJob->deinterlace = fDeintCheck->Value(); + for( int i = 0; i < 4; i++ ) + { + fJob->crop[i] = fCropSteppers[i]->Value(); + } + + if( fJob->keep_ratio ) + { + if( what == MSG_WIDTH ) + { + hb_fix_aspect( fJob, HB_KEEP_WIDTH ); + if( fJob->height > fTitle->height ) + { + fJob->height = fTitle->height; + hb_fix_aspect( fJob, HB_KEEP_HEIGHT ); + } + } + else + { + hb_fix_aspect( fJob, HB_KEEP_HEIGHT ); + if( fJob->width > fTitle->width ) + { + fJob->width = fTitle->width; + hb_fix_aspect( fJob, HB_KEEP_WIDTH ); + } + } + } + + fWidthStepper->SetValue( fJob->width ); + fHeightStepper->SetValue( fJob->height ); +} + +void PicView::UpdateBitmap() +{ + /* Sanity checks */ + if( fIndex < 0 ) + { + fIndex = 0; + return; + } + if( fIndex > 9 ) + { + fIndex = 9; + return; + } + + /* Enable/disable buttons */ + fPrevButton->SetEnabled( fIndex > 0 ); + fNextButton->SetEnabled( fIndex < 9 ); + + /* Get new preview and copy it in our BBitmap */ + hb_get_preview( fHandle, fTitle, fIndex, fRawPic ); + for( int i = 0; i < fTitle->height + 2; i++ ) + { + memcpy( ( (uint8_t *) fBitmap->Bits() ) + + i * fBitmap->BytesPerRow(), + fRawPic + 4 * ( fTitle->width + 2 ) * i, + 4 * ( fTitle->width + 2 ) ); + } + + /* Update size info */ + char text[1024]; + snprintf( text, 1024, "Source: %dx%d, output: %dx%d", + fTitle->width, fTitle->height, + fJob->width, fJob->height ); + fInfoString->SetText( text ); + + /* Force redraw */ + Draw( Bounds() ); +} + +PicWindow::PicWindow( hb_handle_t * handle, int index ) + : BWindow( BRect( 0,0,10,10 ), "Picture settings", + B_FLOATING_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + /* Add the PicView */ + fView = new PicView( handle, index ); + AddChild( fView ); + + /* Resize to fit */ + ResizeTo( fView->Bounds().Width(), fView->Bounds().Height() ); + + /* Center */ + BScreen screen; + MoveTo( ( screen.Frame().Width() - fView->Bounds().Width() ) / 2, + ( screen.Frame().Height() - fView->Bounds().Height() ) / 2 ); +} + +void PicWindow::MessageReceived( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_PREV: + case MSG_NEXT: + case MSG_WIDTH: + case MSG_HEIGHT: + case MSG_RADIO: + fView->HandleMessage( msg ); + break; + + case MSG_CLOSE: + Lock(); + Quit(); + break; + + default: + BWindow::MessageReceived( msg ); + } +} diff --git a/beos/PicWindow.h b/beos/PicWindow.h new file mode 100644 index 000000000..9fe5d3131 --- /dev/null +++ b/beos/PicWindow.h @@ -0,0 +1,54 @@ +#ifndef PICWINDOW_H +#define PICWINDOW_H + +#include <interface/Window.h> +#include <interface/View.h> + +#include "hb.h" + +class HBStepper; + +class PicView : public BView +{ + public: + PicView( hb_handle_t * handle, int index ); + ~PicView(); + void Draw( BRect rect ); + + void HandleMessage( BMessage * msg ); + + private: + void UpdateBitmap(); + void RadioChanged(); + void UpdateSettings( uint32 what ); + + hb_handle_t * fHandle; + hb_title_t * fTitle; + hb_job_t * fJob; + int fIndex; + uint8_t * fRawPic; + BBitmap * fBitmap; + + HBStepper * fWidthStepper; + HBStepper * fHeightStepper; + BCheckBox * fRatioCheck; + BRadioButton * fAutoRadio; + BRadioButton * fCustomRadio; + HBStepper * fCropSteppers[4]; + BCheckBox * fDeintCheck; + BButton * fPrevButton; + BButton * fNextButton; + BStringView * fInfoString; +}; + +class PicWindow : public BWindow +{ + public: + PicWindow( hb_handle_t * handle, int index ); + void MessageReceived( BMessage * msg ); + + private: + PicView * fView; +}; + +#endif diff --git a/beos/QueueWindow.cpp b/beos/QueueWindow.cpp new file mode 100644 index 000000000..2b0319e32 --- /dev/null +++ b/beos/QueueWindow.cpp @@ -0,0 +1,132 @@ +#include <app/Message.h> +#include <interface/Button.h> +#include <interface/Screen.h> +#include <interface/ScrollView.h> +#include <interface/StringView.h> + +#include "QueueWindow.h" + +#define MSG_REMOVE 'remo' +#define MSG_CLOSE 'clos' + +QueueView::QueueView( hb_handle_t * handle ) + : BView( BRect( 0,0,500,300 ), NULL, B_FOLLOW_NONE, B_WILL_DRAW ) +{ + fHandle = handle; + + BRect b = Bounds(), r; + + r = BRect( b.right-90,b.bottom-35,b.right-10,b.bottom-10 ); + BButton * button = new BButton( r, NULL, "Close", new BMessage( MSG_CLOSE ) ); + AddChild( button ); + + fScrollView = NULL; + UpdateQueue(); +} + +QueueView::~QueueView() +{ +} + +void QueueView::HandleMessage( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_REMOVE: + break; + } +} + +void QueueView::AddStringView( char * string, BRect * r ) +{ + BStringView * stringView; + + stringView = new BStringView( *r, NULL, string ); + fQueueView->AddChild( stringView ); + free( string ); + + r->top += 20; + r->bottom += 20; +} + +void QueueView::UpdateQueue() +{ + BRect b = Bounds(), r; + + if( fScrollView ) + { + RemoveChild( fScrollView ); + delete fScrollView; + } + + r = BRect( b.left+10,b.top+10,b.right-B_V_SCROLL_BAR_WIDTH-10,b.bottom-45 ); + fQueueView = new BView( r, NULL, B_FOLLOW_NONE, B_WILL_DRAW ); + fScrollView = new BScrollView( NULL, fQueueView, B_FOLLOW_NONE, 0, + false, true, B_FANCY_BORDER ); + AddChild( fScrollView ); + + hb_job_t * j; + hb_title_t * t; + int i; + char * s; + + b = fQueueView->Bounds(); + r = BRect( b.left+10,b.top+10,b.right-10,b.top+25 ); + + for( i = 0; i < hb_count( fHandle ); i++ ) + { + j = hb_job( fHandle, i ); + t = j->title; + + asprintf( &s, "DVD: %s", t->dvd ); + AddStringView( s, &r ); + + asprintf( &s, "Title: %d", t->index ); + AddStringView( s, &r ); + + asprintf( &s, "Chapters: %d to %d", j->chapter_start, j->chapter_end ); + AddStringView( s, &r ); + + asprintf( &s, "Pass: %d of %d", MAX( 1, j->pass ), MIN( 2, j->pass + 1 ) ); + AddStringView( s, &r ); + + asprintf( &s, "Destination: %s", j->file ); + AddStringView( s, &r ); + } +} + +QueueWindow::QueueWindow( hb_handle_t * handle ) + : BWindow( BRect( 0,0,10,10 ), "Queue", + B_FLOATING_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, + B_NOT_CLOSABLE | B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + /* Add the QueueView */ + fView = new QueueView( handle ); + AddChild( fView ); + + /* Resize to fit */ + ResizeTo( fView->Bounds().Width(), fView->Bounds().Height() ); + + /* Center */ + BScreen screen; + MoveTo( ( screen.Frame().Width() - fView->Bounds().Width() ) / 2, + ( screen.Frame().Height() - fView->Bounds().Height() ) / 2 ); +} + +void QueueWindow::MessageReceived( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_REMOVE: + fView->HandleMessage( msg ); + break; + + case MSG_CLOSE: + Lock(); + Quit(); + break; + + default: + BWindow::MessageReceived( msg ); + } +} diff --git a/beos/QueueWindow.h b/beos/QueueWindow.h new file mode 100644 index 000000000..e9b86e3a7 --- /dev/null +++ b/beos/QueueWindow.h @@ -0,0 +1,38 @@ +#ifndef QUEUE_WINDOW_H +#define QUEUE_WINDOW_H + +#include <interface/Window.h> +#include <interface/View.h> + +#include "hb.h" + +class QueueView : public BView +{ + public: + QueueView( hb_handle_t * handle ); + ~QueueView(); + + void HandleMessage( BMessage * msg ); + + private: + void AddStringView( char * string, BRect * r ); + void UpdateQueue(); + + hb_handle_t * fHandle; + + BScrollView * fScrollView; + BView * fQueueView; + BButton * fCloseButton; +}; + +class QueueWindow : public BWindow +{ + public: + QueueWindow( hb_handle_t * handle ); + void MessageReceived( BMessage * msg ); + + private: + QueueView * fView; +}; + +#endif diff --git a/beos/ScanWindow.cpp b/beos/ScanWindow.cpp new file mode 100644 index 000000000..615731f11 --- /dev/null +++ b/beos/ScanWindow.cpp @@ -0,0 +1,320 @@ +#include <drivers/Drivers.h> +#include <interface/Box.h> +#include <interface/Button.h> +#include <interface/MenuField.h> +#include <interface/MenuItem.h> +#include <interface/PopUpMenu.h> +#include <interface/RadioButton.h> +#include <interface/Screen.h> +#include <interface/StatusBar.h> +#include <interface/StringView.h> +#include <interface/TextControl.h> +#include <kernel/fs_info.h> +#include <storage/FilePanel.h> +#include <storage/Path.h> +#include <storage/Query.h> +#include <storage/VolumeRoster.h> +#include <sys/ioctl.h> + +#include "ScanWindow.h" + +#define MSG_RADIO 'radi' +#define MSG_BROWSE 'brow' +#define MSG_CANCEL 'canc' +#define MSG_OPEN 'open' + +ScanView::ScanView( hb_handle_t * handle ) + : BView( BRect( 0,0,400,215 ), NULL, B_FOLLOW_NONE, B_WILL_DRAW ) +{ + fHandle = handle; + + BRect r, b; + BBox * box; + BStringView * stringView; + + SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) ); + + b = Bounds(); + + r = BRect( 10,10,b.right-10,130 ); + box = new BBox( r ); + AddChild( box ); + + b = box->Bounds(); + + r = BRect( 10,10,b.right-10,30 ); + stringView = new BStringView( r, NULL, "Select a DVD:" ); + box->AddChild( stringView ); + + r = BRect( 10,35,b.right/2,55 ); + fDetectedRadio = new BRadioButton( r, NULL, "Detected volume", + new BMessage( MSG_RADIO ) ); + box->AddChild( fDetectedRadio ); + + r = BRect( b.right/2+1,35,b.right-10,55 ); + fPopUp = new BPopUpMenu( "No volume detected" ); + fMenu = new BMenuField( r, NULL, "", fPopUp, true ); + fMenu->SetDivider( 0 ); + box->AddChild( fMenu ); + + r = BRect( 10,60,b.right/2,80 ); + fFolderRadio = new BRadioButton( r, NULL, "DVD Folder / Image", + new BMessage( MSG_RADIO ) ); + box->AddChild( fFolderRadio ); + + r = BRect( b.right/2+1,60,b.right-10,80 ); + fControl = new BTextControl( r, NULL, "", "", new BMessage() ); + fControl->SetDivider( 0 ); + box->AddChild( fControl ); + + r = BRect( b.right-90,85,b.right-10,110 ); + fBrowseButton = new BButton( r, NULL, "Browse", + new BMessage( MSG_BROWSE ) ); + box->AddChild( fBrowseButton ); + + b = Bounds(); + + r = BRect( 10,b.bottom-75,b.right-10,b.bottom-45 ); + fBar = new BStatusBar( r, NULL, NULL, NULL ); + AddChild( fBar ); + + r = BRect( b.right-180,b.bottom-35,b.right-100,b.bottom-10 ); + fCancelButton = new BButton( r, NULL, "Cancel", + new BMessage( MSG_CANCEL ) ); + AddChild( fCancelButton ); + + r = BRect( b.right-90,b.bottom-35,b.right-10,b.bottom-10 ); + fOpenButton = new BButton( r, NULL, "Open", new BMessage( MSG_OPEN ) ); + AddChild( fOpenButton ); + + DetectVolumes(); + + if( fPopUp->CountItems() > 0 ) + { + fDetectedRadio->SetValue( true ); + } + else + { + fFolderRadio->SetValue( true ); + } + RadioChanged(); + + fFilePanel = NULL; +} + +void ScanView::HandleMessage( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_RADIO: + RadioChanged(); + break; + + case MSG_BROWSE: + if( !fFilePanel ) + { + fFilePanel = new BFilePanel( B_OPEN_PANEL, + new BMessenger( Window() ), NULL, + B_FILE_NODE | B_DIRECTORY_NODE, false, NULL, NULL, + true ); + } + fFilePanel->Show(); + break; + + case B_REFS_RECEIVED: + { + entry_ref ref; + if( msg->FindRef( "refs", 0, &ref ) == B_OK ) + { + BPath * path = new BPath( &ref ); + fControl->SetText( path->Path()); + } + break; + } + + case MSG_CANCEL: + Window()->Hide(); + break; + + case MSG_OPEN: + SetEnabled( false ); + fBar->Update( - fBar->CurrentValue(), "Opening..." ); + if( fDetectedRadio->Value() && fPopUp->CountItems() > 0 ) + { + hb_scan( fHandle, fPopUp->FindMarked()->Label(), 0 ); + } + else if( fFolderRadio->Value() ) + { + hb_scan( fHandle, fControl->Text(), 0 ); + } + break; + } +} + +void ScanView::Update( hb_state_t * s ) +{ + if( !LockLooper() ) + { + return; + } + + switch( s->state ) + { +#define p s->param.scanning + case HB_STATE_SCANNING: + { + char text[1024]; + snprintf( text, 1024, "Scanning title %d of %d...", p.title_cur, + p.title_count ); + fBar->Update( fBar->MaxValue() * ( - 0.5 + p.title_cur ) / + p.title_count - fBar->CurrentValue(), text ); + break; + } +#undef p + + case HB_STATE_SCANDONE: + /* If we are still here, then no title was found */ + fBar->Update( - fBar->CurrentValue(), + "No valid title found." ); + SetEnabled( true ); + break; + } + + UnlockLooper(); +} + +void ScanView::RadioChanged() +{ + bool b = fDetectedRadio->Value(); + fMenu->SetEnabled( b ); + fControl->SetEnabled( !b ); + fBrowseButton->SetEnabled( !b ); + fOpenButton->SetEnabled( !b || ( fPopUp->CountItems() > 0 ) ); +} + +void ScanView::SetEnabled( bool b ) +{ + fDetectedRadio->SetEnabled( b ); + fMenu->SetEnabled( b ); + fFolderRadio->SetEnabled( b ); + fControl->SetEnabled( b ); + fBrowseButton->SetEnabled( b ); + fOpenButton->SetEnabled( b ); + + if( b ) + { + RadioChanged(); + } +} + +void ScanView::DetectVolumes() +{ + BVolumeRoster * roster = new BVolumeRoster(); + BVolume * volume = new BVolume(); + fs_info info; + int device; + device_geometry geometry; + + while( roster->GetNextVolume( volume ) == B_NO_ERROR ) + { + /* open() and ioctl() for more informations */ + fs_stat_dev( volume->Device(), &info ); + if( ( device = open( info.device_name, O_RDONLY ) ) < 0 ) + { + continue; + } + + if( ioctl( device, B_GET_GEOMETRY, &geometry, + sizeof( geometry ) ) < 0 ) + { + continue; + } + + /* Get the volume name */ + char volumeName[B_FILE_NAME_LENGTH]; + volume->GetName( volumeName ); + + if( volume->IsReadOnly() && geometry.device_type == B_CD ) + { + /* May be a DVD */ + fPopUp->AddItem( new BMenuItem( info.device_name, NULL ) ); + } + else if( geometry.device_type == B_DISK ) + { + /* May be a hard drive. Look for VIDEO_TS folders on it */ + BQuery * query = new BQuery(); + + if( query->SetVolume( volume ) != B_OK ) + { + delete query; + continue; + } + + if( query->SetPredicate( "name = VIDEO_TS.IFO" ) != B_OK ) + { + delete query; + continue; + } + + query->Fetch(); + + BEntry entry, parentEntry; + BPath path; + while( query->GetNextEntry( &entry ) == B_OK ) + { + entry.GetParent( &parentEntry ); + parentEntry.GetPath( &path ); + + fPopUp->AddItem( new BMenuItem( path.Path(), NULL ) ); + } + + delete query; + } + } + + if( fPopUp->CountItems() > 0 ) + { + fPopUp->ItemAt( 0 )->SetMarked( true ); + } +} + +ScanWindow::ScanWindow( hb_handle_t * handle ) + : BWindow( BRect( 0,0,10,10 ), "Scan", B_FLOATING_WINDOW_LOOK, + B_MODAL_SUBSET_WINDOW_FEEL, B_NOT_CLOSABLE | + B_NOT_RESIZABLE | B_NOT_ZOOMABLE ) +{ + /* Add the scan view */ + fView = new ScanView( handle ); + AddChild( fView ); + + /* Resize to fit */ + ResizeTo( fView->Bounds().Width(), fView->Bounds().Height() ); + + /* Center */ + BScreen screen; + MoveTo( ( screen.Frame().Width() - fView->Bounds().Width() ) / 2, + ( screen.Frame().Height() - fView->Bounds().Height() ) / 2 ); +} + +void ScanWindow::MessageReceived( BMessage * msg ) +{ + switch( msg->what ) + { + case MSG_RADIO: + case MSG_BROWSE: + case MSG_CANCEL: + case MSG_OPEN: + case B_REFS_RECEIVED: + fView->HandleMessage( msg ); + break; + + default: + BWindow::MessageReceived( msg ); + } +} + +void ScanWindow::Update( hb_state_t * s ) +{ + fView->Update( s ); +} + diff --git a/beos/ScanWindow.h b/beos/ScanWindow.h new file mode 100644 index 000000000..f46c1c14f --- /dev/null +++ b/beos/ScanWindow.h @@ -0,0 +1,56 @@ +#ifndef SCANWINDOW_H +#define SCANWINDOW_H + +#include <interface/Window.h> +#include <interface/View.h> + +#include "hb.h" + +class BButton; +class BMenuField; +class BPopUpMenu; +class BRadioButton; +class BStatusBar; +class BTextControl; + +class ScanView : public BView +{ + public: + ScanView( hb_handle_t * handle ); + + void HandleMessage( BMessage * msg ); + void Update( hb_state_t * s ); + void RadioChanged(); + void SetEnabled( bool ); + + private: + void DetectVolumes(); + + hb_handle_t * fHandle; + + BRadioButton * fDetectedRadio; + BPopUpMenu * fPopUp; + BMenuField * fMenu; + BRadioButton * fFolderRadio; + BTextControl * fControl; + BButton * fBrowseButton; + BStatusBar * fBar; + BButton * fCancelButton; + BButton * fOpenButton; + + BFilePanel * fFilePanel; +}; + +class ScanWindow : public BWindow +{ + public: + ScanWindow( hb_handle_t * handle ); + void MessageReceived( BMessage * msg ); + + void Update( hb_state_t * s ); + + private: + ScanView * fView; +}; + +#endif diff --git a/beos/Stepper.cpp b/beos/Stepper.cpp new file mode 100644 index 000000000..8f2733ac5 --- /dev/null +++ b/beos/Stepper.cpp @@ -0,0 +1,130 @@ +#include <interface/Region.h> +#include <interface/TextControl.h> +#include <interface/Window.h> + +#include "Stepper.h" + +#include <stdio.h> + +HBStepper::HBStepper( BRect rect, int step, int min, int max, int val, + BMessage * message ) + : BView( rect, NULL, B_FOLLOW_NONE, B_WILL_DRAW ) +{ + fStep = step; + fMin = min; + fMax = max; + fMessage = message; + + BRect b = Bounds(); + + fEnabled = true; + + fControl = new BTextControl( BRect( 0,1,b.Width()-14,b.Height()-1 ), + NULL, NULL, "", new BMessage() ); + fControl->SetDivider( 0.0 ); + fControl->TextView()->MakeEditable( false ); + AddChild( fControl ); + + SetValue( val ); +} + +void HBStepper::Draw( BRect rect ) +{ + /* Why do we have to do this here!? */ + fControl->TextView()->MakeEditable( false ); + fControl->TextView()->MakeSelectable( false ); + + BRect b = Bounds(); + BRegion region; + + SetHighColor( 128,128,128 ); /* Dark gray */ + region.MakeEmpty(); + region.Include( BRect( 3, 0,10, 0 ) ); + region.Include( BRect( 2, 1, 3, 1 ) ); + region.Include( BRect( 10, 1,11, 1 ) ); + region.Include( BRect( 1, 2, 2, 2 ) ); + region.Include( BRect( 11, 2,12, 2 ) ); + region.Include( BRect( 1, 2, 1,18 ) ); + region.Include( BRect( 1,10,12,10 ) ); + region.Include( BRect( 12, 2,12,18 ) ); + region.Include( BRect( 1,18, 2,18 ) ); + region.Include( BRect( 11,18,12,18 ) ); + region.Include( BRect( 2,19, 3,19 ) ); + region.Include( BRect( 10,19,11,19 ) ); + region.Include( BRect( 3,20,10,20 ) ); + region.OffsetBy( b.Width()-12,0 ); + FillRegion( ®ion ); + + SetHighColor( 0,0,0 ); /* Black */ + region.MakeEmpty(); + region.Include( BRect( 6, 4, 7, 4 ) ); + region.Include( BRect( 5, 5, 8, 6 ) ); + region.Include( BRect( 5,14, 8,15 ) ); + region.Include( BRect( 6,16, 7,16 ) ); + region.OffsetBy( b.Width()-12,0 ); + FillRegion( ®ion ); + + BView::Draw( rect ); +} + +void HBStepper::AttachedToWindow() +{ + if( Parent() ) + { + SetViewColor( Parent()->ViewColor() ); + } +} + +void HBStepper::MouseDown( BPoint point ) +{ + BRect r, b = Bounds(); + + if( !fEnabled ) + { + return; + } + + BMessenger messenger( Window() ); + + r = BRect( 2,1,11,9 ); + r.OffsetBy( b.Width()-12,0 ); + if( r.Contains( point ) ) + { + SetValue( fValue + fStep ); + messenger.SendMessage( fMessage ); + } + r.OffsetBy( 0,10 ); + if( r.Contains( point ) ) + { + SetValue( fValue - fStep ); + messenger.SendMessage( fMessage ); + } +} + +void HBStepper::SetValue( int val ) +{ + fValue = val; + if( fValue < fMin ) + { + fValue = fMin; + } + if( fValue > fMax ) + { + fValue = fMax; + } + + char text[16]; + snprintf( text, 16, "%d", fValue ); + fControl->SetText( text ); +} + +int HBStepper::Value() +{ + return fValue; +} + +void HBStepper::SetEnabled( bool e ) +{ + fEnabled = e; + fControl->SetEnabled( fEnabled ); +} diff --git a/beos/Stepper.h b/beos/Stepper.h new file mode 100644 index 000000000..2b0493f6e --- /dev/null +++ b/beos/Stepper.h @@ -0,0 +1,31 @@ +#ifndef STEPPER_H +#define STEPPER_H + +#include <interface/View.h> + +class BTextControl; + +class HBStepper : public BView +{ + public: + HBStepper( BRect rect, int step, int min, int max, int val, + BMessage * message ); + void Draw( BRect rect ); + void AttachedToWindow(); + void MouseDown( BPoint point ); + void SetValue( int val ); + int Value(); + void SetEnabled( bool e ); + + private: + int fStep; + int fMin; + int fMax; + int fValue; + BMessage * fMessage; + + bool fEnabled; + BTextControl * fControl; +}; + +#endif diff --git a/beos/liblayout/HGroup.h b/beos/liblayout/HGroup.h deleted file mode 100644 index 9eee83fea..000000000 --- a/beos/liblayout/HGroup.h +++ /dev/null @@ -1,40 +0,0 @@ - -#ifndef _HGROUP_H -#define _HGROUP_H -#include "MGroup.h" -#include <View.h> -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT HGroup : public MGroup, public BView -{ - public: HGroup(minimax mpm,MView *kid=0, ...); - HGroup(MView *kid=0, ...); - HGroup(BMessage*); - virtual ~HGroup(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void MouseDown(BPoint); - - private: virtual void _expansionhgroup1(); - virtual void _expansionhgroup2(); - virtual void _expansionhgroup3(); - - static int cmpkids(const void* v1,const void *v2); - int *size; - float totalweight; - int numkids; - sortstruct *childorder; - MView **mkid; - float totalminx,totalmaxx; - BRect *lastrect; - - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/LayeredGroup.h b/beos/liblayout/LayeredGroup.h deleted file mode 100644 index 61264ca36..000000000 --- a/beos/liblayout/LayeredGroup.h +++ /dev/null @@ -1,37 +0,0 @@ - -#ifndef _LAYEREDGROUP_H -#define _LAYEREDGROUP_H - -#include "MGroup.h" -#include <Control.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT LayeredGroup : public MGroup, public BControl -{ - public: LayeredGroup(minimax mpm,MView *arg=0, ...); - LayeredGroup(MView *arg=0, ...); - LayeredGroup(BMessage*); - virtual ~LayeredGroup(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - void ActivateLayer(int); - virtual void MessageReceived(BMessage *mes); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: virtual void _expansionlayeredgroup1(); - virtual void _expansionlayeredgroup2(); - - int numkids; - int activekid; - - uint32 _expansiondata[3]; -}; - - -#endif diff --git a/beos/liblayout/MApplication.h b/beos/liblayout/MApplication.h deleted file mode 100644 index acdd13214..000000000 --- a/beos/liblayout/MApplication.h +++ /dev/null @@ -1,29 +0,0 @@ - -#ifndef _MAPPLICATION_H -#define _MAPPLICATION_H - -#include "layout.h" -#include <Application.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MApplication : public BApplication -{ - public: MApplication(char *); - MApplication(BMessage*); - virtual ~MApplication(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual void MessageReceived(BMessage*); - - virtual status_t GetSupportedSuites(BMessage *message); - virtual BHandler *ResolveSpecifier(BMessage *message, int32 index, BMessage *specifier, int32 command, const char *property); - - private: - virtual void _expansionmapplication1(); - virtual void _expansionmapplication2(); - uint32 _expansiondata[4]; -}; -#endif diff --git a/beos/liblayout/MBViewWrapper.h b/beos/liblayout/MBViewWrapper.h deleted file mode 100644 index 351dfb800..000000000 --- a/beos/liblayout/MBViewWrapper.h +++ /dev/null @@ -1,30 +0,0 @@ - -#ifndef _MBVIEWWRAPPER_H -#define _MBVIEWWRAPPER_H -#include "layout.h" -#include <View.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MBViewWrapper : public MView, public BView -{ - public: MBViewWrapper(BView *view, bool usepreferred=true, bool x_fixed=true, bool y_fixed=true); - MBViewWrapper(BMessage*); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual ~MBViewWrapper(); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: virtual void _expansionmbviewwrapper1(); - - BView *childview; - - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/MBorder.h b/beos/liblayout/MBorder.h deleted file mode 100644 index 4e925ec2d..000000000 --- a/beos/liblayout/MBorder.h +++ /dev/null @@ -1,68 +0,0 @@ - -#ifndef _MBORDER_H -#define _MBORDER_H -#include "MGroup.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MBorder : public MGroup, public BView -{ - public: - enum { - ROTATE_REVERSE=(int)0x80000000 - }; - - MBorder(ulong border_type,ulong spacing,char *name=NULL,MView *kid=NULL); - MBorder(BMessage*); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - ~MBorder(); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void Draw(BRect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void FrameResized(float width, float height); - void DrawBorder(); - void SetLabel(char *); - char *Label(); - void SetHighlight(int); - void SetHighlightColors(rgb_color color1, rgb_color color2, rgb_color color3); - - private: - virtual void _expansionmborder1(); - virtual void _expansionmborder2(); - - static long _cycler(void *arg); - void Cycler(); - int highlightmode; - thread_id cycler; - - ulong bordertype; - ulong extraspacing; - ulong extralabelspacing; - char *label; - char *truncatedlabel; - - rgb_color *highlightcolors; - - uint32 _expansiondata[1]; -}; - - -enum -{ - M_NO_BORDER, - M_RAISED_BORDER, - M_DEPRESSED_BORDER, - M_LABELED_BORDER, - M_ETCHED_BORDER -}; - -enum -{ - M_SHOW_FULL_LABEL= 0x00000100 -}; -#endif diff --git a/beos/liblayout/MButton.h b/beos/liblayout/MButton.h deleted file mode 100644 index 64cd3e32b..000000000 --- a/beos/liblayout/MButton.h +++ /dev/null @@ -1,53 +0,0 @@ - -#ifndef _MBUTTON -#define _MBUTTON -#include "layout.h" -#include <Button.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MButton : public MView, public BButton -{ - public: ulong ID; - - MButton(const char *label, ulong id=0,minimax size=minimax(-1,-1,1E6,1E6,1)); - MButton(const char *label, BMessage *message, BHandler *handler=NULL, minimax size=minimax(-1,-1,1E6,1E6,1)); - MButton(BMessage*); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual ~MButton(); - void SetRepeat(ulong initial_delay, ulong repeat_delay); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void setcolor(rgb_color, bool); - - virtual void Draw(BRect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - virtual void MouseDown(BPoint); - - private: static long _mousetracker(void *arg); - void _MouseTracker(); - thread_id mousethread; - BHandler *target; - int64 lastwhen; - ulong initialdelay; - ulong repeatdelay; - void initobject(); - ulong buttonmask; - - uint32 _expansiondata[2]; -}; - -extern const IMPEXPLIBLAYOUT char M_BUTTON_POINTER[]; -extern const IMPEXPLIBLAYOUT char M_BUTTON_ID[]; -extern const IMPEXPLIBLAYOUT char M_BUTTON_MASK[]; -extern const IMPEXPLIBLAYOUT char M_DOUBLECLICK[]; -extern const IMPEXPLIBLAYOUT char M_REPEAT[]; -extern const IMPEXPLIBLAYOUT char M_RELEASE[]; - -#endif diff --git a/beos/liblayout/MCheckBox.h b/beos/liblayout/MCheckBox.h deleted file mode 100644 index 7b39abda2..000000000 --- a/beos/liblayout/MCheckBox.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef _MCHECKBOX -#define _MCHECKBOX -#include "layout.h" -#include <CheckBox.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MCheckBox : public MView, public BCheckBox -{ - public: MCheckBox(const char *label,ulong id=0, bool state=false); - MCheckBox(const char *label, BMessage *message, BHandler *handler=NULL, bool state=false); - MCheckBox(BMessage*); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual ~MCheckBox(); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - - private: BHandler *target; - uint32 _expansiondata[2]; -}; - -extern const IMPEXPLIBLAYOUT char M_CHECKBOX_POINTER[]; -extern const IMPEXPLIBLAYOUT char M_CHECKBOX_ID[]; - -#endif diff --git a/beos/liblayout/MDividable.h b/beos/liblayout/MDividable.h deleted file mode 100644 index 800772b88..000000000 --- a/beos/liblayout/MDividable.h +++ /dev/null @@ -1,35 +0,0 @@ - -// Abstract base class for an object that can be 'divided'. -// Currently this includes MTextControl and MPopup. -// The dividable class, and the global function below, is -// used to align the left half (the label) and the right -// half (data-entry/selection) of a group of MDividable's - -#ifndef _MDIVIDABLE_H -#define _MDIVIDABLE_H - -#include "layout.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MDividable -{ - public: - float labelwidth; - MDividable *rolemodel; - - public: - MDividable(); -// work around my own bug... -#ifdef BUILDING_LIBLAYOUT - ~MDividable(); -#endif - void DivideSameAs(MDividable *); - virtual float LabelWidth(); -}; - -extern void IMPEXPLIBLAYOUT DivideSame(MView *, MView *, ...); - -#endif diff --git a/beos/liblayout/MDragBar.h b/beos/liblayout/MDragBar.h deleted file mode 100644 index e345668c4..000000000 --- a/beos/liblayout/MDragBar.h +++ /dev/null @@ -1,38 +0,0 @@ - -#ifndef _MDRAGBAR_H -#define _MDRAGBAR_H -#include "layout.h" -#include <Control.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MDragBar : public MView, public BControl -{ - public: MDragBar(minimax size=minimax(1,1,1E6,1E6)); - MDragBar(BMessage*); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual ~MDragBar(); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void AttachedToWindow(); - virtual void Draw(BRect rect); - virtual void KeyDown(const char *bytes, int32 numbytes); - virtual void DetachedFromWindow(); - virtual void MouseDown(BPoint); - - private: virtual void _expansionmdragbar1(); - - thread_id mousethread; - BPoint dragpoint; - - static long _mousetracker(void *arg); - void _MouseTracker(); - - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/MEject.h b/beos/liblayout/MEject.h deleted file mode 100644 index a9c017346..000000000 --- a/beos/liblayout/MEject.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _MEJECT_H -#define _MEJECT_H - -#include "MPictureButton.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MEject : public MPictureButton -{ - public: MEject(BHandler *id); - MEject(BHandler *id, BMessage*); - MEject(BMessage*); - virtual ~MEject(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual void MakePictures(); -}; -extern const IMPEXPLIBLAYOUT char M_BUTTON_POINTER[]; - -#endif diff --git a/beos/liblayout/MFFWD.h b/beos/liblayout/MFFWD.h deleted file mode 100644 index 97c0d53e1..000000000 --- a/beos/liblayout/MFFWD.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _MFFWD_H -#define _MFFWD_H - -#include "MPictureButton.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MFFWD : public MPictureButton -{ - public: MFFWD(BHandler *id=NULL); - MFFWD(BHandler *id, BMessage*); - MFFWD(BMessage*); - virtual ~MFFWD(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual void MakePictures(); -}; - -extern const IMPEXPLIBLAYOUT char M_BUTTON_POINTER[]; - -#endif diff --git a/beos/liblayout/MGroup.h b/beos/liblayout/MGroup.h deleted file mode 100644 index 73dcbfb9c..000000000 --- a/beos/liblayout/MGroup.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - - MGroup is an abstract class from which all groups should derive. - -*/ - -#ifndef _MGROUP_H -#define _MGROUP_H - -#include "layout.h" -#include <View.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MGroup : public MView -{ - public: MGroup(); - virtual ~MGroup(); - - virtual void reloadfont(BFont *font[]); -}; - -typedef struct -{ - MView *kid; - int kidnum; -} sortstruct; - -#endif diff --git a/beos/liblayout/MListView.h b/beos/liblayout/MListView.h deleted file mode 100644 index 95c4d42ca..000000000 --- a/beos/liblayout/MListView.h +++ /dev/null @@ -1,30 +0,0 @@ - -#ifndef _MLISTVIEW_H -#define _MLISTVIEW_H -#include "layout.h" -#include <ListView.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MListView : public MView, public BListView -{ - public: MListView(list_view_type type=B_SINGLE_SELECTION_LIST, - minimax size=minimax(50,50)); - MListView(BMessage*); - virtual ~MListView(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual void reloadfont(BFont *font[]); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void MessageReceived(BMessage*); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: virtual void _expansionmlistview1(); - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/MMenuBar.h b/beos/liblayout/MMenuBar.h deleted file mode 100644 index a5b061a19..000000000 --- a/beos/liblayout/MMenuBar.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef _MMENUBAR_H -#define _MMENUBAR_H - -#include "layout.h" -#include <MenuBar.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MMenuBar: public MView, public BMenuBar -{ - public: - MMenuBar(menu_layout layout=B_ITEMS_IN_ROW); - MMenuBar(menu_layout layout, bool resizetofit); - MMenuBar(BMessage*); - virtual ~MMenuBar(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect); - virtual void reloadfont(BFont *font[]); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - private: - virtual void _expansionmmenubar1(); - virtual void _expansionmmenubar2(); - - uint32 _expansiondata[2]; -}; -#endif diff --git a/beos/liblayout/MOutlineListView.h b/beos/liblayout/MOutlineListView.h deleted file mode 100644 index acb00e19b..000000000 --- a/beos/liblayout/MOutlineListView.h +++ /dev/null @@ -1,32 +0,0 @@ - -#ifndef _MOUTLINELISTVIEW_H -#define _MOUTLINELISTVIEW_H -#include "layout.h" -#include <OutlineListView.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MOutlineListView : public MView, public BOutlineListView -{ - public: MOutlineListView(list_view_type type=B_SINGLE_SELECTION_LIST, - minimax size=minimax(50,50)); - MOutlineListView(BMessage*); - virtual ~MOutlineListView(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual void reloadfont(BFont *font[]); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void MessageReceived(BMessage*); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: virtual void _expansionmoutlinelistview1(); - virtual void _expansionmoutlinelistview2(); - - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/MPictureButton.h b/beos/liblayout/MPictureButton.h deleted file mode 100644 index 687b5c28a..000000000 --- a/beos/liblayout/MPictureButton.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _MPICTUREBUTTON_H -#define _MPICTUREBUTTON_H - -#include "layout.h" -#include <PictureButton.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MPictureButton : public MView, public BPictureButton -{ - public: - MPictureButton(minimax size, BPicture *off, BPicture *on, - BMessage *message=NULL, BHandler *target=NULL, - uint32 behavior=B_ONE_STATE_BUTTON); - MPictureButton(BMessage *archive); - virtual ~MPictureButton(); - void SetRepeat(ulong initial_delay, ulong repeat_delay); - - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect); - virtual void setcolor(rgb_color col, bool deep=false); - virtual void MakePictures(); - - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void MouseDown(BPoint); - - private: - virtual void _expansionmpicturebutton1(); - virtual void _expansionmpicturebutton2(); - - thread_id mousethread; - int64 lastwhen; - ulong initialdelay; - ulong repeatdelay; - ulong buttonmask; - BHandler *target; - - static long _mousetracker(void *arg); - void _MouseTracker(); - - uint32 _expansiondata[2]; -}; - -extern const IMPEXPLIBLAYOUT char M_DOUBLECLICK[]; -extern const IMPEXPLIBLAYOUT char M_BUTTON_MASK[]; -extern const IMPEXPLIBLAYOUT char M_REPEAT[]; -extern const IMPEXPLIBLAYOUT char M_RELEASE[]; - -#endif diff --git a/beos/liblayout/MPlayBW.h b/beos/liblayout/MPlayBW.h deleted file mode 100644 index 043aa46d3..000000000 --- a/beos/liblayout/MPlayBW.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _MPLAYBW_H -#define _MPLAYBW_H - -#include "MPictureButton.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MPlayBW : public MPictureButton -{ - public: MPlayBW(BHandler*); - MPlayBW(BHandler *id, BMessage*); - MPlayBW(BMessage*); - virtual ~MPlayBW(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual void MakePictures(); -}; -extern const IMPEXPLIBLAYOUT char M_BUTTON_POINTER[]; - -#endif diff --git a/beos/liblayout/MPlayFW.h b/beos/liblayout/MPlayFW.h deleted file mode 100644 index 7f847df7b..000000000 --- a/beos/liblayout/MPlayFW.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _MPLAYFW_H -#define _MPLAYFW_H - -#include "MPictureButton.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MPlayFW : public MPictureButton -{ - public: MPlayFW(BHandler*); - MPlayFW(BHandler *id, BMessage*); - MPlayFW(BMessage*); - virtual ~MPlayFW(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual void MakePictures(); -}; -extern const IMPEXPLIBLAYOUT char M_BUTTON_POINTER[]; - -#endif diff --git a/beos/liblayout/MPopup.h b/beos/liblayout/MPopup.h deleted file mode 100644 index 2223664ec..000000000 --- a/beos/liblayout/MPopup.h +++ /dev/null @@ -1,45 +0,0 @@ - -#ifndef _MPOPUP_H -#define _MPOPUP_H -#include "layout.h" -#include "MDividable.h" -#include <MenuField.h> - -class BPopUpMenu; - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MPopup: - public MView, public MDividable, public BMenuField -{ - public: MPopup(char *label, char *item ...); - MPopup(char *label, BMessage*, BHandler *, char *item ...); - MPopup(BMessage*); - virtual ~MPopup(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual float LabelWidth(); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void reloadfont(BFont *font[]); - void SetActive(ulong, bool send=true); - void EnableItem(ulong index, bool enabled); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: virtual void _expansionmpopup1(); - - char *poplabel; - BHandler *target; - BPopUpMenu *popup; - - uint32 _expansiondata[2]; -}; - -extern const IMPEXPLIBLAYOUT char M_POPUP_POINTER_NAME[]; - -#endif diff --git a/beos/liblayout/MProgressBar.h b/beos/liblayout/MProgressBar.h deleted file mode 100644 index 3938c2583..000000000 --- a/beos/liblayout/MProgressBar.h +++ /dev/null @@ -1,58 +0,0 @@ - -#ifndef _MSTATUSBAR_H -#define _MSTATUSBAR_H -#include "layout.h" -#include <View.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MProgressBar : public MView, public BView -{ - public: float value; - float currentwidth; - - public: MProgressBar(BHandler *, bool pulsed_updates=false); - MProgressBar(BMessage*); - virtual ~MProgressBar(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void setcolor(rgb_color,bool); - void setbarcolor(rgb_color); - rgb_color getbarcolor() {return bar_fill;}; - virtual void Draw(BRect); - virtual void Pulse(); - void Refresh(); - void SetValue(float value); - virtual void MouseDown(BPoint); - virtual void WindowActivated(bool); - virtual void FrameResized(float,float); - virtual void MessageReceived(BMessage *mes); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: virtual void _expansionmprogressbar1(); - virtual void _expansionmprogressbar2(); - - thread_id mousethread; - static long _mousetracker(void *arg); - long mousetracker(); - - BRect lastbounds; - BHandler *target; - rgb_color bar_hi; - rgb_color bar_fill; - rgb_color bar_low; - float barwidth; - - uint32 _expansiondata[2]; -}; - -extern const IMPEXPLIBLAYOUT char M_PROGRESSBAR_FRACTION[]; - -#endif - diff --git a/beos/liblayout/MRadioGroup.h b/beos/liblayout/MRadioGroup.h deleted file mode 100644 index bb430f2da..000000000 --- a/beos/liblayout/MRadioGroup.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef _MRADIOGROUP_H -#define _MRADIOGROUP_H -#include "MGroup.h" -#include <RadioButton.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MRadioGroup : public MGroup, public BView -{ - public: MRadioGroup(char *item ...); - MRadioGroup(BMessage *model, char *item ...); - MRadioGroup(BMessage *model, BHandler *target, char *item ...); - MRadioGroup(BMessage*); - virtual ~MRadioGroup(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void SetActive(ulong); - virtual long ActiveButton(); - virtual void reloadfont(BFont *font[]); - virtual void setcolor(rgb_color col,bool deep); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: virtual void _expansionmradiogroup1(); - virtual void _expansionmradiogroup2(); - - ulong numradios; - BHandler *handler; - - uint32 _expansiondata[3]; -}; - -extern const IMPEXPLIBLAYOUT char M_RADIO_POINTER_NAME[]; -extern const IMPEXPLIBLAYOUT char M_RADIO_INDEX_NAME[]; - - -#endif - - - diff --git a/beos/liblayout/MRew.h b/beos/liblayout/MRew.h deleted file mode 100644 index f21683b5d..000000000 --- a/beos/liblayout/MRew.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _MREW_H -#define _MREW_H - -#include "MPictureButton.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MRew : public MPictureButton -{ - public: MRew(BHandler*); - MRew(BHandler *id, BMessage*); - MRew(BMessage*); - virtual ~MRew(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual void MakePictures(); -}; -extern const IMPEXPLIBLAYOUT char M_BUTTON_POINTER[]; - -#endif diff --git a/beos/liblayout/MScrollView.h b/beos/liblayout/MScrollView.h deleted file mode 100644 index 8ba21ce0e..000000000 --- a/beos/liblayout/MScrollView.h +++ /dev/null @@ -1,39 +0,0 @@ - -#ifndef _MSCROLLVIEW_H -#define _MSCROLLVIEW_H - -#include "layout.h" -#include <ScrollView.h> - -// An MScrollView accepts another MView as its target. -// The MScrollView will display scrollbars as requested -// so that the target MView may be scrolled left/right or -// up/down. - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MScrollView: public MView, public BScrollView -{ - public: - MScrollView(MView *target, bool horizontal=false, bool vertical=false, - border_style border=B_FANCY_BORDER, minimax size=0); - MScrollView(BMessage*); - virtual ~MScrollView(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual minimax layoutprefs(); - virtual BRect layout(BRect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: - MView *kid; - float leftinset; - float rightinset; - float topinset; - float bottominset; -}; - -#endif diff --git a/beos/liblayout/MSlider.h b/beos/liblayout/MSlider.h deleted file mode 100644 index 6e7077d3d..000000000 --- a/beos/liblayout/MSlider.h +++ /dev/null @@ -1,30 +0,0 @@ - - -#ifndef _MSLIDER_H -#define _MSLIDER_H - -#include "layout.h" -#include "Slider.h" - -class IMPEXPLIBLAYOUT MSlider: public MView, public BSlider -{ - public: - MSlider(const char *label, int32 minval, int32 maxval,int32 granularity=1, BMessage *message=NULL, BHandler *target=NULL, thumb_style ts=B_BLOCK_THUMB); - virtual ~MSlider(); - virtual void AllAttached(); - virtual void DetachedFromWindow(); - virtual void SetValue(int32 value); - void SetGranularity(int32 granul); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect); - - private: - virtual void _expansionmslider1(); - virtual void _expansionmslider2(); - BHandler *target; - int32 granularity; - uint32 _expansiondata[4]; -}; - -#endif diff --git a/beos/liblayout/MSplitter.h b/beos/liblayout/MSplitter.h deleted file mode 100644 index 411c5d14f..000000000 --- a/beos/liblayout/MSplitter.h +++ /dev/null @@ -1,38 +0,0 @@ - -#ifndef _MSPLITTER_H -#define _MSPLITTER_H - -#include "layout.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MSplitter : public MView, public BView -{ - public: MSplitter(); - MSplitter(bool cosmetic); - MSplitter(BMessage*); - virtual ~MSplitter(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void MouseDown(BPoint); - virtual void Draw(BRect); - virtual void MouseMoved(BPoint, ulong, const BMessage*); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: - float siblingweight; - MView *previoussibling; - MView *nextsibling; - thread_id mousethread; - static long _mousetracker(void *); - void _MouseTracker(void); - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/MStop.h b/beos/liblayout/MStop.h deleted file mode 100644 index b99fc2fe4..000000000 --- a/beos/liblayout/MStop.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _MSTOP_H -#define _MSTOP_H - -#include "MPictureButton.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MStop : public MPictureButton -{ - public: MStop(BHandler*); - MStop(BHandler *id, BMessage*); - MStop(BMessage*); - virtual ~MStop(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual void MakePictures(); -}; -extern const IMPEXPLIBLAYOUT char M_BUTTON_POINTER[]; - -#endif diff --git a/beos/liblayout/MStringView.h b/beos/liblayout/MStringView.h deleted file mode 100644 index 4db74452e..000000000 --- a/beos/liblayout/MStringView.h +++ /dev/null @@ -1,25 +0,0 @@ - -#ifndef _MSTRINGVIEW_H -#define _MSTRINGVIEW_H -#include "layout.h" -#include <StringView.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MStringView : public MView, public BStringView -{ - public: MStringView(const char *label,alignment a=B_ALIGN_LEFT,minimax size=minimax(10,10,65536,65536,1)); - MStringView(BMessage*); - virtual ~MStringView(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); -}; - -#endif diff --git a/beos/liblayout/MTabView.h b/beos/liblayout/MTabView.h deleted file mode 100644 index 04c69ec59..000000000 --- a/beos/liblayout/MTabView.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef _MTABVIEW_H -#define _MTABVIEW_H - -#include <TabView.h> -#include "MGroup.h" - -class IMPEXPLIBLAYOUT MTab: public BTab -{ - public: - MTab(MView *view, const char *name=NULL); - MTab(BMessage *archive); - virtual ~MTab(); -}; - - -class IMPEXPLIBLAYOUT MTabView: public MGroup, public BTabView -{ - public: - MTabView(); - MTabView(BMessage *archive); - virtual void Add(MTab *tab); - virtual void Select(int32 tab); - - virtual void reloadfont(BFont *font[]); - virtual minimax layoutprefs(); - virtual BRect layout(BRect); - - private: - void LayoutCurrentTab(); -}; - -#endif diff --git a/beos/liblayout/MTextControl.h b/beos/liblayout/MTextControl.h deleted file mode 100644 index 46f1a746f..000000000 --- a/beos/liblayout/MTextControl.h +++ /dev/null @@ -1,36 +0,0 @@ - -#ifndef _MTEXTCONTROL_H -#define _MTEXTCONTROL_H -#include "layout.h" -#include "MDividable.h" -#include <TextControl.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MTextControl: - public MView, public MDividable, public BTextControl -{ - public: MTextControl(char *label, char *text); - MTextControl(char *label, char *text, BMessage *mes); - MTextControl(BMessage*); - virtual ~MTextControl(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual void SetLabel(const char *); - virtual float LabelWidth(); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void reloadfont(BFont *font[]); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - - private: float lastheight; - - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/MTextView.h b/beos/liblayout/MTextView.h deleted file mode 100644 index 512a85cd1..000000000 --- a/beos/liblayout/MTextView.h +++ /dev/null @@ -1,31 +0,0 @@ - -#ifndef _MTEXTVIEW_H -#define _MTEXTVIEW_H -#include "layout.h" -#include <TextView.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MTextView : public MView, public BTextView -{ - public: MTextView(minimax size=0); - MTextView(BMessage*); - virtual ~MTextView(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void MessageReceived(BMessage *mes); - - private: void initobject(); - static long AsyncSetTextRect(void *arg); - thread_id resizer; - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/MVolume.h b/beos/liblayout/MVolume.h deleted file mode 100644 index 9d70b7955..000000000 --- a/beos/liblayout/MVolume.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _MVOLUME_H -#define _MVOLUME_H - -#include "layout.h" -#include <Control.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MVolume : public MView, public BControl -{ - public: MVolume(BHandler*); - MVolume(BMessage*); - virtual ~MVolume(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual minimax layoutprefs(); - BRect layout(BRect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void Draw(BRect); - virtual void DrawVolume(void); - float Volume(); - void SetVolume(float vol); - virtual void MouseDown(BPoint); - virtual void KeyDown(const char *bytes, int32 numbytes); - - private: float volume; - BHandler *target; - BPoint lastvoldot; - BPoint clickpoint; - thread_id mousethread; - bool ispressed; - // moved into private area 21-6-98 - static long _mousetracker(void *arg); - void _MouseTracker(); - // added 21-6-98 - void _PUMouseTracker(); -}; - -inline float MVolume::Volume() -{ - return volume; -} - -#endif diff --git a/beos/liblayout/MWindow.h b/beos/liblayout/MWindow.h deleted file mode 100644 index 6118f87bc..000000000 --- a/beos/liblayout/MWindow.h +++ /dev/null @@ -1,62 +0,0 @@ - -#ifndef _MWINDOW_H -#define _MWINDOW_H - -#include "layout.h" -#include <Window.h> - -class BPopUpMenu; - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT MWindow : public BWindow -{ - public: - ulong flags; - - MWindow(BRect r,const char *name,window_type type,uint32 flags, uint32 workspaces=B_CURRENT_WORKSPACE); - MWindow(BRect r,const char *name,window_look look, window_feel feel,uint32 flags, uint32 workspaces=B_CURRENT_WORKSPACE); - MWindow(BMessage*); - virtual ~MWindow(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - virtual const BFont *getfont(fontspec font); - - virtual void MessageReceived(BMessage *message); - virtual void Show(); - virtual void RecalcSize(); - virtual void FrameResized(float width, float height); - - virtual status_t GetSupportedSuites(BMessage *message); - virtual BHandler *ResolveSpecifier(BMessage *message, int32 index, BMessage *specifier, int32 command, const char *property); - virtual void ScreenChanged(BRect frame, color_space mode); - virtual void WorkspaceActivated(int32 workspace, bool active); - - void StartDragging(); - static long _mousetracker(void *arg); - void _MouseTracker(); - - private: - virtual void _expansionmwindow1(); - virtual void _expansionmwindow2(); - virtual void _expansionmwindow3(); - - void initobject(); - BFont **fontlist; - BRect lastrect; - BPopUpMenu *pop; - thread_id mousethread; - BPoint dragpoint; - - uint32 _expansiondata[1]; -}; - -enum { - M_WIN_AUTORESIZE =0x00000100, - M_WIN_ESCAPETOCLOSE=0x00000200 -}; - -#endif // MWINDOW_H diff --git a/beos/liblayout/PropGadget.h b/beos/liblayout/PropGadget.h deleted file mode 100644 index 81a3f1f9b..000000000 --- a/beos/liblayout/PropGadget.h +++ /dev/null @@ -1,75 +0,0 @@ - -#ifndef _PROPGADGET -#define _PROPGADGET -#include "layout.h" -#include <Control.h> -#include <Bitmap.h> - -class IMPEXPLIBLAYOUT PropGadget; - -typedef void (*propgadget_hook)(PropGadget*, void*, double, double); - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class PropGadget : public MView, public BControl -{ - public: PropGadget(double xprop, double xval, double yprop, double yval, - BBitmap *knobimage=NULL, - propgadget_hook=NULL, - void *callbackarg=NULL, - long extraspacing=0); - PropGadget(BMessage*); - virtual ~PropGadget(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - - BBitmap* Pknob; - - virtual void Draw(BRect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void MouseDown(BPoint); - - void SetProportion(double, double); - void SetProportionNoDraw(double,double); - virtual void SetValues(double,double); - void SetValuesNoDraw(double,double); - virtual void FrameResized(float,float); - void ReDraw(); - inline double Hval() {return hval;} - inline double Vval() {return 1.0-vval;} - - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void setcolor(rgb_color col, bool deep=false); - virtual void DrawContainer(BRect); - virtual void DrawKnob(BRect); - virtual void KeyDown(const char *bytes, int32 numbytes); - bool IsBusy(); - - private: virtual void _expansionpropgadget1(); - virtual void _expansionpropgadget2(); - - thread_id mousethread; - BPoint clickpoint; - BRect lastknobrect; - bool _isbusy; - bool vertical; - bool horizontal; - - double hprop; - double hval; - double vprop; - double vval; - void (*callback)(PropGadget*,void*,double,double); - void *callbackarg; - long borderspacing; - - static long _mousetracker(void *arg); - void _MouseTracker(); - - uint32 _expansiondata[2]; -}; -#endif diff --git a/beos/liblayout/Space.h b/beos/liblayout/Space.h deleted file mode 100644 index c49f6fbd2..000000000 --- a/beos/liblayout/Space.h +++ /dev/null @@ -1,22 +0,0 @@ - -#ifndef _SPACE_H -#define _SPACE_H -#include "layout.h" -#include "View.h" - -#if __POWERPC__ -#pragma simple_class_byval off -#endif -class IMPEXPLIBLAYOUT Space : public MView, public BView -{ - public: Space(); - Space(minimax); - Space(BMessage*); - virtual ~Space(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); -}; - -#endif diff --git a/beos/liblayout/SpinButton.h b/beos/liblayout/SpinButton.h deleted file mode 100644 index 3bb00db69..000000000 --- a/beos/liblayout/SpinButton.h +++ /dev/null @@ -1,78 +0,0 @@ - -#ifndef _SPINBUTTON_H -#define _SPINBUTTON_H - -#include <View.h> -#include "layout.h" -#include "HGroup.h" -#include "MTextControl.h" - -enum spinmode -{ - SPIN_FLOAT, - SPIN_INTEGER -}; - -class NumberTextView; -class TinyButton; -#if __POWERPC__ -#pragma warn_hidevirtual off -#endif -class IMPEXPLIBLAYOUT SpinButton: public MView, public MDividable, public BControl -{ - public: - SpinButton(const char *label,spinmode mode, BHandler *target=NULL); - virtual ~SpinButton(); - - virtual void reloadfont(BFont *font[]); - virtual minimax layoutprefs(); - virtual BRect layout(BRect); - - virtual float LabelWidth(); - - virtual void AllAttached(); - virtual void DetachedFromWindow(); - virtual void Draw(BRect); - virtual void MessageReceived(BMessage *mes); - virtual void SetEnabled(bool); - - double Increment(); - double Decrement(); - double StepSize(); - void SetStepSize(double step); - - virtual void SetValue(int32 v); - virtual void SetValue(double v); - double Value(); - double Maximum(); - void SetMaximum(double max); - double Minimum(); - void SetMinimum(double min); - const char * Format() const; - void SetFormat(const char *f); - - private: - spinmode mode; - ulong height; - TinyButton *tb1,*tb2; - NumberTextView *tv; - long lx,ly; - void NotifyWorld(BMessage *mes); - BHandler *target; - uint32 _expansiondata[4]; -}; - -enum -{ - M_SPIN_UP='!!up', - M_SPIN_DOWN='!!dn', - M_SPIN_TICK='!spn' -}; - -extern const IMPEXPLIBLAYOUT char M_RELEASE[]; - -#if __POWERPC__ -#pragma warn_hidevirtual on -#endif - -#endif diff --git a/beos/liblayout/TabGroup.h b/beos/liblayout/TabGroup.h deleted file mode 100644 index 64a2cf9cc..000000000 --- a/beos/liblayout/TabGroup.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef _TABGROUP_H -#define _TABGROUP_H - -#include "MGroup.h" -#include <Control.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT TabGroup : public MGroup, public BControl -{ - public: TabGroup(minimax mpm,char *arg=0, ...); - TabGroup(char *arg=0, ...); - TabGroup(BMessage*); - virtual ~TabGroup(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void AttachedToWindow(); - virtual void MouseDown(BPoint point); - virtual void Draw(BRect clip); - virtual void KeyDown(const char *bytes, int32 numbytes); - virtual void ActivateTab(int); - int32 ActiveTab(); - virtual void DetachedFromWindow(); - virtual void SetEnabled(bool enabled); - void SetExtraSpacing(float spacing); - float ExtraSpacing(); - - private: virtual void _expansiontabgroup1(); - virtual void _expansiontabgroup2(); - - int numkids; - int activekid; - float tabheight; - float biggesttabmin; - float fontdescent; - float extraspacing; - - uint32 _expansiondata[1]; -}; - -#endif diff --git a/beos/liblayout/VGroup.h b/beos/liblayout/VGroup.h deleted file mode 100644 index 56be070df..000000000 --- a/beos/liblayout/VGroup.h +++ /dev/null @@ -1,41 +0,0 @@ - -#ifndef _VGROUP_H -#define _VGROUP_H -#include "MGroup.h" -#include <View.h> - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -class IMPEXPLIBLAYOUT VGroup : public MGroup, public BView -{ - public: VGroup(minimax mpm,MView *kid=0, ...); - VGroup(MView *kid=0, ...); - VGroup(BMessage*); - virtual ~VGroup(); - virtual long Archive(BMessage *archive, bool deep=true) const; - static BArchivable *Instantiate(BMessage *archive); - virtual minimax layoutprefs(); - virtual BRect layout(BRect rect); - virtual void AttachedToWindow(); - virtual void DetachedFromWindow(); - virtual void MouseDown(BPoint); - - private: virtual void _expansionvgroup1(); - virtual void _expansionvgroup2(); - virtual void _expansionvgroup3(); - - static int cmpkids(const void* v1,const void *v2); - int *size; - float totalweight; - int numkids; - sortstruct *childorder; - MView **mkid; - float totalminy,totalmaxy; - BRect *lastrect; - - uint32 _expansiondata[2]; -}; - -#endif diff --git a/beos/liblayout/layout-all.h b/beos/liblayout/layout-all.h deleted file mode 100644 index b2e78df10..000000000 --- a/beos/liblayout/layout-all.h +++ /dev/null @@ -1,35 +0,0 @@ -#include "MApplication.h" -#include "MWindow.h" -#include "HGroup.h" -#include "VGroup.h" -#include "LayeredGroup.h" -#include "TabGroup.h" -#include "MBViewWrapper.h" -#include "MBorder.h" -#include "MButton.h" -#include "MCheckBox.h" -#include "MDividable.h" -#include "MDragBar.h" -#include "MEject.h" -#include "MFFWD.h" -#include "MListView.h" -#include "MMenuBar.h" -#include "MOutlineListView.h" -#include "MPictureButton.h" -#include "MPlayBW.h" -#include "MPlayFW.h" -#include "MPopup.h" -#include "MProgressBar.h" -#include "MRadioGroup.h" -#include "MRew.h" -#include "MScrollView.h" -#include "MSlider.h" -#include "MSplitter.h" -#include "MStop.h" -#include "MStringView.h" -#include "MTextControl.h" -#include "MTextView.h" -#include "MVolume.h" -#include "PropGadget.h" -#include "Space.h" -#include "SpinButton.h" diff --git a/beos/liblayout/layout.h b/beos/liblayout/layout.h deleted file mode 100644 index 772b251db..000000000 --- a/beos/liblayout/layout.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - - Lowest-level classes in liblayout - - minimax, used to store information about minimum size, maximum size, and weigth of objects - - MView, a class that knows how to layout itself - -*/ - -#ifndef _LAYOUT_H -#define _LAYOUT_H - -#if __POWERPC__ -#pragma simple_class_byval off -#endif - -#include <BeBuild.h> - -#if !defined(IMPEXPLIBLAYOUT) && defined(BUILDING_LIBLAYOUT) -#define IMPEXPLIBLAYOUT _EXPORT -#else -#define IMPEXPLIBLAYOUT _IMPORT -#endif - -#include <Rect.h> -#include <GraphicsDefs.h> -#include <stdlib.h> - -class BMessage; -class BFont; - -// use macro to make code slightly more readable -#define MVPTR(x) dynamic_cast<MView*>(x) - -enum fontspec -{ - M_PLAIN_FONT=0, - M_BOLD_FONT, - M_FIXED_FONT -}; - - -// this structure is exported from liblayout, and contains the version number -struct LAYOUT_VERSION_INFO -{ - uchar major; - uchar minor; - ushort patchlevel; -}; - -extern "C" LAYOUT_VERSION_INFO IMPEXPLIBLAYOUT LIBLAYOUT_VERSION; - - -class IMPEXPLIBLAYOUT minimax // Order now, by dialing the number on your screen! -{ -struct xypair { float x,y;}; - - public: xypair mini; - xypair maxi; - float weight; - - minimax(int minx=0,int miny=0, - int maxx=10000,int maxy=10000, - float wght=1.0); -}; - -class IMPEXPLIBLAYOUT MView -{ - protected: rgb_color FILL_COLOR; - rgb_color LOW_COLOR; - rgb_color HI_COLOR; - - // helper functions for archiving/unarchiving the MView - // part of MView hybrids - status_t archive(BMessage *); - status_t unarchive(BMessage *); - - public: minimax mpm; // currently active minimax (calculated from ct_mpm and environmental constraints) - minimax ct_mpm; // size specified at construction-time - ulong flags; // various flags - // upper 16 bits are reserve for liblayout-use - // bits 8-15 are reserved for per-class liblayout-use - // bits 0-7 are available - - MView(); - virtual ~MView(); - virtual minimax layoutprefs()=0; - virtual BRect layout(BRect rect)=0; - - // reload the font from one of the fonts in the font-array - virtual void reloadfont(BFont *font[]); - // get a BFont with the required fontspec - const BFont *getfont(fontspec font); - - // set the color of the MView - virtual void setcolor(rgb_color col, bool deep=true); - // this one calls the above function - void setcolor(uchar red, uchar green, uchar blue, bool deep=true); - rgb_color getcolor(); // get the base color (what is set through setcolor() ) - - private: - virtual void _expansionmview1(); - virtual void _expansionmview2(); - virtual void _expansionmview3(); - virtual void _expansionmview4(); - - uint32 _expansiondata[4]; -}; - - -// constants used in messaging all start with a '!' -#define M_POPUP_SELECTED '!pop' -#define M_CHECKBOX_SELECTED '!chk' -#define M_BUTTON_SELECTED '!but' -#define M_RADIO_SELECTED '!rad' -#define M_PLAYBW_SELECTED '!ylp' -#define M_PLAYFW_SELECTED '!ply' -#define M_FFWD_SELECTED '!fwd' -#define M_REW_SELECTED '!rwd' -#define M_STOP_SELECTED '!stp' -#define M_VOLUME_CHANGED '!vol' -#define M_EJECT_SELECTED '!ejt' -#define M_PREV_SELECTED '!prv' -#define M_NEXT_SELECTED '!nxt' -#define M_PROGRESSBAR_CLICKED '!pbc' -#define M_PROGRESSBAR_DRAGGED '!pbd' -#define M_PROGRESSBAR_RELEASED '!pbr' -#define M_ACTIVATE_LAYER '!lyr' - -// when sent to a window, it recalculates the entire window -#define M_RECALCULATE_SIZE '!rsz' - -// font-change message is understood by MWindow and MApplication, -// but is not generated by liblayout. -#define M_FONT_CHANGED '!FNT' - -extern IMPEXPLIBLAYOUT rgb_color M_FILL_COLOR; -extern IMPEXPLIBLAYOUT rgb_color M_LOW_COLOR; -extern IMPEXPLIBLAYOUT rgb_color M_HI_COLOR; -extern IMPEXPLIBLAYOUT rgb_color BLACK_COLOR; -extern IMPEXPLIBLAYOUT rgb_color WHITE_COLOR; - -void IMPEXPLIBLAYOUT SetDefaultColors(uchar red, uchar green, uchar blue); -void IMPEXPLIBLAYOUT SetDefaultColors(rgb_color cs); - -// misc flags -// note that not all controls responds to all flags - -enum{ - M_REPORT_IMMEDIATE= 0x00010000, // report first click on control - M_REPORT_REPEAT = 0x00020000, // report if control is clicked and held - M_REPORT_RELEASE= 0x00040000, // report release of button over control - M_REPORT_RELEASE_ALWAYS= 0x00080000, // always report release of button - M_REPORT_MASK= 0x000f0000, // all of the above - - // mostly for internal use, therefore not documented (yet) - M_USE_CALCULATED_MINX= 0x00100000, - M_USE_CALCULATED_MINY= 0x00200000, - M_USE_CALCULATED_MAXX= 0x00400000, - M_USE_CALCULATED_MAXY= 0x00800000, - M_NO_X_LEFTOVERS= 0x01000000, // don't add "leftover" space to this object - M_NO_Y_LEFTOVERS= 0x02000000, // don't add "leftover" space to this object - M_NO_COLOR_CHANGES= 0x20000000, // don't listen to color-drop messages - M_NO_FONT_CHANGES= 0x40000000, // don't listen to font-change messages - M_USE_FULL_SIZE = (int) 0x80000000 // don't respect max-size (set for grouping classes) -}; - - -#endif diff --git a/configure b/configure new file mode 100755 index 000000000..d0c292873 --- /dev/null +++ b/configure @@ -0,0 +1,90 @@ +#! /bin/sh + +CC="gcc" +CXX="g++" +CCFLAGS="$CCFLAGS -Wall -g" +OPTIM="$OPTIM -O3 -funroll-loops" + +# System-specific flags +SYSTEM=`uname -s` +case $SYSTEM in + BeOS) + CCFLAGS="$CCFLAGS -Wno-multichar" + DEFINES="$DEFINES SYS_BEOS" + LINKLIBS="$LINKLIBS -lbe -ltracker" + + RELEASE=`uname -r` + case $RELEASE in + 6.0|5.0.4) # Zeta or R5 / BONE beta 7 + SYSTEM="$SYSTEM / BONE" + LINKLIBS="$LINKLIBS -lbind -lsocket" + ;; + 5.0*) # R5 / net_server + SYSTEM="$SYSTEM / net_server" + DEFINES="$DEFINES BEOS_NETSERVER" + LINKLIBS="$LINKLIBS -lnet" + ;; + *) + echo "Unsupported BeOS version" + exit 1 ;; + esac + ;; + + Darwin) + DEFINES="$DEFINES SYS_DARWIN" + LINKLIBS="$LINKLIBS -lpthread" + ;; + + FreeBSD) + DEFINES="$DEFINES SYS_FREEBSD" + LINKLIBS="$LINKLIBS -pthread" + ;; + + NetBSD) + DEFINES="$DEFINES SYS_NETBSD" + LINKLIBS="$LINKLIBS -lpthread" + ;; + + Linux) + DEFINES="$DEFINES SYS_LINUX" + LINKLIBS="$LINKLIBS -lpthread" + ;; + + *) + echo "Unsupported operating system" + exit 1 ;; +esac +echo "System: $SYSTEM" + +# Check for endianness (we need to define WORDS_BIGENDIAN for libdvdread) +cat > testconf.c << EOF +int main() +{ + int i = 1; + return *( (char *) &i ); +} +EOF +if ( cc -o testconf testconf.c && ./testconf ) > /dev/null 2>&1 +then + echo "Endian: big" + DEFINES="$DEFINES WORDS_BIGENDIAN" +else + echo "Endian: little" +fi +rm -f testconf.c testconf + +# Generate config.jam +rm -f config.jam +cat << EOF > config.jam +CC = $CC ; +C++ = $CXX ; +LINK = $CXX ; +CCFLAGS = $CCFLAGS ; +C++FLAGS = $CCFLAGS ; +OPTIM = $OPTIM ; +DEFINES = $DEFINES ; +LINKLIBS = $LINKLIBS ; +EOF + +echo +echo "To build HandBrake, run 'jam'." diff --git a/contrib/Jamfile b/contrib/Jamfile new file mode 100644 index 000000000..5bdf71bfa --- /dev/null +++ b/contrib/Jamfile @@ -0,0 +1,270 @@ +SubDir TOP contrib ; + +# Use curl on Mac OS X since it's always installed, and assume wget +# is installed for all other systems +if $(OS) = MACOSX +{ + WGET = curl -o ; +} +else +{ + WGET = wget -O ; +} + +# Wget rule: downloads $(<) from the link in $(>) +rule Wget +{ + Depends $(<) : $(>) ; +} +actions Wget +{ + $(RM) $(<) && + $(WGET) $(<) `cat $(>)` && + ( touch $(<) || true ) +} + +# liba52 +rule LibA52 +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibA52 +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf a52dec && tar xzf a52dec.tar.gz && cd a52dec && + ./configure --prefix=$CONTRIB && make && make install && + strip -S $CONTRIB/lib/liba52.a +} +Wget $(SUBDIR)/a52dec.tar.gz : $(SUBDIR)/version_a52dec.txt ; +LibA52 $(SUBDIR)/lib/liba52.a : $(SUBDIR)/a52dec.tar.gz ; + +# libavcodec +rule LibAvCodec +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibAvCodec +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf ffmpeg && tar xzf ffmpeg.tar.gz && cd ffmpeg && + ./configure --prefix=$CONTRIB --enable-gpl && + make -C libavcodec && make -C libavutil && + make -C libavcodec installlib && make -C libavutil installlib && + strip -S $CONTRIB/lib/libavcodec.a +} +Wget $(SUBDIR)/ffmpeg.tar.gz : $(SUBDIR)/version_ffmpeg.txt ; +LibAvCodec $(SUBDIR)/lib/libavcodec.a : $(SUBDIR)/ffmpeg.tar.gz ; + +rule LibAvUtil +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibAvUtil +{ + strip -S $(<) +} +LibAvUtil $(SUBDIR)/lib/libavutil.a : $(SUBDIR)/lib/libavcodec.a ; + +# libdvdcss +# We need libdvdcss.so for libdvdread's configure to work... +rule LibDvdCss +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibDvdCss +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf libdvdcss && tar xzf libdvdcss.tar.gz && cd libdvdcss && + ./configure --prefix=$CONTRIB && make && make install && + strip -S $CONTRIB/lib/libdvdcss.a +} +Wget $(SUBDIR)/libdvdcss.tar.gz : $(SUBDIR)/version_libdvdcss.txt ; +LibDvdCss $(SUBDIR)/lib/libdvdcss.a : $(SUBDIR)/libdvdcss.tar.gz ; + +# libdvdread +rule LibDvdRead +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibDvdRead +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf libdvdread && tar xzf libdvdread.tar.gz && cd libdvdread && + ./configure --prefix=$CONTRIB --disable-shared --with-libdvdcss=$CONTRIB && + make && make install && + strip -S $CONTRIB/lib/libdvdread.a +} +Wget $(SUBDIR)/libdvdread.tar.gz : $(SUBDIR)/version_libdvdread.txt ; +LibDvdRead $(SUBDIR)/lib/libdvdread.a : $(SUBDIR)/libdvdread.tar.gz ; + +# libfaac +rule LibFaac +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibFaac +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf faac && tar xzf faac.tar.gz && cd faac && + ./configure --prefix=$CONTRIB --disable-shared && + make && make install && + strip -S $CONTRIB/lib/libfaac.a +} +Wget $(SUBDIR)/faac.tar.gz : $(SUBDIR)/version_faac.txt ; +LibFaac $(SUBDIR)/lib/libfaac.a : $(SUBDIR)/faac.tar.gz ; + +# libmp3lame +rule LibMp3Lame +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibMp3Lame +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf lame && tar xzf lame.tar.gz && cd lame && + ./configure --prefix=$CONTRIB --disable-shared && + make && make install && + strip -S $CONTRIB/lib/libmp3lame.a +} +Wget $(SUBDIR)/lame.tar.gz : $(SUBDIR)/version_lame.txt ; +LibMp3Lame $(SUBDIR)/lib/libmp3lame.a : $(SUBDIR)/lame.tar.gz ; + +# libmp4v2 +rule LibMp4v2 +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibMp4v2 +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf mpeg4ip && tar xzf mpeg4ip.tar.gz && cd mpeg4ip && + ./bootstrap && make -C lib/mp4v2 libmp4v2.la && + cp lib/mp4v2/.libs/libmp4v2.a $CONTRIB/lib && + cp mpeg4ip_config.h include/mpeg4ip.h include/mpeg4ip_version.h \ + include/mpeg4ip_win32.h lib/mp4v2/mp4.h $CONTRIB/include && + strip -S $CONTRIB/lib/libmp4v2.a +} +Wget $(SUBDIR)/mpeg4ip.tar.gz : $(SUBDIR)/version_mpeg4ip.txt ; +LibMp4v2 $(SUBDIR)/lib/libmp4v2.a : $(SUBDIR)/mpeg4ip.tar.gz ; + +# libmpeg2 +rule LibMpeg2 +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibMpeg2 +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf mpeg2dec && tar xzf mpeg2dec.tar.gz && cd mpeg2dec && + ./configure --prefix=$CONTRIB --disable-shared && + make && make install && + strip -S $CONTRIB/lib/libmpeg2.a +} +Wget $(SUBDIR)/mpeg2dec.tar.gz : $(SUBDIR)/version_mpeg2dec.txt ; +LibMpeg2 $(SUBDIR)/lib/libmpeg2.a : $(SUBDIR)/mpeg2dec.tar.gz ; + +# libogg +rule LibOgg +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibOgg +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf libogg && tar xzf libogg.tar.gz && cd libogg && + ./configure --prefix=$CONTRIB --disable-shared && + make && make install && + strip -S $CONTRIB/lib/libogg.a +} +Wget $(SUBDIR)/libogg.tar.gz : $(SUBDIR)/version_libogg.txt ; +LibOgg $(SUBDIR)/lib/libogg.a : $(SUBDIR)/libogg.tar.gz ; + +# libsamplerate +rule LibSampleRate +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibSampleRate +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf libsamplerate && tar xzf libsamplerate.tar.gz && cd libsamplerate && + ./configure --prefix=$CONTRIB --disable-shared && + make && make install && + strip -S $CONTRIB/lib/libsamplerate.a +} +Wget $(SUBDIR)/libsamplerate.tar.gz : $(SUBDIR)/version_libsamplerate.txt ; +LibSampleRate $(SUBDIR)/lib/libsamplerate.a : $(SUBDIR)/libsamplerate.tar.gz ; + +# libvorbis +rule LibVorbis +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibVorbis +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf libvorbis && tar xzf libvorbis.tar.gz && cd libvorbis && + ./configure --prefix=$CONTRIB --with-ogg=$CONTRIB --disable-shared && + make && make install && + strip -S $CONTRIB/lib/libvorbis.a +} +Wget $(SUBDIR)/libvorbis.tar.gz : $(SUBDIR)/version_libvorbis.txt ; +LibVorbis $(SUBDIR)/lib/libvorbis.a : $(SUBDIR)/libvorbis.tar.gz ; + +rule LibVorbisEnc +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibVorbisEnc +{ + strip -S $(<) +} +LibVorbisEnc $(SUBDIR)/lib/libvorbisenc.a : $(SUBDIR)/lib/libvorbis.a ; + +# libx264 +rule LibX264 +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibX264 +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf x264 && tar xzf x264.tar.gz && cd x264 && + ./configure --prefix=$CONTRIB --enable-pthread && make && + make install && + strip -S $CONTRIB/lib/libx264.a +} +Wget $(SUBDIR)/x264.tar.gz : $(SUBDIR)/version_x264.txt ; +LibX264 $(SUBDIR)/lib/libx264.a : $(SUBDIR)/x264.tar.gz ; + +# libxvidcore +rule LibXvidCore +{ + Depends $(<) : $(>) ; + Depends lib : $(<) ; +} +actions LibXvidCore +{ + cd `dirname $(>)` && CONTRIB=`pwd` && + rm -rf xvidcore && tar xzf xvidcore.tar.gz && + cd xvidcore/build/generic/ && ./configure && make libxvidcore.a && + cp ./=build/libxvidcore.a $CONTRIB/lib/ && + cp ../../src/xvid.h $CONTRIB/include/ && + strip -S $CONTRIB/lib/libxvidcore.a +} +Wget $(SUBDIR)/xvidcore.tar.gz : $(SUBDIR)/version_xvidcore.txt ; +LibXvidCore $(SUBDIR)/lib/libxvidcore.a : $(SUBDIR)/xvidcore.tar.gz ; diff --git a/contrib/version_a52dec.txt b/contrib/version_a52dec.txt new file mode 100644 index 000000000..86617fd36 --- /dev/null +++ b/contrib/version_a52dec.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/a52dec-0.7.4.tar.gz diff --git a/contrib/version_faac.txt b/contrib/version_faac.txt new file mode 100644 index 000000000..e3466666b --- /dev/null +++ b/contrib/version_faac.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/faac-1.24.tar.gz diff --git a/contrib/version_ffmpeg.txt b/contrib/version_ffmpeg.txt new file mode 100644 index 000000000..b8a5c6f6e --- /dev/null +++ b/contrib/version_ffmpeg.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/ffmpeg-20051007.tar.gz diff --git a/contrib/version_lame.txt b/contrib/version_lame.txt new file mode 100644 index 000000000..b4bb63c81 --- /dev/null +++ b/contrib/version_lame.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/lame-3.96.1.tar.gz diff --git a/contrib/version_libdvdcss.txt b/contrib/version_libdvdcss.txt new file mode 100644 index 000000000..81d1ef157 --- /dev/null +++ b/contrib/version_libdvdcss.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/libdvdcss-1.2.9.tar.gz diff --git a/contrib/version_libdvdread.txt b/contrib/version_libdvdread.txt new file mode 100644 index 000000000..b7be38fd7 --- /dev/null +++ b/contrib/version_libdvdread.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/libdvdread-20050928.tar.gz diff --git a/contrib/version_libogg.txt b/contrib/version_libogg.txt new file mode 100644 index 000000000..57daaf702 --- /dev/null +++ b/contrib/version_libogg.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/libogg-1.1.2.tar.gz diff --git a/contrib/version_libsamplerate.txt b/contrib/version_libsamplerate.txt new file mode 100644 index 000000000..a0f5b3804 --- /dev/null +++ b/contrib/version_libsamplerate.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/libsamplerate-0.1.2.tar.gz diff --git a/contrib/version_libvorbis.txt b/contrib/version_libvorbis.txt new file mode 100644 index 000000000..db3f67caf --- /dev/null +++ b/contrib/version_libvorbis.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/libvorbis-1.1.1.tar.gz diff --git a/contrib/version_mpeg2dec.txt b/contrib/version_mpeg2dec.txt new file mode 100644 index 000000000..87a73c92a --- /dev/null +++ b/contrib/version_mpeg2dec.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/mpeg2dec-20051019.tar.gz diff --git a/contrib/version_mpeg4ip.txt b/contrib/version_mpeg4ip.txt new file mode 100644 index 000000000..f60e5972a --- /dev/null +++ b/contrib/version_mpeg4ip.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/mpeg4ip-1.3.tar.gz diff --git a/contrib/version_x264.txt b/contrib/version_x264.txt new file mode 100644 index 000000000..560f081ab --- /dev/null +++ b/contrib/version_x264.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/x264-r305.tar.gz diff --git a/contrib/version_xvidcore.txt b/contrib/version_xvidcore.txt new file mode 100644 index 000000000..573cd3c8a --- /dev/null +++ b/contrib/version_xvidcore.txt @@ -0,0 +1 @@ +http://download.m0k.org/handbrake/contrib/xvidcore-1.1.0-beta2.tar.gz diff --git a/core/Ac3Dec.c b/core/Ac3Dec.c deleted file mode 100644 index ef805588c..000000000 --- a/core/Ac3Dec.c +++ /dev/null @@ -1,157 +0,0 @@ -/* $Id: Ac3Dec.c,v 1.17 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* liba52 */ -#include "a52dec/a52.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBAudio * audio; - - /* liba52 stuff */ - a52_state_t * state; - int inFlags; - int outFlags; - float sampleLevel; - - /* Buffers */ - uint8_t ac3Frame[3840]; /* Max size of a A52 frame */ - int hasSync; - int nextFrameSize; -}; - -/* Local prototypes */ -static int Ac3DecWork( HBWork * ); - -HBWork * HBAc3DecInit( HBHandle * handle, HBAudio * audio ) -{ - HBWork * w; - if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) - { - HBLog( "HBAc3DecInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "Ac3Dec" ); - w->work = Ac3DecWork; - - w->handle = handle; - w->audio = audio; - - /* Init liba52 */ - w->state = a52_init( 0 ); - - /* Let it do the downmixing */ - w->outFlags = A52_STEREO; - - /* 16 bits samples */ - w->sampleLevel = 32768.0; - - return w; -} - -void HBAc3DecClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - a52_free( w->state ); - free( w->name ); - free( w ); - - *_w = NULL; -} - -static int Ac3DecWork( HBWork * w ) -{ - HBAudio * audio = w->audio; - - float position; - - if( HBFifoIsHalfFull( audio->rawFifo ) ) - { - return 0; - } - - /* Get a frame header (7 bytes) */ - if( !w->hasSync ) - { - if( !HBFifoGetBytes( audio->inFifo, w->ac3Frame, 7, - &position ) ) - { - return 0; - } - - /* Check the header */ - w->nextFrameSize = a52_syncinfo( w->ac3Frame, &w->inFlags, - &audio->inSampleRate, - &audio->inBitrate ); - - if( !w->nextFrameSize ) - { - HBLog( "HBAc3Dec: a52_syncinfo() failed" ); - HBErrorOccured( w->handle, HB_ERROR_A52_SYNC ); - return 0; - } - - w->hasSync = 1; - } - - /* Get the whole frame */ - if( w->hasSync ) - { - sample_t * samples; - HBBuffer * rawBuffer; - int i; - - if( !HBFifoGetBytes( audio->inFifo, w->ac3Frame + 7, - w->nextFrameSize - 7, &position ) ) - { - return 0; - } - - w->hasSync = 0; - - /* Feed liba52 */ - a52_frame( w->state, w->ac3Frame, &w->outFlags, - &w->sampleLevel, 0 ); - - /* 6 blocks per frame, 256 samples per block, 2 channels */ - rawBuffer = HBBufferInit( 3072 * sizeof( float ) ); - rawBuffer->position = position; - - for( i = 0; i < 6; i++ ) - { - int j; - - /* Decode a block */ - a52_block( w->state ); - - /* Get a pointer to the float samples */ - samples = a52_samples( w->state ); - - /* Interleave samples */ - for( j = 0; j < 256; j++ ) - { - rawBuffer->dataf[512*i+2*j] = samples[j]; - rawBuffer->dataf[512*i+2*j+1] = samples[256+j]; - } - } - - /* Send decoded data to the resampler */ - if( !HBFifoPush( audio->rawFifo, &rawBuffer ) ) - { - HBLog( "HBAc3Dec: HBFifoPush failed" ); - } - } - - return 1; -} - diff --git a/core/AviMux.c b/core/AviMux.c deleted file mode 100644 index c0209dd49..000000000 --- a/core/AviMux.c +++ /dev/null @@ -1,559 +0,0 @@ -/* $Id: AviMux.c,v 1.24 2004/05/12 18:02:35 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#define AVIF_HASINDEX 0x10 -#define AVIIF_KEYFRAME 0x10 -#define FOURCC(a) ((a[3]<<24)|(a[2]<<16)|(a[1]<<8)|a[0]) - -/* Structures definitions */ -typedef struct __attribute__((__packed__)) -{ - uint32_t FourCC; - uint32_t BytesCount; - uint32_t MicroSecPerFrame; - uint32_t MaxBytesPerSec; - uint32_t PaddingGranularity; - uint32_t Flags; - uint32_t TotalFrames; - uint32_t InitialFrames; - uint32_t Streams; - uint32_t SuggestedBufferSize; - uint32_t Width; - uint32_t Height; - uint32_t Reserved[4]; - -} HBAviMainHeader; - -typedef struct __attribute__((__packed__)) -{ - uint32_t FourCC; - uint32_t BytesCount; - uint32_t Type; - uint32_t Handler; - uint32_t Flags; - uint16_t Priority; - uint16_t Language; - uint32_t InitialFrames; - uint32_t Scale; - uint32_t Rate; - uint32_t Start; - uint32_t Length; - uint32_t SuggestedBufferSize; - uint32_t Quality; - uint32_t SampleSize; - int16_t Left; - int16_t Top; - int16_t Right; - int16_t Bottom; - -} HBAviStreamHeader; - -typedef struct __attribute__((__packed__)) -{ - uint32_t FourCC; - uint32_t BytesCount; - uint32_t Size; - uint32_t Width; - uint32_t Height; - uint16_t Planes; - uint16_t BitCount; - uint32_t Compression; - uint32_t SizeImage; - uint32_t XPelsPerMeter; - uint32_t YPelsPerMeter; - uint32_t ClrUsed; - uint32_t ClrImportant; - -} HBBitmapInfo; - -typedef struct __attribute__((__packed__)) -{ - uint32_t FourCC; - uint32_t BytesCount; - uint16_t FormatTag; - uint16_t Channels; - uint32_t SamplesPerSec; - uint32_t AvgBytesPerSec; - uint16_t BlockAlign; - uint16_t BitsPerSample; - uint16_t Size; - - /* mp3 specific */ - uint16_t Id; - uint32_t Flags; - uint16_t BlockSize; - uint16_t FramesPerBlock; - uint16_t CodecDelay; - -} HBWaveFormatEx; - -struct HBMux -{ - HB_MUX_COMMON_MEMBERS - - HBHandle * handle; - HBTitle * title; - - /* Data size in bytes, not including headers */ - unsigned size; - - FILE * file; - HBBuffer * index; -}; - -typedef struct -{ - HBAviMainHeader mainHeader; - HBAviStreamHeader videoHeader; - HBBitmapInfo videoFormat; - -} AviVideoMuxData; - -typedef struct -{ - uint32_t fourCC; - HBAviStreamHeader audioHeader; - HBWaveFormatEx audioFormat; - -} AviAudioMuxData; - -/* Local prototypes */ -static int AviStart( HBMux * ); -static int AviMuxVideo( HBMux *, void *, HBBuffer *); -static int AviMuxAudio( HBMux *, void *, HBBuffer *); -static int AviEnd( HBMux * ); - -static void AddChunk( HBMux *, HBBuffer *, uint32_t, - HBAviStreamHeader * ); -static void AddIndex( HBMux * ); -static void WriteInt8( FILE *, uint8_t ); -static void WriteInt16( FILE *, uint16_t ); -static void WriteInt32( FILE *, uint32_t ); -static void WriteBuffer( FILE *, HBBuffer * ); -static void WriteMainHeader( FILE *, HBAviMainHeader * ); -static void WriteStreamHeader( FILE *, HBAviStreamHeader * ); -static void WriteHBBitmapInfo( FILE *, HBBitmapInfo * ); -static void WriteHBWaveFormatEx( FILE *, HBWaveFormatEx * ); -static void IndexAddInt32( HBBuffer * buffer, uint32_t ); - -HBMux * HBAviMuxInit( HBHandle * handle, HBTitle * title ) -{ - HBMux * m; - HBAudio * audio; - int i; - - if( !( m = calloc( sizeof( HBMux ), 1 ) ) ) - { - HBLog( "HBAviMux: malloc() failed, gonna crash" ); - return NULL; - } - m->start = AviStart; - m->muxVideo = AviMuxVideo; - m->muxAudio = AviMuxAudio; - m->end = AviEnd; - m->handle = handle; - m->title = title; - - m->file = NULL; - m->index = HBBufferInit( 1024 * 1024 ); - m->index->size = 0; - - /* Alloc muxer data */ - title->muxData = calloc( sizeof( AviVideoMuxData ), 1 ); - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - audio->muxData = calloc( sizeof( AviAudioMuxData ), 1 ); - } - - return m; -} - -void HBAviMuxClose( HBMux ** _m ) -{ - HBMux * m = *_m; - HBTitle * title = m->title; - HBAudio * audio; - int i; - - /* Free muxer data */ - free( title->muxData ); - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - free( audio->muxData ); - } - - HBBufferClose( &m->index ); - - free( m ); - - *_m = NULL; -} - -#define mh videoMuxData->mainHeader -#define vh videoMuxData->videoHeader -#define vf videoMuxData->videoFormat -#define ah audioMuxData->audioHeader -#define af audioMuxData->audioFormat -static int AviStart( HBMux * m ) -{ - HBTitle * title = m->title; - int audioCount = HBListCount( title->ripAudioList ); - AviVideoMuxData * videoMuxData = (AviVideoMuxData *) title->muxData; - AviAudioMuxData * audioMuxData; - HBAudio * audio; - int hdrlBytes; - int i; - - /* Open destination file */ - HBLog( "HBAviMux: opening %s", title->file ); - if( !( m->file = fopen( title->file, "wb" ) ) ) - { - HBLog( "HBAviMux: fopen() failed" ); - HBErrorOccured( m->handle, HB_ERROR_AVI_WRITE ); - return 1; - } - - /* AVI main header */ - mh.FourCC = FOURCC( "avih" ); - mh.BytesCount = sizeof( HBAviMainHeader ) - 8; - mh.MicroSecPerFrame = (uint64_t) 1000000 * title->rateBase / - title->rate; - mh.Streams = 1 + audioCount; - mh.Width = title->outWidth; - mh.Height = title->outHeight; - - /* Video stream header */ - vh.FourCC = FOURCC( "strh" ); - vh.BytesCount = sizeof( HBAviStreamHeader ) - 8; - vh.Type = FOURCC( "vids" ); - - if( title->codec == HB_CODEC_FFMPEG ) - vh.Handler = FOURCC( "divx" ); - else if( title->codec == HB_CODEC_XVID ) - vh.Handler = FOURCC( "xvid" ); - else if( title->codec == HB_CODEC_X264 ) - vh.Handler = FOURCC( "h264" ); - - vh.Scale = title->rateBase; - vh.Rate = title->rate; - - /* Video stream format */ - vf.FourCC = FOURCC( "strf" ); - vf.BytesCount = sizeof( HBBitmapInfo ) - 8; - vf.Size = sizeof( HBBitmapInfo ) - 8; - vf.Width = title->outWidth; - vf.Height = title->outHeight; - vf.Planes = 1; - vf.BitCount = 24; - if( title->codec == HB_CODEC_FFMPEG ) - vf.Compression = FOURCC( "DX50" ); - else if( title->codec == HB_CODEC_XVID ) - vf.Compression = FOURCC( "XVID" ); - else if( title->codec == HB_CODEC_X264 ) - vf.Compression = FOURCC( "H264" ); - - for( i = 0; i < audioCount; i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - audioMuxData = (AviAudioMuxData *) audio->muxData; - - /* Audio stream header */ - ah.FourCC = FOURCC( "strh" ); - ah.BytesCount = sizeof( HBAviStreamHeader ) - 8; - ah.Type = FOURCC( "auds" ); - ah.InitialFrames = 1; - ah.Scale = 1; - ah.Rate = audio->outBitrate * 1000 / 8; - ah.SampleSize = 1; - ah.Quality = 0xFFFFFFFF; - - /* Audio stream format */ - af.FourCC = FOURCC( "strf" ); - af.BytesCount = sizeof( HBWaveFormatEx ) - 8; - af.FormatTag = 0x55; - af.Channels = 2; - af.SamplesPerSec = audio->outSampleRate; - af.AvgBytesPerSec = audio->outBitrate * 1000 / 8; - af.BlockAlign = 1; - af.Size = 12; - af.Id = 1; - af.Flags = 2; - af.BlockSize = 1152 * af.AvgBytesPerSec / - audio->outSampleRate; - af.FramesPerBlock = 1; - af.CodecDelay = 1393; - } - - hdrlBytes = 4 + sizeof( HBAviMainHeader ) + ( 1 + audioCount ) * - ( 12 + sizeof( HBAviStreamHeader ) ) + sizeof( HBBitmapInfo ) + - audioCount * sizeof( HBWaveFormatEx ); - - /* Here we really start to write into the file */ - - WriteInt32( m->file, FOURCC( "RIFF" ) ); - WriteInt32( m->file, 2040 ); - WriteInt32( m->file, FOURCC( "AVI " ) ); - WriteInt32( m->file, FOURCC( "LIST" ) ); - WriteInt32( m->file, hdrlBytes ); - WriteInt32( m->file, FOURCC( "hdrl" ) ); - WriteMainHeader( m->file, &mh ); - WriteInt32( m->file, FOURCC( "LIST" ) ); - WriteInt32( m->file, 4 + sizeof( HBAviStreamHeader ) + - sizeof( HBBitmapInfo ) ); - WriteInt32( m->file, FOURCC( "strl" ) ); - WriteStreamHeader( m->file, &vh ); - WriteHBBitmapInfo( m->file, &vf ); - - for( i = 0; i < audioCount; i++ ) - { - char fourCC[5]; - - audio = HBListItemAt( title->ripAudioList, i ); - audioMuxData = (AviAudioMuxData *) audio->muxData; - - snprintf( fourCC, 5, "%02dwb", i + 1 ); - audioMuxData->fourCC = FOURCC( fourCC ); - - WriteInt32( m->file, FOURCC( "LIST" ) ); - WriteInt32( m->file, 4 + sizeof( HBAviStreamHeader ) + - sizeof( HBWaveFormatEx ) ); - WriteInt32( m->file, FOURCC( "strl" ) ); - WriteStreamHeader( m->file, &ah ); - WriteHBWaveFormatEx( m->file, &af ); - } - - WriteInt32( m->file, FOURCC( "JUNK" ) ); - WriteInt32( m->file, 2008 - hdrlBytes ); - for( i = 0; i < 2008 - hdrlBytes; i++ ) - { - WriteInt8( m->file, 0 ); - } - WriteInt32( m->file, FOURCC( "LIST" ) ); - WriteInt32( m->file, 4 ); - WriteInt32( m->file, FOURCC( "movi" ) ); - - return 0; -} - -static int AviMuxVideo( HBMux * m, void * _muxData, HBBuffer * buffer ) -{ - AviVideoMuxData * muxData = (AviVideoMuxData *) _muxData; - AddChunk( m, buffer, FOURCC( "00dc" ), &muxData->videoHeader ); - return 0; -} - -static int AviMuxAudio( HBMux * m, void * _muxData, HBBuffer * buffer ) -{ - AviAudioMuxData * muxData = (AviAudioMuxData *) _muxData; - AddChunk( m, buffer, muxData->fourCC, &muxData->audioHeader ); - return 0; -} - -static int AviEnd( HBMux * m ) -{ - AddIndex( m ); - fclose( m->file ); - return 0; -} -#undef mh -#undef vh -#undef vf -#undef ah -#undef af - -static void AddChunk( HBMux * m, HBBuffer * buffer, - uint32_t fourCC, HBAviStreamHeader * header ) -{ - HBTitle * title = m->title; - AviVideoMuxData * videoMuxData = (AviVideoMuxData *) title->muxData; - AviAudioMuxData * audioMuxData; - - HBAudio * audio; - int i; - - /* Update index */ - IndexAddInt32( m->index, fourCC ); - IndexAddInt32( m->index, buffer->keyFrame ? AVIIF_KEYFRAME : 0 ); - IndexAddInt32( m->index, 4 + m->size ); - IndexAddInt32( m->index, buffer->size ); - - /* Write the chunk to the file */ - fseek( m->file, 0, SEEK_END ); - WriteInt32( m->file, fourCC ); - WriteInt32( m->file, buffer->size ); - WriteBuffer( m->file, buffer ); - - /* Chunks must be 2-bytes aligned */ - if( buffer->size & 1 ) - { - WriteInt8( m->file, 0 ); - } - - /* Update headers */ - m->size += 8 + EVEN( buffer->size ); - header->Length++; - - /* RIFF size */ - fseek( m->file, 4, SEEK_SET ); - WriteInt32( m->file, 2040 + m->size ); - - /* HBAviStreamHeader's lengths */ - fseek( m->file, 140, SEEK_SET ); - WriteInt32( m->file, videoMuxData->videoHeader.Length ); - - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); - audioMuxData = (AviAudioMuxData *) audio->muxData; - fseek( m->file, 268 + i * 114, SEEK_SET ); - WriteInt32( m->file, audioMuxData->audioHeader.Length ); - } - - /* movi size */ - fseek( m->file, 2040, SEEK_SET ); - WriteInt32( m->file, 4 + m->size ); -} - -static void AddIndex( HBMux * m ) -{ - HBTitle * title = m->title; - AviVideoMuxData * videoMuxData = (AviVideoMuxData *) title->muxData; - - fseek( m->file, 0, SEEK_END ); - - WriteInt32( m->file, FOURCC( "idx1" ) ); - WriteInt32( m->file, m->index->size ); - WriteBuffer( m->file, m->index ); - - m->size += 8 + m->index->size; - fseek( m->file, 4, SEEK_SET ); - WriteInt32( m->file, 2040 + m->size ); - videoMuxData->mainHeader.Flags |= AVIF_HASINDEX; - fseek( m->file, 24, SEEK_SET ); - WriteMainHeader( m->file, &videoMuxData->mainHeader ); -} - -static void WriteInt8( FILE * file, uint8_t val ) -{ - fputc( val, file ); -} - -static void WriteInt16( FILE * file, uint16_t val ) -{ - fputc( val & 0xFF, file ); - fputc( val >> 8, file ); -} - -static void WriteInt32( FILE * file, uint32_t val ) -{ - fputc( val & 0xFF, file ); - fputc( ( val >> 8 ) & 0xFF, file ); - fputc( ( val >> 16 ) & 0xFF, file ); - fputc( val >> 24, file ); -} - -static void WriteBuffer( FILE * file, HBBuffer * buffer ) -{ - fwrite( buffer->data, buffer->size, 1, file ); -} - -static void WriteHBBitmapInfo( FILE * file, HBBitmapInfo * bitmapInfo ) -{ - WriteInt32( file, bitmapInfo->FourCC ); - WriteInt32( file, bitmapInfo->BytesCount ); - WriteInt32( file, bitmapInfo->Size ); - WriteInt32( file, bitmapInfo->Width ); - WriteInt32( file, bitmapInfo->Height ); - WriteInt16( file, bitmapInfo->Planes ); - WriteInt16( file, bitmapInfo->BitCount ); - WriteInt32( file, bitmapInfo->Compression ); - WriteInt32( file, bitmapInfo->SizeImage ); - WriteInt32( file, bitmapInfo->XPelsPerMeter ); - WriteInt32( file, bitmapInfo->YPelsPerMeter ); - WriteInt32( file, bitmapInfo->ClrUsed ); - WriteInt32( file, bitmapInfo->ClrImportant ); -} - -static void WriteHBWaveFormatEx( FILE * file, HBWaveFormatEx * waveFormatEx ) -{ - WriteInt32( file, waveFormatEx->FourCC ); - WriteInt32( file, waveFormatEx->BytesCount ); - WriteInt16( file, waveFormatEx->FormatTag ); - WriteInt16( file, waveFormatEx->Channels ); - WriteInt32( file, waveFormatEx->SamplesPerSec ); - WriteInt32( file, waveFormatEx->AvgBytesPerSec ); - WriteInt16( file, waveFormatEx->BlockAlign ); - WriteInt16( file, waveFormatEx->BitsPerSample ); - WriteInt16( file, waveFormatEx->Size ); - WriteInt16( file, waveFormatEx->Id ); - WriteInt32( file, waveFormatEx->Flags ); - WriteInt16( file, waveFormatEx->BlockSize ); - WriteInt16( file, waveFormatEx->FramesPerBlock ); - WriteInt16( file, waveFormatEx->CodecDelay ); -} - -static void WriteMainHeader( FILE * file, HBAviMainHeader * mainHeader ) -{ - WriteInt32( file, mainHeader->FourCC ); - WriteInt32( file, mainHeader->BytesCount ); - WriteInt32( file, mainHeader->MicroSecPerFrame ); - WriteInt32( file, mainHeader->MaxBytesPerSec ); - WriteInt32( file, mainHeader->PaddingGranularity ); - WriteInt32( file, mainHeader->Flags ); - WriteInt32( file, mainHeader->TotalFrames ); - WriteInt32( file, mainHeader->InitialFrames ); - WriteInt32( file, mainHeader->Streams ); - WriteInt32( file, mainHeader->SuggestedBufferSize ); - WriteInt32( file, mainHeader->Width ); - WriteInt32( file, mainHeader->Height ); - WriteInt32( file, mainHeader->Reserved[0] ); - WriteInt32( file, mainHeader->Reserved[1] ); - WriteInt32( file, mainHeader->Reserved[2] ); - WriteInt32( file, mainHeader->Reserved[3] ); -} - -static void WriteStreamHeader( FILE * file, HBAviStreamHeader * streamHeader ) -{ - WriteInt32( file, streamHeader->FourCC ); - WriteInt32( file, streamHeader->BytesCount ); - WriteInt32( file, streamHeader->Type ); - WriteInt32( file, streamHeader->Handler ); - WriteInt32( file, streamHeader->Flags ); - WriteInt16( file, streamHeader->Priority ); - WriteInt16( file, streamHeader->Language ); - WriteInt32( file, streamHeader->InitialFrames ); - WriteInt32( file, streamHeader->Scale ); - WriteInt32( file, streamHeader->Rate ); - WriteInt32( file, streamHeader->Start ); - WriteInt32( file, streamHeader->Length ); - WriteInt32( file, streamHeader->SuggestedBufferSize ); - WriteInt32( file, streamHeader->Quality ); - WriteInt32( file, streamHeader->SampleSize ); - WriteInt16( file, streamHeader->Left ); - WriteInt16( file, streamHeader->Top ); - WriteInt16( file, streamHeader->Right ); - WriteInt16( file, streamHeader->Bottom ); -} - -static void IndexAddInt32( HBBuffer * b, uint32_t val ) -{ - if( b->size + 16 > b->alloc ) - { - HBLog( "HBAviMux: reallocing index (%d MB)", - 1 + b->alloc / 1024 / 1024 ); - HBBufferReAlloc( b, b->alloc + 1024 * 1024 ); - } - - b->data[b->size++] = val & 0xFF; - b->data[b->size++] = ( val >> 8 ) & 0xFF; - b->data[b->size++] = ( val >> 16 ) & 0xFF; - b->data[b->size++] = val >> 24; -} - diff --git a/core/DVDRead.c b/core/DVDRead.c deleted file mode 100644 index 4c36f3942..000000000 --- a/core/DVDRead.c +++ /dev/null @@ -1,257 +0,0 @@ -/* $Id: DVDRead.c,v 1.13 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#include "dvdread/dvd_reader.h" - -/* Local prototypes */ -static void DVDReadThread( void * ); -static int DoPass( HBDVDRead * ); -static int Demux( HBDVDRead * ); -static int Push( HBDVDRead *, HBFifo * fifo, HBBuffer ** buffer ); - -struct HBDVDRead -{ - HBHandle * handle; - - dvd_reader_t * reader; - dvd_file_t * file; - HBTitle * title; - int beginPosition; - int endPosition; - int pass; - HBBuffer * psBuffer; - HBList * esBufferList; - - volatile int die; - HBThread * thread; -}; - -HBDVDRead * HBDVDReadInit( HBHandle * handle, HBTitle * title ) -{ - HBDVDRead * d; - if( !( d = malloc( sizeof( HBDVDRead ) ) ) ) - { - HBLog( "HBDVDReadInit: malloc() failed, gonna crash" ); - return NULL; - } - - /* Initializations */ - d->handle = handle; - d->reader = NULL; - d->file = NULL; - d->title = title; - d->beginPosition = 0; - d->endPosition = 0; - d->pass = 0; - d->psBuffer = NULL; - d->esBufferList = HBListInit(); - - /* Launch the thread */ - d->die = 0; - d->thread = HBThreadInit( "dvd reader", DVDReadThread, d, - HB_NORMAL_PRIORITY ); - - return d; -} - -void HBDVDReadClose( HBDVDRead ** _d ) -{ - HBBuffer * buffer; - - HBDVDRead * d = *_d; - - /* Stop the thread */ - d->die = 1; - HBThreadClose( &d->thread ); - - /* Clean up */ - while( ( buffer = (HBBuffer*) HBListItemAt( d->esBufferList, 0 ) ) ) - { - HBListRemove( d->esBufferList, buffer ); - HBBufferClose( &buffer ); - } - HBListClose( &d->esBufferList ) ; - free( d ); - - (*_d) = NULL; -} - -static void DVDReadThread( void * _d ) -{ - HBDVDRead * d = (HBDVDRead*) _d; - HBTitle * title = d->title; - - int i; - - /* Open the device */ - d->reader = DVDOpen( title->device ); - if( !d->reader ) - { - HBLog( "HBDVDRead: DVDOpen() failed" ); - HBErrorOccured( d->handle, HB_ERROR_DVD_OPEN ); - return; - } - - /* Open the title */ - d->file = DVDOpenFile( d->reader, title->vts_id, DVD_READ_TITLE_VOBS ); - - /* Do the job */ - for( i = 0; i < ( title->twoPass ? 2 : 1 ); i++ ) - { - HBLog( "HBDVDRead: starting pass %d of %d", i + 1, - title->twoPass ? 2 : 1 ); - - d->pass = title->twoPass ? ( i + 1 ) : 0; - - if( !DoPass( d ) ) - { - break; - } - } - - if( !d->die ) - { - HBLog( "HBDVDRead: done" ); - HBDone( d->handle ); - } - - /* Clean up */ - DVDCloseFile( d->file ); - DVDClose( d->reader ); -} - - -static int DoPass( HBDVDRead * d ) -{ - int i; - - for( i = d->title->startBlock; i < d->title->endBlock; i++ ) - { - d->psBuffer = HBBufferInit( DVD_VIDEO_LB_LEN ); - d->psBuffer->position = (float) ( i - d->title->startBlock ) / - ( d->title->endBlock - d->title->startBlock ); - - if( d->pass ) - { - d->psBuffer->position /= 2; - - if( d->pass == 2 ) - { - d->psBuffer->position += 0.5; - } - } - d->psBuffer->pass = d->pass; - - if( DVDReadBlocks( d->file, i, 1, d->psBuffer->data ) < 0 ) - { - HBLog( "HBDVDRead: DVDReadBlocks() failed" ); - HBErrorOccured( d->handle, HB_ERROR_DVD_READ ); - HBBufferClose( &d->psBuffer ); - return 0; - } - - if( !Demux( d ) ) - { - return 0; - } - } - - return 1; -} - -static int Demux( HBDVDRead * d ) -{ - HBTitle * title = d->title; - - HBAudio * audio; - HBBuffer * esBuffer; - int i; - - /* Demux */ - HBPStoES( &d->psBuffer, d->esBufferList ); - - /* Push buffers */ - while( ( esBuffer = (HBBuffer*) HBListItemAt( d->esBufferList, 0 ) ) ) - { - /* First pass: trash audio buffers */ - if( d->pass == 1 && esBuffer->streamId != 0xE0 ) - { - HBListRemove( d->esBufferList, esBuffer ); - HBBufferClose( &esBuffer ); - continue; - } - - /* Video */ - if( esBuffer->streamId == 0xE0 ) - { - if( title->start < 0 ) - { - title->start = esBuffer->pts / 90; - HBLog( "HBDVDRead: got first 0xE0 packet (%d)", - title->start ); - } - - HBListRemove( d->esBufferList, esBuffer ); - if( !Push( d, title->inFifo, &esBuffer ) ) - { - return 0; - } - continue; - } - - /* Audio or whatever */ - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio*) HBListItemAt( title->ripAudioList, i ); - - if( esBuffer->streamId != audio->id ) - { - continue; - } - - if( audio->start < 0 ) - { - audio->start = esBuffer->pts / 90; - HBLog( "HBDVDRead: got first 0x%x packet (%d)", - audio->id, audio->start ); - - audio->delay = audio->start - title->start; - } - - HBListRemove( d->esBufferList, esBuffer ); - if( !Push( d, audio->inFifo, &esBuffer ) ) - { - return 0; - } - break; - } - - if( esBuffer ) - { - HBListRemove( d->esBufferList, esBuffer ); - HBBufferClose( &esBuffer ); - } - } - - return 1; -} - -static int Push( HBDVDRead * d, HBFifo * fifo, HBBuffer ** buffer ) -{ - while( !d->die ) - { - if( HBFifoPush( fifo, buffer ) ) - { - return 1; - } - HBSnooze( 5000 ); - } - - return 0; -} - diff --git a/core/FaacEnc.c b/core/FaacEnc.c deleted file mode 100644 index 689e6e18f..000000000 --- a/core/FaacEnc.c +++ /dev/null @@ -1,140 +0,0 @@ -/* $Id: FaacEnc.c,v 1.20 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* libfaac */ -#include "faac.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBAudio * audio; - - faacEncHandle * faac; - unsigned long inputSamples; - unsigned long maxOutputBytes; - float * inputBuffer; -}; - -/* Local prototypes */ -static int FaacEncWork( HBWork * ); - -HBWork * HBFaacEncInit( HBHandle * handle, HBAudio * audio ) -{ - HBWork * w; - if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) - { - HBLog( "HBFaacEncInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "FaacEnc" ); - w->work = FaacEncWork; - - w->handle = handle; - w->audio = audio; - - return w; -} - -void HBFaacEncClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - if( w->faac ) - { - faacEncClose( w->faac ); - free( w->inputBuffer ); - } - - free( w->name ); - free( w ); - - *_w = NULL; -} - -static int FaacEncWork( HBWork * w ) -{ - HBAudio * audio = w->audio; - - HBBuffer * aacBuffer; - float position; - - if( !w->faac ) - { - faacEncConfigurationPtr config; - - if( !HBFifoSize( audio->resampleFifo ) ) - { - return 0; - } - - HBLog( "HBFaacEnc: opening libfaac (%x)", audio->id ); - - w->faac = faacEncOpen( audio->outSampleRate, 2, - &w->inputSamples, &w->maxOutputBytes ); - w->inputBuffer = malloc( w->inputSamples * sizeof( float ) ); - config = faacEncGetCurrentConfiguration( w->faac ); - config->mpegVersion = MPEG4; - config->aacObjectType = LOW; - config->allowMidside = 1; - config->useLfe = 0; - config->useTns = 0; - config->bitRate = audio->outBitrate * 500; /* per channel */ - config->bandWidth = 0; - config->outputFormat = 0; - config->inputFormat = FAAC_INPUT_FLOAT; - if( !faacEncSetConfiguration( w->faac, config ) ) - { - HBLog( "HBFaacEnc: faacEncSetConfiguration failed" ); - } - if( faacEncGetDecoderSpecificInfo( w->faac, &audio->esConfig, - &audio->esConfigLength ) < 0 ) - { - HBLog( "HBFaacEnc: faacEncGetDecoderSpecificInfo failed" ); - } - } - - if( HBFifoIsHalfFull( audio->outFifo ) ) - { - return 0; - } - - if( !HBFifoGetBytes( audio->resampleFifo, - (uint8_t *) w->inputBuffer, - w->inputSamples * sizeof( float ), - &position ) ) - { - return 0; - } - - aacBuffer = HBBufferInit( w->maxOutputBytes ); - aacBuffer->position = position; - aacBuffer->size = faacEncEncode( w->faac, (int32_t*)w->inputBuffer, - w->inputSamples, aacBuffer->data, w->maxOutputBytes ); - - if( !aacBuffer->size ) - { - HBBufferClose( &aacBuffer ); - } - else if( aacBuffer->size < 0 ) - { - HBLog( "HBFaacEnc: faacEncEncode() failed" ); - } - else - { - if( !HBFifoPush( audio->outFifo, &aacBuffer ) ) - { - HBLog( "HBFaacEnc: HBFifoPush failed" ); - } - } - - return 1; -} - diff --git a/core/FfmpegEnc.c b/core/FfmpegEnc.c deleted file mode 100644 index ae474d00b..000000000 --- a/core/FfmpegEnc.c +++ /dev/null @@ -1,255 +0,0 @@ -/* $Id: FfmpegEnc.c,v 1.26 2004/05/12 18:02:35 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* libavcodec */ -#include "ffmpeg/avcodec.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBTitle * title; - - int pass; - AVCodecContext * context; - FILE * file; -}; - -/* Local prototypes */ -static int FfmpegEncWork( HBWork * ); -static int InitAvcodec( HBWork * ); -static void CloseAvcodec( HBWork * ); - -HBWork * HBFfmpegEncInit( HBHandle * handle, HBTitle * title ) -{ - HBWork * w; - if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) - { - HBLog( "HBFfmpegEncInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "FfmpegEnc" ); - w->work = FfmpegEncWork; - - w->handle = handle; - w->title = title; - w->pass = 42; - - return w; -} - -void HBFfmpegEncClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - if( w->context ) - { - CloseAvcodec( w ); - } - - free( w->name ); - free( w ); - - *_w = NULL; -} - -static int FfmpegEncWork( HBWork * w ) -{ - HBTitle * title = w->title; - - HBBuffer * scaledBuffer; - HBBuffer * mpeg4Buffer; - AVFrame * frame; - - if( HBFifoIsHalfFull( title->outFifo ) ) - { - return 0; - } - - if( !( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) - { - return 0; - } - - /* Init or re-init if needed */ - if( scaledBuffer->pass != w->pass ) - { - if( w->context ) - { - CloseAvcodec( w ); - } - - w->pass = scaledBuffer->pass; - - if( !InitAvcodec( w ) ) - { - HBErrorOccured( w->handle, HB_ERROR_MPEG4_INIT ); - return 0; - } - } - - frame = avcodec_alloc_frame(); - frame->data[0] = scaledBuffer->data; - frame->data[1] = frame->data[0] + title->outWidth * - title->outHeight; - frame->data[2] = frame->data[1] + title->outWidth * - title->outHeight / 4; - frame->linesize[0] = title->outWidth; - frame->linesize[1] = title->outWidth / 2; - frame->linesize[2] = title->outWidth / 2; - - mpeg4Buffer = HBBufferInit( 3 * title->outWidth * - title->outHeight / 2 ); - mpeg4Buffer->position = scaledBuffer->position; - mpeg4Buffer->size = avcodec_encode_video( w->context, - mpeg4Buffer->data, mpeg4Buffer->alloc, frame ); - mpeg4Buffer->keyFrame = w->context->coded_frame->key_frame; - - /* Inform the GUI about the current position */ - HBPosition( w->handle, scaledBuffer->position ); - - if( w->pass == 1 ) - { - if( w->context->stats_out ) - { - fprintf( w->file, "%s", w->context->stats_out ); - } - HBBufferClose( &mpeg4Buffer ); - } - else - { - if( !HBFifoPush( title->outFifo, &mpeg4Buffer ) ) - { - HBLog( "HBFfmpegEnc: HBFifoPush failed" ); - } - } - - HBBufferClose( &scaledBuffer ); - free( frame ); - - return 1; -} - -static int InitAvcodec( HBWork * w ) -{ - AVCodec * codec; - AVCodecContext * context; - HBTitle * title = w->title; - - HBLog( "HBFfmpegEnc: opening libavcodec (pass %d)", w->pass ); - - codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); - if( !codec ) - { - HBLog( "HBFfmpegEnc: avcodec_find_encoder() failed" ); - HBErrorOccured( w->handle, HB_ERROR_MPEG4_INIT ); - return 0; - } - - context = avcodec_alloc_context(); - context->bit_rate = 1024 * title->bitrate; - context->bit_rate_tolerance = 10 * context->bit_rate; - context->width = title->outWidth; - context->height = title->outHeight; - context->frame_rate = title->rate; - context->frame_rate_base = title->rateBase; - context->gop_size = 10 * title->rate / title->rateBase; - - if( title->mux == HB_MUX_MP4 && w->pass != 1 ) - { - context->flags |= CODEC_FLAG_GLOBAL_HEADER; - } - - if( w->pass ) - { - char fileName[1024]; memset( fileName, 0, 1024 ); -#ifndef HB_CYGWIN - sprintf( fileName, "/tmp/HB.%d.ffmpeg.log", - HBGetPid( w->handle ) ); -#else - sprintf( fileName, "C:\\HB.%d.ffmpeg.log", - HBGetPid( w->handle ) ); -#endif - - if( w->pass == 1 ) - { - w->file = fopen( fileName, "wb" ); - context->flags |= CODEC_FLAG_PASS1; - } - else - { - FILE * file; - int size; - char * log; - - file = fopen( fileName, "rb" ); - fseek( file, 0, SEEK_END ); - size = ftell( file ); - fseek( file, 0, SEEK_SET ); - if( !( log = malloc( size + 1 ) ) ) - { - HBLog( "HBFfmpegEnc: malloc() failed, gonna crash" ); - } - log[size] = '\0'; - fread( log, size, 1, file ); - fclose( file ); - - context->flags |= CODEC_FLAG_PASS2; - context->stats_in = log; - } - } - -#ifdef HB_NOMMX - context->dct_algo = FF_DCT_INT; - context->idct_algo = FF_IDCT_INT; - context->dsp_mask = 0x1F; -#endif - - if( avcodec_open( context, codec ) < 0 ) - { - HBLog( "HBFfmpegEnc: avcodec_open() failed" ); - return 0; - } - - if( title->mux == HB_MUX_MP4 && w->pass != 1 ) - { - /* UGLY */ - title->esConfig = malloc( 15 ); - title->esConfigLength = 15; - memcpy( title->esConfig, context->extradata + 15, 15 ); - } - - w->context = context; - return 1; -} - -static void CloseAvcodec( HBWork * w ) -{ - HBLog( "HBFfmpegEnc: closing libavcodec (pass %d)", - w->pass ); - - if( w->context->stats_in ) - { - free( w->context->stats_in ); - } - avcodec_close( w->context ); - if( w->file ) - { - fclose( w->file ); - w->file = NULL; - } - if( w->title->esConfig ) - { - free( w->title->esConfig ); - w->title->esConfig = NULL; - w->title->esConfigLength = 0; - } -} - diff --git a/core/Fifo.c b/core/Fifo.c deleted file mode 100644 index ae0c412da..000000000 --- a/core/Fifo.c +++ /dev/null @@ -1,135 +0,0 @@ -/* $Id: Fifo.c,v 1.17 2004/04/27 19:30:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Fifo.h" -#if defined( HB_BEOS ) || defined( HB_LINUX ) -#include <malloc.h> -#endif - -HBBuffer * HBBufferInit( int size ) -{ - HBBuffer * b; - if( !( b = calloc( sizeof( HBBuffer ), 1 ) ) ) - { - HBLog( "HBBuffer: malloc() failed, gonna crash" ); - return NULL; - } - - b->alloc = size; - b->size = size; - -#if defined( HB_BEOS ) || defined( HB_LINUX ) - b->data = memalign( 16, size ); -#elif defined( HB_MACOSX ) - /* OS X's malloc returns 16-bytes aligned memory */ - b->data = malloc( size ); -#elif defined( HB_CYGWIN ) - b->dataOrig = malloc( size + 15 ); - b->data = b->dataOrig + 15; - b->data -= (long) b->data & 15; -#endif - b->dataf = (float*) b->data; - - if( !b->data ) - { - HBLog( "HBBuffer: malloc() failed, gonna crash" ); - free( b ); - return NULL; - } - - return b; -} - -void HBBufferReAlloc( HBBuffer * b, int size ) -{ - /* We don't care about alignment here, realloc is only used in the - AVI muxer anyway */ -#if defined( HB_BEOS ) || defined( HB_LINUX ) || defined( HB_MACOSX ) - b->data = realloc( b->data, size ); -#elif defined( HB_CYGWIN ) - int alignment = b->data - b->dataOrig; - b->dataOrig = realloc( b->dataOrig, size + alignment ); - b->data = b->dataOrig + alignment; -#endif - b->alloc = size; - - if( !b->data ) - { - HBLog( "HBBuffer: realloc() failed, gonna crash soon" ); - } -} - -void HBBufferClose( HBBuffer ** _b ) -{ - HBBuffer * b = *_b; - -#if defined( HB_BEOS ) || defined( HB_LINUX ) || defined( HB_MACOSX ) - free( b->data ); -#elif defined( HB_CYGWIN ) - free( b->dataOrig ); -#endif - free( b ); - - *_b = NULL; -} - -HBFifo * HBFifoInit( int capacity ) -{ - HBFifo * f; - if( !( f = malloc( sizeof( HBFifo ) ) ) ) - { - HBLog( "HBFifo: malloc() failed, gonna crash" ); - return NULL; - } - - f->die = 0; - f->capacity = capacity; - f->whereToPush = 0; - f->whereToPop = 0; - - if( !( f->buffers = malloc( ( capacity + 1 ) * sizeof( void* ) ) ) ) - { - HBLog( "HBFifo: malloc() failed, gonna crash" ); - free( f ); - return NULL; - } - - f->lock = HBLockInit(); - f->cond = HBCondInit(); - - return f; -} - -void HBFifoDie( HBFifo * f ) -{ - HBLockLock( f->lock ); - f->die = 1; - HBCondSignal( f->cond ); - HBLockUnlock( f->lock ); -} - -void HBFifoClose( HBFifo ** _f ) -{ - HBFifo * f = (*_f); - - HBLog( "HBFifo: trashing %d buffer%s", - HBFifoSize( f ), ( HBFifoSize( f ) > 1 ) ? "s" : "" ); - - while( f->whereToPush != f->whereToPop ) - { - HBBufferClose( &(f->buffers[f->whereToPop]) ); - f->whereToPop++; - f->whereToPop %= ( f->capacity + 1 ); - } - - HBLockClose( &f->lock ); - HBCondClose( &f->cond ); - free( f->buffers ); - free( f ); - - *_f = NULL; -} - diff --git a/core/Fifo.h b/core/Fifo.h deleted file mode 100644 index 26c4b5581..000000000 --- a/core/Fifo.h +++ /dev/null @@ -1,217 +0,0 @@ -/* $Id: Fifo.h,v 1.16 2004/04/27 22:02:59 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_FIFO_H -#define HB_FIFO_H - -#include "Utils.h" -#include "Thread.h" - -struct HBBuffer -{ - /* Members used everywhere */ - int alloc; - int size; - uint8_t * data; -#if defined( HB_CYGWIN ) - uint8_t * dataOrig; -#endif - float * dataf; - float position; - int pass; - - /* Only used for PStoES */ - uint32_t streamId; - uint64_t pts; - - /* NTSC suxx */ - int repeat; - - /* Only used for MPEG-4, MP3 and AAC buffers */ - int keyFrame; - - /* Use for bitstreams */ - int _pos; -}; - -HBBuffer * HBBufferInit( int size ); -void HBBufferReAlloc( HBBuffer *, int size ); -void HBBufferClose( HBBuffer ** ); - -struct HBFifo -{ - int die; - int capacity; - int whereToPush; - int whereToPop; - HBBuffer ** buffers; - HBLock * lock; - HBCond * cond; -}; - -HBFifo * HBFifoInit( int capacity ); -static inline int HBFifoSize( HBFifo * ); -static inline int HBFifoIsHalfFull( HBFifo * ); -static inline int HBFifoPush( HBFifo *, HBBuffer ** ); -static inline HBBuffer * HBFifoPop( HBFifo * ); -static inline int HBFifoWait( HBFifo * ); -static inline float HBFifoPosition( HBFifo * ); -static inline int HBFifoGetBytes( HBFifo * f, uint8_t *, int, - float * position ); -void HBFifoDie( HBFifo * ); -void HBFifoClose( HBFifo ** ); - -static inline int HBFifoSize( HBFifo * f ) -{ - int size; - HBLockLock( f->lock ); - size = ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % - ( f->capacity + 1 ); - HBLockUnlock( f->lock ); - return size; -} - -static inline int HBFifoIsHalfFull( HBFifo * f ) -{ - int size; - HBLockLock( f->lock ); - size = ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % - ( f->capacity + 1 ); - HBLockUnlock( f->lock ); - return ( 2 * size > f->capacity ); -} - -static inline int HBFifoPush( HBFifo * f, HBBuffer ** b ) -{ - HBLockLock( f->lock ); - HBCondSignal( f->cond ); - if( ( f->capacity + 1 + f->whereToPush - f->whereToPop ) % - ( f->capacity + 1 ) != f->capacity ) - { - f->buffers[f->whereToPush] = *b; - f->whereToPush++; - f->whereToPush %= ( f->capacity + 1 ); - HBLockUnlock( f->lock ); - *b = NULL; - return 1; - } - HBLockUnlock( f->lock ); - return 0; -} - -static inline HBBuffer * HBFifoPop( HBFifo * f ) -{ - HBLockLock( f->lock ); - if( f->whereToPush != f->whereToPop ) - { - HBBuffer * b = f->buffers[f->whereToPop]; - f->whereToPop++; - f->whereToPop %= ( f->capacity + 1 ); - HBLockUnlock( f->lock ); - return b; - } - HBLockUnlock( f->lock ); - return NULL; -} - -static inline int HBFifoWait( HBFifo * f ) -{ - HBLockLock( f->lock ); - if( f->whereToPush != f->whereToPop ) - { - HBLockUnlock( f->lock ); - return 1; - } - if( f->die ) - { - HBLockUnlock( f->lock ); - return 0; - } - HBCondWait( f->cond, f->lock ); - if( f->whereToPush != f->whereToPop ) - { - HBLockUnlock( f->lock ); - return 1; - } - HBLockUnlock( f->lock ); - return 0; -} - -static inline float HBFifoPosition( HBFifo * f ) -{ - float pos; - HBLockLock( f->lock ); - if( f->whereToPush != f->whereToPop ) - { - pos = f->buffers[f->whereToPop]->position; - } - else - { - pos = 0.0; - } - HBLockUnlock( f->lock ); - return pos; -} - -static inline int HBFifoGetBytes( HBFifo * f, uint8_t * data, int nb, - float * position ) -{ - int whereToPop, bytes = 0; - HBBuffer * buffer; - HBLockLock( f->lock ); - - /* Do we have enough? */ - for( whereToPop = f->whereToPop; ; whereToPop++ ) - { - whereToPop %= ( f->capacity + 1 ); - if( f->whereToPush == whereToPop ) - { - /* We hit the end of the fifo */ - break; - } - - bytes += f->buffers[whereToPop]->size - - f->buffers[whereToPop]->_pos; - - if( bytes >= nb ) - { - break; - } - } - - if( bytes < nb ) - { - /* Not enough data */ - HBLockUnlock( f->lock ); - return 0; - } - - for( bytes = 0; bytes < nb; ) - { - int copy; - - buffer = f->buffers[f->whereToPop]; - copy = MIN( nb - bytes, buffer->size - buffer->_pos ); - - memcpy( data + bytes, buffer->data + buffer->_pos, copy ); - (*position) = buffer->position; - - buffer->_pos += copy; - bytes += copy; - - if( buffer->_pos == buffer->size ) - { - HBBufferClose( &buffer ); - f->whereToPop++; - f->whereToPop %= ( f->capacity + 1 ); - } - } - - HBLockUnlock( f->lock ); - return 1; -} - -#endif diff --git a/core/HBInternal.h b/core/HBInternal.h deleted file mode 100644 index 4fa45f8b0..000000000 --- a/core/HBInternal.h +++ /dev/null @@ -1,86 +0,0 @@ -/* $Id: HBInternal.h,v 1.10 2004/05/12 17:21:24 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_INTERNAL_H -#define HB_INTERNAL_H - -#include "HandBrake.h" -#include "Fifo.h" -#include "Mux.h" -#include "Thread.h" -#include "Work.h" - -#ifndef HB_CYGWIN -#define LLD "%lld" -#else -#define LLD "%I64d" -#endif - -/* Demuxer */ -HBDVDRead * HBDVDReadInit( HBHandle *, HBTitle * ); -void HBDVDReadClose( HBDVDRead ** ); - -/* Decoders */ -HBWork * HBMpeg2DecInit( HBHandle *, HBTitle * ); -void HBMpeg2DecClose( HBWork ** ); -HBWork * HBAc3DecInit( HBHandle *, HBAudio * ); -void HBAc3DecClose( HBWork ** ); -HBWork * HBLpcmDecInit( HBHandle *, HBAudio * ); -void HBLpcmDecClose( HBWork ** ); -HBWork * HBMpgaDecInit( HBHandle *, HBAudio * ); -void HBMpgaDecClose( HBWork ** ); - -/* Scaler */ -HBWork * HBScaleInit( HBHandle *, HBTitle * ); -void HBScaleClose( HBWork ** ); - -/* Resampler */ -HBWork * HBResampleInit( HBHandle *, HBAudio * ); -void HBResampleClose( HBWork ** ); - -/* Encoders */ -HBWork * HBFfmpegEncInit( HBHandle *, HBTitle * ); -void HBFfmpegEncClose( HBWork ** ); -HBWork * HBXvidEncInit( HBHandle *, HBTitle * ); -void HBXvidEncClose( HBWork ** ); -HBWork * HBX264EncInit( HBHandle *, HBTitle * ); -void HBX264EncClose( HBWork ** ); -HBWork * HBMp3EncInit( HBHandle *, HBAudio * ); -void HBMp3EncClose( HBWork ** ); -HBWork * HBFaacEncInit( HBHandle *, HBAudio * ); -void HBFaacEncClose( HBWork ** ); -HBWork * HBVorbisEncInit ( HBHandle *, HBAudio * ); -void HBVorbisEncClose( HBWork ** ); - -/* Scanner */ -HBScan * HBScanInit( HBHandle *, const char * device, int title ); -void HBScanClose( HBScan ** ); - -/* Called by HBScan to tell the GUI how far we've been */ -void HBScanning( HBHandle *, int title, int titleCount ); - -/* Called by HBScan. titleList is a list of all valid titles which - should be shown on the interface */ -void HBScanDone( HBHandle *, HBList * titleList ); - -/* Used to create temporary files (/tmp/HB.pid.whatever) */ -int HBGetPid( HBHandle * ); - -/* Called by every thread involved in the rip process. Returns - immediately is rip isn't paused, blocks until the rip is resumed - otherwise */ -void HBCheckPaused( HBHandle * ); - -/* Called by the decoders when the last packet is being proceeded */ -void HBDone( HBHandle * ); - -/* Called by the video encoder to update the GUI progress */ -void HBPosition( HBHandle *, float ); - -/* Called by any thread which couldn't continue and asks to stop */ -void HBErrorOccured( HBHandle *, int error ); - -#endif diff --git a/core/HandBrake.c b/core/HandBrake.c deleted file mode 100644 index 6d16b4640..000000000 --- a/core/HandBrake.c +++ /dev/null @@ -1,780 +0,0 @@ -/* $Id: HandBrake.c,v 1.58 2004/05/12 18:02:35 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* libavcodec */ -#include "ffmpeg/avcodec.h" - -/* Local prototypes */ -static void HandBrakeThread( void * ); -static void _StopRip( HBHandle * ); -static void FixPictureSettings( HBTitle * ); -static int GetCPUCount(); - -struct HBHandle -{ - int cpuCount; - HBCallbacks cb; - - int stopScan; - int stopRip; - int ripDone; - int error; - - HBScan * scan; - HBList * titleList; - HBTitle * curTitle; - uint64_t beginDate; - uint64_t pauseDate; - uint64_t lastPosUpdate; - uint64_t lastFpsUpdate; - int framesSinceBegin; - int framesSinceFps; - float curFrameRate; - float avgFrameRate; - int remainingTime; - - HBLock * lock; - HBLock * pauseLock; - volatile int die; - HBThread * thread; - int pid; -}; - -HBHandle * HBInit( int debug, int cpuCount ) -{ - HBHandle * h; - - /* See HBLog() in Utils.cpp */ - if( debug ) - { - putenv( "HB_DEBUG=1" ); - } - - HBLog( "HBInit: starting HandBrake " HB_VERSION ); - - if( !( h = calloc( sizeof( HBHandle ), 1 ) ) ) - { - HBLog( "HBInit: malloc() failed, gonna crash" ); - return NULL; - } - - /* Init libavcodec */ - avcodec_init(); - register_avcodec( &mpeg4_encoder ); - register_avcodec( &mp2_decoder ); - - /* Check CPU count */ - if( !cpuCount ) - { - h->cpuCount = GetCPUCount(); - HBLog( "HBInit: %d CPU%s detected", h->cpuCount, - ( h->cpuCount > 1 ) ? "s" : "" ); - } - else - { - if( cpuCount < 1 ) - { - HBLog( "HBInit: invalid CPU count (%d), using 1", - cpuCount ); - h->cpuCount = 1; - } - else if( cpuCount > 8 ) - { - HBLog( "HBInit: invalid CPU count (%d), using 8", - cpuCount ); - h->cpuCount = 8; - } - else - { - HBLog( "HBInit: user specified %d CPU%s", - cpuCount, ( cpuCount > 1 ) ? "s" : "" ); - h->cpuCount = cpuCount; - } - } - - h->lock = HBLockInit(); - h->pauseLock = HBLockInit(); - h->thread = HBThreadInit( "libhb", HandBrakeThread, h, - HB_NORMAL_PRIORITY ); - return h; -} - -void HBSetCallbacks( HBHandle * h, HBCallbacks callbacks ) -{ - HBLockLock( h->lock ); - h->cb = callbacks; - HBLockUnlock( h->lock ); -} - -void HBScanDVD( HBHandle * h, const char * dvd, int title ) -{ - HBLockLock( h->lock ); - h->scan = HBScanInit( h, dvd, title ); - HBLockUnlock( h->lock ); -} - -void HBStartRip( HBHandle * h, HBTitle * title ) -{ - int i; - HBAudio * audio; - - HBLockLock( h->lock ); - - h->beginDate = HBGetDate(); - h->lastPosUpdate = 0; - h->lastFpsUpdate = 0; - h->framesSinceBegin = 0; - h->framesSinceFps = 0; - - FixPictureSettings( title ); - - /* Video fifos */ - title->inFifo = HBFifoInit( 2048 ); - title->rawFifo = HBFifoInit( 32 ); - title->scaledFifo = HBFifoInit( 32 ); - title->outFifo = HBFifoInit( 32 ); - - /* Video work objects */ - title->decoder = HBMpeg2DecInit( h, title ); - title->scale = HBScaleInit( h, title ); - if( title->codec == HB_CODEC_FFMPEG ) - title->encoder = HBFfmpegEncInit( h, title ); - else if( title->codec == HB_CODEC_XVID ) - title->encoder = HBXvidEncInit( h, title ); - else if( title->codec == HB_CODEC_X264 ) - title->encoder = HBX264EncInit( h, title ); - - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - - /* Audio fifos */ - audio->inFifo = HBFifoInit( 2048 ); - audio->rawFifo = HBFifoInit( 32 ); - audio->resampleFifo = HBFifoInit( 32 ); - audio->outFifo = HBFifoInit( 32 ); - - /* Audio work objects */ - if( audio->inCodec == HB_CODEC_AC3 ) - audio->decoder = HBAc3DecInit( h, audio ); - else if( audio->inCodec == HB_CODEC_LPCM ) - audio->decoder = HBLpcmDecInit( h, audio ); - else if( audio->inCodec == HB_CODEC_MPGA ) - audio->decoder = HBMpgaDecInit( h, audio ); - - audio->resample = HBResampleInit( h, audio ); - - if( audio->outCodec == HB_CODEC_MP3 ) - audio->encoder = HBMp3EncInit( h, audio ); - else if( audio->outCodec == HB_CODEC_AAC ) - audio->encoder = HBFaacEncInit( h, audio ); - else if( audio->outCodec == HB_CODEC_VORBIS ) - audio->encoder = HBVorbisEncInit( h, audio ); - } - - /* Create threads */ - title->dvdRead = HBDVDReadInit( h, title ); - - title->muxThread = HBMuxThreadInit( h, title ); - - for( i = 0; i < h->cpuCount; i++ ) - { - title->workThreads[i] = HBWorkThreadInit( h, title, i ? 0 : 1 ); - } - - h->curTitle = title; - - HBLockUnlock( h->lock ); -} - -void HBPauseRip( HBHandle * h ) -{ - HBLockLock( h->lock ); - h->pauseDate = HBGetDate(); - HBLockLock( h->pauseLock ); - HBLockUnlock( h->lock ); -} - -void HBResumeRip( HBHandle * h ) -{ - HBLockLock( h->lock ); - h->beginDate += HBGetDate() - h->pauseDate; - h->lastPosUpdate += HBGetDate() - h->pauseDate; - h->lastFpsUpdate += HBGetDate() - h->pauseDate; - HBLockUnlock( h->pauseLock ); - HBLockUnlock( h->lock ); -} - -void HBStopRip( HBHandle * h ) -{ - HBLockLock( h->lock ); - h->stopRip = 1; - HBLockUnlock( h->lock ); -} - -uint8_t * HBGetPreview( HBHandle * h, HBTitle * t, int picture ) -{ - AVPicture pic1, pic2, pic3, pic4; - uint8_t * buf1, * buf2, * buf3, * buf4; - char fileName[1024]; - FILE * file; - ImgReSampleContext * resampleContext; - int8_t * preview, * pen; - int i; - - FixPictureSettings( t ); - - buf1 = malloc( 3 * t->inWidth * t->inHeight / 2 ); - buf2 = malloc( 3 * t->inWidth * t->inHeight / 2 ); - buf3 = malloc( 3 * t->outWidth * t->outHeight / 2 ); - buf4 = malloc( 4 * t->outWidth * t->outHeight ); - - if( !buf1 || !buf2 || !buf3 || !buf4 ) - { - HBLog( "HBGetPreview: malloc() failed, gonna crash" ); - return NULL; - } - - /* Original YUV picture */ - avpicture_fill( &pic1, buf1, PIX_FMT_YUV420P, t->inWidth, - t->inHeight ); - - /* Deinterlaced YUV picture */ - avpicture_fill( &pic2, buf2, PIX_FMT_YUV420P, - t->inWidth, t->inHeight ); - - /* Scaled YUV picture */ - avpicture_fill( &pic3, buf3, PIX_FMT_YUV420P, t->outWidth, - t->outHeight ); - - /* Scaled RGB picture ) */ - avpicture_fill( &pic4, buf4, PIX_FMT_RGBA32, t->outWidth, - t->outHeight ); - - /* Get the original image from the temp file */ - memset( fileName, 0, 1024 ); - sprintf( fileName, "/tmp/HB.%d.%d.%d", h->pid, t->title, - picture ); - file = fopen( fileName, "rb" ); - if( file ) - { - fread( buf1, 3 * t->inWidth * t->inHeight / 2, 1, file ); - fclose( file ); - } - else - { - HBLog( "HBGetPreview: could not open %s", fileName ); - memset( buf1, 0, 3 * t->inWidth * t->inHeight / 2 ); - } - - /* Deinterlace if needed, and scale */ - resampleContext = - img_resample_full_init( t->outWidth, t->outHeight, - t->inWidth, t->inHeight, - t->topCrop, t->bottomCrop, - t->leftCrop, t->rightCrop ); - if( t->deinterlace ) - { - avpicture_deinterlace( &pic2, &pic1, PIX_FMT_YUV420P, - t->inWidth, t->inHeight ); - img_resample( resampleContext, &pic3, &pic2 ); - } - else - { - img_resample( resampleContext, &pic3, &pic1 ); - } - - /* Convert to RGB */ - img_convert( &pic4, PIX_FMT_RGBA32, &pic3, PIX_FMT_YUV420P, - t->outWidth, t->outHeight ); - - /* Create the final preview */ - preview = malloc( 4 * ( t->outWidthMax + 2 ) * - ( t->outHeightMax + 2 ) ); - - if( !preview ) - { - HBLog( "HBGetPreview: malloc() failed, gonna crash" ); - return NULL; - } - - /* Blank it */ - memset( preview, 0x80, - 4 * ( t->outWidthMax + 2 ) * ( t->outHeightMax + 2 ) ); - - /* Draw the picture (centered) and draw the cropping zone */ - pen = preview + ( t->outHeightMax - t->outHeight ) * - ( t->outWidthMax + 2 ) * 2 + - ( t->outWidthMax - t->outWidth ) * 2; - - memset( pen, 0xFF, 4 * ( t->outWidth + 2 ) ); - pen += 4 * ( t->outWidthMax + 2 ); - - for( i = 0; i < t->outHeight; i++ ) - { - uint8_t * nextLine = pen + 4 * ( t->outWidthMax + 2 ); - - memset( pen, 0xFF, 4 ); - pen += 4; - memcpy( pen, buf4 + 4 * t->outWidth * i, 4 * t->outWidth ); - pen += 4 * t->outWidth; - memset( pen, 0xFF, 4 ); - - pen = nextLine; - } - - memset( pen, 0xFF, 4 * ( t->outWidth + 2 ) ); - - /* Free memory */ - free( buf1 ); - free( buf2 ); - free( buf3 ); - free( buf4 ); - - return preview; - return NULL; -} - -int HBGetBitrateForSize( HBTitle * title, int size, int muxer, - int audioCount, int audioBitrate ) -{ - int64_t available; - int overheadPerFrame; - int samplesPerFrame; - int length; - - switch( muxer ) - { - /* Overhead are max seen values */ - case HB_MUX_MP4: - overheadPerFrame = 6; - samplesPerFrame = 1024; /* AAC */ - break; - case HB_MUX_AVI: - overheadPerFrame = 26; - samplesPerFrame = 1152; /* MP3 */ - break; - case HB_MUX_OGM: - overheadPerFrame = 0; /* XXX */ - samplesPerFrame = 1024; /* Vorbis */ - break; - default: - return 0; - } - - length = 3600 * title->hours + 60 * title->minutes + - title->seconds + 1; - - available = (int64_t) size * 1024 * 1024; - - /* Audio data */ - available -= audioCount * length * audioBitrate * 1000 / 8; - - /* Video headers */ - available -= (int64_t) length * title->rate * - overheadPerFrame / title->rateBase; - - /* Audio headers */ - available -= (int64_t) audioCount * length * 44100 * - overheadPerFrame / samplesPerFrame; - - if( available < 0 ) - { - return 0; - } - return( available / ( 128 * length ) ); -} - -void HBClose( HBHandle ** _h ) -{ - char command[1024]; - - HBHandle * h = *_h; - - h->die = 1; - HBThreadClose( &h->thread ); - - if( h->scan ) - { - HBScanClose( &h->scan ); - } - if( h->curTitle ) - { - _StopRip( h ); - } - if( h->titleList ) - { - HBTitle * title; - while( ( title = (HBTitle*) HBListItemAt( h->titleList, 0 ) ) ) - { - HBListRemove( h->titleList, title ); - HBTitleClose( &title ); - } - } - -#ifndef HB_CYGWIN - memset( command, 0, 1024 ); - sprintf( command, "rm -f /tmp/HB.%d.*", h->pid ); - system( command ); -#endif - - HBLockClose( &h->lock ); - HBLockClose( &h->pauseLock ); - free( h ); - - *_h = NULL; -} - -/* Following functions are called by libhb's internal threads */ -void HBCheckPaused( HBHandle * h ) -{ - HBLockLock( h->pauseLock ); - HBLockUnlock( h->pauseLock ); -} - -void HBScanning( HBHandle * h, int title, int titleCount ) -{ - h->cb.scanning( h->cb.data, title, titleCount ); -} - -void HBScanDone( HBHandle * h, HBList * titleList ) -{ - HBLockLock( h->lock ); - h->stopScan = 1; - h->titleList = titleList; - HBLockUnlock( h->lock ); -} - -int HBGetPid( HBHandle * h ) -{ - return h->pid; -} - -void HBDone( HBHandle * h ) -{ - HBLockLock( h->lock ); - h->ripDone = 1; - HBLockUnlock( h->lock ); -} - -void HBPosition( HBHandle * h, float position ) -{ - int pass, passCount; - - h->framesSinceBegin++; - h->framesSinceFps++; - - if( h->curTitle->twoPass ) - { - pass = ( position < 0.5 ) ? 1 : 2; - passCount = 2; - } - else - { - passCount = pass = 1; - } - - if( HBGetDate() - h->lastPosUpdate < 200000 ) - { - return; - } - - h->lastPosUpdate = HBGetDate(); - - if( HBGetDate() - h->lastFpsUpdate > 1000000 ) - { - h->curFrameRate = 1000000.0 * h->framesSinceFps / - ( HBGetDate() - h->lastFpsUpdate ); - h->avgFrameRate = 1000000.0 * h->framesSinceBegin / - ( HBGetDate() - h->beginDate ); - h->remainingTime = ( 1.0 - position ) * - ( HBGetDate() - h->beginDate ) / position / 1000000; - - h->lastFpsUpdate = HBGetDate(); - h->framesSinceFps = 0; - } - - h->cb.encoding( h->cb.data, position, pass, passCount, - h->curFrameRate, h->avgFrameRate, - h->remainingTime ); -} - -void HBErrorOccured( HBHandle * h, int error ) -{ - HBLockLock( h->lock ); - h->error = error; - HBLockUnlock( h->lock ); -} - -/* Local functions */ -static void HandBrakeThread( void * _h ) -{ - HBHandle * h = (HBHandle*) _h; - - h->pid = getpid(); - - while( !h->die ) - { - HBLockLock( h->lock ); - - if( h->stopScan ) - { - HBScanClose( &h->scan ); - h->stopScan = 0; - HBLockUnlock( h->lock ); - h->cb.scanDone( h->cb.data, h->titleList ); - continue; - } - - if( h->stopRip ) - { - _StopRip( h ); - h->stopRip = 0; - HBLockUnlock( h->lock ); - h->cb.ripDone( h->cb.data, HB_CANCELED ); - continue; - } - - if( h->ripDone ) - { - HBTitle * title = h->curTitle; - - /* Wait until we're done with the video track */ - uint64_t waitStart = HBGetDate(); - for( ;; ) - { - if( !HBFifoSize( title->inFifo ) && - !HBFifoSize( title->rawFifo ) && - !HBFifoSize( title->scaledFifo ) ) - { - break; - } - - /* XXX Deadlock workaround */ - if( HBGetDate() - waitStart > 30000000 ) - { - HBLog( "Waited too long, stopping now" ); - break; - } - - HBSnooze( 5000 ); - } - - HBSnooze( 500000 ); - _StopRip( h ); - h->ripDone = 0; - h->error = 0; - HBLockUnlock( h->lock ); - h->cb.ripDone( h->cb.data, HB_SUCCESS ); - continue; - } - - if( h->error ) - { - _StopRip( h ); - HBLockUnlock( h->lock ); - h->cb.ripDone( h->cb.data, h->error ); - h->error = 0; - continue; - } - - HBLockUnlock( h->lock ); - HBSnooze( 10000 ); - } -} - -static void _StopRip( HBHandle * h ) -{ - HBTitle * title = h->curTitle; - HBAudio * audio; - int i; - - if( !title ) - { - return; - } - - /* Stop input and work threads */ - HBDVDReadClose( &title->dvdRead ); - for( i = 0; i < h->cpuCount; i++ ) - { - HBWorkThreadClose( &title->workThreads[h->cpuCount-i-1] ); - } - - /* Invalidate fifos */ - HBFifoDie( title->outFifo ); - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - HBFifoDie( audio->outFifo ); - } - - /* Stop mux thread */ - HBMuxThreadClose( &title->muxThread ); - - /* Clean up */ - HBMpeg2DecClose( &title->decoder ); - HBScaleClose( &title->scale ); - - if( title->codec == HB_CODEC_FFMPEG ) - HBFfmpegEncClose( &title->encoder ); - else if( title->codec == HB_CODEC_XVID ) - HBXvidEncClose( &title->encoder ); - else if( title->codec == HB_CODEC_X264 ) - HBX264EncClose( &title->encoder ); - - HBFifoClose( &title->inFifo ); - HBFifoClose( &title->rawFifo ); - HBFifoClose( &title->scaledFifo ); - HBFifoClose( &title->outFifo ); - - while( ( audio = HBListItemAt( title->ripAudioList, 0 ) ) ) - { - /* Audio work objects */ - if( audio->inCodec == HB_CODEC_AC3 ) - HBAc3DecClose( &audio->decoder ); - else if( audio->inCodec == HB_CODEC_LPCM ) - HBLpcmDecClose( &audio->decoder ); - else if( audio->inCodec == HB_CODEC_MPGA ) - HBMpgaDecClose( &audio->decoder ); - - HBResampleClose( &audio->resample ); - - if( audio->outCodec == HB_CODEC_MP3 ) - HBMp3EncClose( &audio->encoder ); - else if( audio->outCodec == HB_CODEC_AAC ) - HBFaacEncClose( &audio->encoder ); - else if( audio->outCodec == HB_CODEC_VORBIS ) - HBVorbisEncClose( &audio->encoder ); - - /* Audio fifos */ - HBFifoClose( &audio->inFifo ); - HBFifoClose( &audio->rawFifo ); - HBFifoClose( &audio->resampleFifo ); - HBFifoClose( &audio->outFifo ); - - HBListRemove( title->ripAudioList, audio ); - } - - h->curTitle = NULL; -} - -static void FixPictureSettings( HBTitle * t ) -{ - /* Sanity checks */ - t->outWidth = MULTIPLE_16( t->outWidth ); - t->topCrop = EVEN( t->topCrop ); - t->bottomCrop = EVEN( t->bottomCrop ); - t->leftCrop = EVEN( t->leftCrop ); - t->rightCrop = EVEN( t->rightCrop ); - - t->outWidth = MIN( t->outWidth, t->outWidthMax ); - t->outWidth = MAX( 16, t->outWidth ); - - t->outHeight = - MULTIPLE_16( (uint64_t) t->outWidth * t->inWidth * - ( t->inHeight - t->topCrop - t->bottomCrop ) * - VOUT_ASPECT_FACTOR / - ( (uint64_t) t->inHeight * - ( t->inWidth - t->leftCrop - t->rightCrop ) * - t->aspect ) ); - t->outHeight = MAX( 16, t->outHeight ); - - if( t->outHeight > t->outHeightMax ) - { - t->outHeight = t->outHeightMax; - t->outWidth = - MULTIPLE_16( (uint64_t) t->outHeight * t->inHeight * - ( t->inWidth - t->leftCrop - t->rightCrop ) * - t->aspect / - ( (uint64_t) t->inWidth * - ( t->inHeight - t->topCrop - t->bottomCrop ) * - VOUT_ASPECT_FACTOR ) ); - t->outWidth = MIN( t->outWidth, t->outWidthMax ); - t->outWidth = MAX( 16, t->outWidth ); - } -} - -static int GetCPUCount() -{ - int CPUCount = 1; - -#if defined( HB_BEOS ) - system_info info; - get_system_info( &info ); - CPUCount = info.cpu_count; - -#elif defined( HB_MACOSX ) - FILE * info; - char buffer[256]; - - if( ( info = popen( "/usr/sbin/sysctl hw.ncpu", "r" ) ) ) - { - if( fgets( buffer, 256, info ) ) - { - int count; - if( sscanf( buffer, "hw.ncpu: %d", &count ) == 1 ) - { - CPUCount = count; - } - else - { - HBLog( "GetCPUCount: sscanf() failed" ); - } - } - else - { - HBLog( "GetCPUCount: fgets() failed" ); - } - fclose( info ); - } - else - { - HBLog( "GetCPUCount: popen() failed" ); - } - -#elif defined( HB_LINUX ) - FILE * info; - char buffer[256]; - - if( ( info = popen( "grep -c '^processor' /proc/cpuinfo", "r" ) ) ) - { - if( fgets( buffer, 256, info ) ) - { - int count; - if( sscanf( buffer, "%d", &count ) == 1 ) - { - CPUCount = count; - } - else - { - HBLog( "GetCPUCount: sscanf() failed" ); - } - } - else - { - HBLog( "GetCPUCount: fgets() failed" ); - } - fclose( info ); - } - else - { - HBLog( "GetCPUCount: fopen() failed" ); - } - -#elif defined( HB_CYGWIN ) - /* TODO */ - CPUCount = 1; - -#endif - CPUCount = MAX( 1, CPUCount ); - CPUCount = MIN( CPUCount, 8 ); - - return CPUCount; -} - diff --git a/core/HandBrake.h b/core/HandBrake.h deleted file mode 100644 index 9d84d39dc..000000000 --- a/core/HandBrake.h +++ /dev/null @@ -1,75 +0,0 @@ -/* $Id: HandBrake.h,v 1.10 2004/01/21 18:40:36 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_HANDBRAKE_H -#define HB_HANDBRAKE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "Utils.h" - -/* Interface callbacks */ -typedef struct HBCallbacks -{ - void * data; - - void (*scanning) ( void * data, int title, int titleCount ); - void (*scanDone) ( void * data, HBList * titleList ); - void (*encoding) ( void * data, float position, int pass, - int passCount, float curFrameRate, - float avgFrameRate, int remainingTime ); - void (*ripDone) ( void * data, int result ); - -} HBCallbacks; - -/* Init libhb. Set debug to 0 to see no output, 1 to see all libhb logs. - Set cpuCount to 0 if you want libhb to autodetect */ -HBHandle * HBInit( int debug, int cpuCount ); - -/* Tell libhb what functions should be called when a GUI should be - updated. */ -void HBSetCallbacks( HBHandle *, HBCallbacks callbacks ); - -/* Launch a thread which scans the specified DVD and title. Use - title = 0 to scan all titles. Returns immediately */ -void HBScanDVD( HBHandle *, const char * dvd, int title ); - -/* Calculate bitrate so the output file fits in X MB */ -int HBGetBitrateForSize( HBTitle * title, int size, int muxer, - int audioCount, int audioBitrate ); - -/* Start ripping the specified title. Returns immediatly */ -void HBStartRip( HBHandle *, HBTitle * ); - -/* Suspend rip */ -void HBPauseRip( HBHandle * ); - -/* Resume rip */ -void HBResumeRip( HBHandle * ); - -/* Cancel rip. Returns immediatly - you'll be noticed by the ripDone - callback when it's really stopped. - If the rip was paused, you _must_ call HBResumeRip() first. */ -void HBStopRip( HBHandle * ); - -/* Calculate preview for the specified picture of the specified title, - taking care of the current cropping & scaling settings. Returns a - pointer to raw RGBA data that _has_ to be freed by the calling - function. The picture includes the white border around the picture, - so its size is ( maxWidth + 2 ) x ( maxHeight + 2 ). - The data belongs to the caller, who must free it. */ -uint8_t * HBGetPreview( HBHandle *, HBTitle *, int picture ); - -/* Clean up things */ -void HBClose( HBHandle ** ); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/core/Jamfile b/core/Jamfile deleted file mode 100644 index 3c683531b..000000000 --- a/core/Jamfile +++ /dev/null @@ -1,39 +0,0 @@ -# $Id: Jamfile,v 1.12 2004/04/27 19:42:24 titer Exp $ -# -# This file is part of the HandBrake source code. -# Homepage: <http://handbrake.m0k.org/>. -# It may be used under the terms of the GNU General Public License. - -SubDir TOP core ; - -LIBHB_SRC = - Ac3Dec.c AviMux.c DVDRead.c FaacEnc.c FfmpegEnc.c Fifo.c HandBrake.c - LpcmDec.c Mp3Enc.c Mp4Mux.c Mpeg2Dec.c MpgaDec.c Mux.c OgmMux.c - Resample.c Scale.c Scan.c Thread.c Utils.c VorbisEnc.c Work.c - X264Enc.c XvidEnc.c ; - -Library libhb : $(LIBHB_SRC) ; - -# Sadly, we might want to debug our code -ObjectCcFlags $(LIBHB_SRC) : -g -Wall -W ; - -# Needed includes -ObjectHdrs Ac3Dec.c : $(TOP)/contrib/liba52 ; -ObjectHdrs FfmpegEnc.c - HandBrake.c - MpgaDec.c - Scale.c : $(TOP)/contrib/libavcodec ; -ObjectHdrs DVDRead.c - Scan.c : $(TOP)/contrib/libdvdread ; -ObjectHdrs FaacEnc.c : $(TOP)/contrib/libfaac ; -ObjectHdrs Mp3Enc.c : $(TOP)/contrib/libmp3lame ; -ObjectHdrs Mp4Mux.c : $(TOP)/contrib/libmp4v2 ; -ObjectHdrs Mpeg2Dec.c - Scan.c : $(TOP)/contrib/libmpeg2 ; -ObjectHdrs Resample.c : $(TOP)/contrib/libsamplerate ; -ObjectHdrs OgmMux.c - VorbisEnc.c : $(TOP)/contrib/libogg ; -ObjectHdrs VorbisEnc.c : $(TOP)/contrib/libvorbis ; -ObjectHdrs X264Enc.c : $(TOP)/contrib/libx264 ; -ObjectHdrs XvidEnc.c : $(TOP)/contrib/libxvidcore ; - diff --git a/core/LpcmDec.c b/core/LpcmDec.c deleted file mode 100644 index 425f429d9..000000000 --- a/core/LpcmDec.c +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id: LpcmDec.c,v 1.10 2004/05/10 16:50:32 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBAudio * audio; - - int initDone; -}; - -/* Local prototypes */ -static int LpcmDecWork( HBWork * ); - -HBWork * HBLpcmDecInit( HBHandle * handle, HBAudio * audio ) -{ - HBWork * w; - if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) - { - HBLog( "HBLpcmDecInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "LpcmDec" ); - w->work = LpcmDecWork; - - w->handle = handle; - w->audio = audio; - - return w; -} - -void HBLpcmDecClose( HBWork ** _w ) -{ - HBWork * w = *_w; - free( w->name ); - free( w ); - *_w = NULL; -} - -static int LpcmDecWork( HBWork * w ) -{ - HBAudio * audio = w->audio; - - HBBuffer * lpcmBuffer; - HBBuffer * rawBuffer; - uint8_t * samples_u8; - float * samples_f; - int samples_nr, i; - - if( HBFifoIsHalfFull( audio->rawFifo ) ) - { - return 0; - } - - /* Get a new LPCM buffer */ - lpcmBuffer = HBFifoPop( audio->inFifo ); - if( !lpcmBuffer ) - { - return 0; - } - - if( !w->initDone ) - { - /* SampleRate */ - switch( ( lpcmBuffer->data[4] >> 4 ) & 0x3 ) - { - case 0: - audio->inSampleRate = 48000; - break; - case 1: - audio->inSampleRate = 32000; - break; - default: - HBLog( "HBLpcmDec: unknown samplerate (%d)", - ( lpcmBuffer->data[4] >> 4 ) & 0x3 ); - } - - /* We hope there are 2 channels */ - HBLog( "HBLpcmDec: samplerate: %d Hz, channels: %d", - audio->inSampleRate, ( lpcmBuffer->data[4] & 0x7 ) + 1 ); - - w->initDone = 1; - } - - if( lpcmBuffer->data[5] != 0x80 ) - { - HBLog( "HBLpcmDec: no frame sync (%02x)", lpcmBuffer->data[5] ); - } - - /* Allocate raw buffer */ - samples_nr = ( lpcmBuffer->size - 6 ) / sizeof( int16_t ); - rawBuffer = HBBufferInit( samples_nr * sizeof( float ) ); - rawBuffer->position = lpcmBuffer->position; - - /* Big endian int16 -> float conversion (happy casting) */ - samples_u8 = lpcmBuffer->data + 6; - samples_f = rawBuffer->dataf; - for( i = 0; i < samples_nr; i++ ) - { - samples_f[0] = (float) (int16_t) - ( ( ( (uint16_t) samples_u8[0] ) << 8 ) + - (uint16_t) samples_u8[1] ); - samples_u8 += 2; - samples_f += 1; - } - - HBBufferClose( &lpcmBuffer ); - - if( !HBFifoPush( audio->rawFifo, &rawBuffer ) ) - { - HBLog( "HBLpcmDec: HBFifoPush failed" ); - } - - return 1; -} - diff --git a/core/Mp3Enc.c b/core/Mp3Enc.c deleted file mode 100644 index c1aae34fe..000000000 --- a/core/Mp3Enc.c +++ /dev/null @@ -1,138 +0,0 @@ -/* $Id: Mp3Enc.c,v 1.23 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* libmp3lame */ -#include "lame/lame.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBAudio * audio; - lame_global_flags * globalFlags; -}; - -/* Local prototypes */ -static int Mp3EncWork( HBWork * ); - -HBWork * HBMp3EncInit( HBHandle * handle, HBAudio * audio ) -{ - HBWork * w; - if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) - { - HBLog( "HBMp3EncInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "Mp3Enc" ); - w->work = Mp3EncWork; - - w->handle = handle; - w->audio = audio; - - return w; -} - -void HBMp3EncClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - if( w->globalFlags ) lame_close( w->globalFlags ); - - free( w->name ); - free( w ); - *_w = NULL; -} - -static int Mp3EncWork( HBWork * w ) -{ - HBAudio * audio = w->audio; - - HBBuffer * mp3Buffer; - int ret; - - float samples_f[1152 * 2]; - int16_t samples_s16[1152 * 2]; - float position; - int i; - - if( !w->globalFlags ) - { - if( !HBFifoSize( audio->resampleFifo ) ) - { - return 0; - } - - HBLog( "HBMp3Enc: opening lame (%d kbps)", audio->outBitrate ); - - w->globalFlags = lame_init(); - lame_set_brate( w->globalFlags, audio->outBitrate ); - - /* No resampling there - it's been done before */ - lame_set_in_samplerate( w->globalFlags, audio->outSampleRate ); - lame_set_out_samplerate( w->globalFlags, audio->outSampleRate ); - - if( lame_init_params( w->globalFlags ) == -1 ) - { - HBLog( "HBMp3Enc: lame_init_params() failed" ); - HBErrorOccured( w->handle, HB_ERROR_MP3_INIT ); - return 0; - } - } - - if( HBFifoIsHalfFull( audio->outFifo ) ) - { - return 0; - } - - if( !HBFifoGetBytes( audio->resampleFifo, (uint8_t*) samples_f, - 1152 * 2 * sizeof( float ), &position ) ) - { - return 0; - } - - /* float -> s16 */ - for( i = 0; i < 1152 * 2; i++ ) - { - samples_s16[i] = samples_f[i]; - } - - mp3Buffer = HBBufferInit( LAME_MAXMP3BUFFER ); - ret = lame_encode_buffer_interleaved( w->globalFlags, - samples_s16, 1152, mp3Buffer->data, LAME_MAXMP3BUFFER ); - - if( ret < 0 ) - { - /* Error */ - HBLog( "HBMp3Enc: lame_encode_buffer_float() failed (%d)", - ret ); - HBErrorOccured( w->handle, HB_ERROR_MP3_ENCODE ); - HBBufferClose( &mp3Buffer ); - } - else if( ret == 0 ) - { - /* No error, but nothing encoded */ - HBBufferClose( &mp3Buffer ); - } - else - { - /* Encoding was successful */ - mp3Buffer->size = ret; - mp3Buffer->keyFrame = 1; - mp3Buffer->position = position; - - if( !HBFifoPush( audio->outFifo, &mp3Buffer ) ) - { - HBLog( "HBMp3Enc: HBFifoPush failed" ); - } - } - - return 1; -} - diff --git a/core/Mp4Mux.c b/core/Mp4Mux.c deleted file mode 100644 index d48c1adc6..000000000 --- a/core/Mp4Mux.c +++ /dev/null @@ -1,197 +0,0 @@ -/* $Id: Mp4Mux.c,v 1.31 2004/05/13 21:10:56 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* libmp4v2 */ -#include "mp4.h" - -struct HBMux -{ - HB_MUX_COMMON_MEMBERS - - HBHandle * handle; - HBTitle * title; - - MP4FileHandle file; - - /* QuickTime sync workaround */ - int sampleRate; - uint64_t frames; - uint64_t date; - -}; - -typedef struct -{ - int track; - -} Mp4MuxData; - -/* Local prototypes */ -static int Mp4Start( HBMux * ); -static int Mp4MuxVideo( HBMux *, void *, HBBuffer *); -static int Mp4MuxAudio( HBMux *, void *, HBBuffer *); -static int Mp4End( HBMux * ); - -HBMux * HBMp4MuxInit( HBHandle * handle, HBTitle * title ) -{ - HBMux * m; - HBAudio * audio; - int i; - - if( !( m = calloc( sizeof( HBMux ), 1 ) ) ) - { - HBLog( "HBMp4Mux: malloc() failed, gonna crash" ); - return NULL; - } - m->start = Mp4Start; - m->muxVideo = Mp4MuxVideo; - m->muxAudio = Mp4MuxAudio; - m->end = Mp4End; - - m->handle = handle; - m->title = title; - - /* Alloc muxer data */ - title->muxData = calloc( sizeof( Mp4MuxData ), 1 ); - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - audio->muxData = calloc( sizeof( Mp4MuxData ), 1 ); - } - - return m; -} - -void HBMp4MuxClose( HBMux ** _m ) -{ - HBMux * m = *_m; - HBTitle * title = m->title; - HBAudio * audio; - int i; - - /* Free muxer data */ - free( title->muxData ); - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - free( audio->muxData ); - } - - free( m ); - *_m = NULL; -} - -static int Mp4Start( HBMux * m ) -{ - HBTitle * title = m->title; - HBAudio * audio; - Mp4MuxData * muxData; - int i; - - /* Create file */ - m->file = MP4Create( title->file, 0, 0 ); - - /* Add video track */ - muxData = (Mp4MuxData *) title->muxData; - if( HBListCount( title->ripAudioList ) ) - { - /* QuickTime sync workaround */ - audio = (HBAudio *) HBListItemAt( title->ripAudioList, 0 ); - m->sampleRate = audio->outSampleRate; - MP4SetTimeScale( m->file, m->sampleRate ); - muxData->track = MP4AddVideoTrack( m->file, m->sampleRate, - MP4_INVALID_DURATION, title->outWidth, title->outHeight, - MP4_MPEG4_VIDEO_TYPE ); - } - else - { - MP4SetTimeScale( m->file, 90000 ); - muxData->track = MP4AddVideoTrack( m->file, 90000, - (uint64_t) 90000 * title->rateBase / title->rate, - title->outWidth, title->outHeight, - MP4_MPEG4_VIDEO_TYPE ); - } - MP4SetVideoProfileLevel( m->file, 0x03 ); - MP4SetTrackESConfiguration( m->file, muxData->track, - title->esConfig, title->esConfigLength ); - - /* Add audio tracks */ - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - muxData = (Mp4MuxData *) audio->muxData; - muxData->track = MP4AddAudioTrack( m->file, - audio->outSampleRate, 1024, MP4_MPEG4_AUDIO_TYPE ); - MP4SetAudioProfileLevel( m->file, 0x0F ); - MP4SetTrackESConfiguration( m->file, muxData->track, - audio->esConfig, audio->esConfigLength ); - } - - return 0; -} - -static int Mp4MuxVideo( HBMux * m, void * _muxData, HBBuffer * buffer ) -{ - Mp4MuxData * muxData = (Mp4MuxData *) _muxData; - HBTitle * title = m->title; - - if( HBListCount( title->ripAudioList ) ) - { - /* QuickTime sync workaround */ - int dur = (uint64_t) m->sampleRate * ( ++m->frames ) * - title->rateBase / title->rate - m->date; - MP4WriteSample( m->file, muxData->track, buffer->data, buffer->size, - dur, 0, buffer->keyFrame ); - m->date += dur; - } - else - { - MP4WriteSample( m->file, muxData->track, buffer->data, - buffer->size, MP4_INVALID_DURATION, 0, - buffer->keyFrame ); - } - return 0; -} - -static int Mp4MuxAudio( HBMux * m, void * _muxData, HBBuffer * buffer ) -{ - Mp4MuxData * muxData = (Mp4MuxData *) _muxData; - - MP4WriteSample( m->file, muxData->track, buffer->data, buffer->size, - MP4_INVALID_DURATION, 0, buffer->keyFrame ); - return 0; -} - -static int Mp4End( HBMux * m ) -{ - HBTitle * title = m->title; - char tmpFile[1024]; - - MP4Close( m->file ); - - HBLog( "HBMp4Mux: making the file ISMA compliant" ); - if( !MP4MakeIsmaCompliant( title->file, 0 /*MP4_DETAILS_ALL*/, 1 ) ) - { - HBLog( "HBMp4Mux: MP4MakeIsmaCompliant() failed" ); - } - - HBLog( "HBMp4Mux: optimizing" ); - sprintf( tmpFile, "%s.tmp", title->file ); - tmpFile[strlen( title->file ) + 4] = '\0'; - if( !MP4Optimize( title->file, tmpFile, 0 /*MP4_DETAILS_ALL*/ ) ) - { - HBLog( "HBMp4Mux: MP4Optimize() failed" ); - unlink( tmpFile ); - } - else - { - rename( tmpFile, title->file ); - } - return 0; -} - diff --git a/core/Mpeg2Dec.c b/core/Mpeg2Dec.c deleted file mode 100644 index 043c416dc..000000000 --- a/core/Mpeg2Dec.c +++ /dev/null @@ -1,160 +0,0 @@ -/* $Id: Mpeg2Dec.c,v 1.15 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#include "mpeg2dec/mpeg2.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBTitle * title; - int pass; - mpeg2dec_t * libmpeg2; - const mpeg2_info_t * info; - int lateField; -}; - -/* Local prototypes */ -static int Mpeg2DecWork( HBWork * ); - -HBWork * HBMpeg2DecInit( HBHandle * handle, HBTitle * title ) -{ - HBWork * w ; - if( !( w = malloc( sizeof( HBWork ) ) ) ) - { - HBLog( "HBMpeg2Dec: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "Mpeg2Dec" ); - w->work = Mpeg2DecWork; - - w->handle = handle; - w->title = title; - - w->pass = 42; - w->libmpeg2 = NULL; - w->info = NULL; - w->lateField = 0; - - return w; -} - -void HBMpeg2DecClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - if( w->libmpeg2 ) - { - HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", w->pass ); - mpeg2_close( w->libmpeg2 ); - } - free( w->name ); - free( w ); - - *_w = NULL; -} - -static int Mpeg2DecWork( HBWork * w ) -{ - HBTitle * title = w->title; - HBBuffer * mpeg2Buffer; - HBBuffer * rawBuffer; - mpeg2_state_t state; - - if( HBFifoIsHalfFull( title->rawFifo ) ) - { - return 0; - } - - /* Get a new buffer to decode */ - if( !( mpeg2Buffer = HBFifoPop( title->inFifo ) ) ) - { - return 0; - } - - /* Init or re-init if needed */ - if( mpeg2Buffer->pass != w->pass ) - { - if( w->libmpeg2 ) - { - HBLog( "HBMpeg2Dec: closing libmpeg2 (pass %d)", w->pass ); - mpeg2_close( w->libmpeg2 ); - } - - w->pass = mpeg2Buffer->pass; - - HBLog( "HBMpeg2Dec: opening libmpeg2 (pass %d)", w->pass ); -#ifdef HB_NOMMX - mpeg2_accel( 0 ); -#endif - w->libmpeg2 = mpeg2_init(); - w->info = mpeg2_info( w->libmpeg2 ); - w->lateField = 0; - } - - /* Decode */ - mpeg2_buffer( w->libmpeg2, mpeg2Buffer->data, - mpeg2Buffer->data + mpeg2Buffer->size ); - - for( ;; ) - { - state = mpeg2_parse( w->libmpeg2 ); - - if( state == STATE_BUFFER ) - { - break; - } - else if( ( state == STATE_SLICE || state == STATE_END ) && - w->info->display_fbuf ) - { - rawBuffer = HBBufferInit( 3 * title->inWidth * - title->inHeight ); - - /* TODO: make libmpeg2 write directly in our buffer */ - memcpy( rawBuffer->data, w->info->display_fbuf->buf[0], - title->inWidth * title->inHeight ); - memcpy( rawBuffer->data + title->inWidth * title->inHeight, - w->info->display_fbuf->buf[1], - title->inWidth * title->inHeight / 4 ); - memcpy( rawBuffer->data + title->inWidth * title->inHeight + - title->inWidth * title->inHeight / 4, - w->info->display_fbuf->buf[2], - title->inWidth * title->inHeight / 4 ); - - rawBuffer->position = mpeg2Buffer->position; - rawBuffer->pass = mpeg2Buffer->pass; - - /* NTSC pulldown kludge */ - if( w->info->display_picture->nb_fields == 3 ) - { - rawBuffer->repeat = w->lateField; - w->lateField = !w->lateField; - } - else - { - rawBuffer->repeat = 0; - } - - if( !HBFifoPush( title->rawFifo, &rawBuffer ) ) - { - HBLog( "HBMpeg2Dec: HBFifoPush failed" ); - } - } - else if( state == STATE_INVALID ) - { - /* Shouldn't happen on a DVD */ - HBLog( "HBMpeg2Dec: STATE_INVALID" ); - } - } - - HBBufferClose( &mpeg2Buffer ); - - return 1; -} diff --git a/core/MpgaDec.c b/core/MpgaDec.c deleted file mode 100644 index e397a7234..000000000 --- a/core/MpgaDec.c +++ /dev/null @@ -1,132 +0,0 @@ -/* $Id: MpgaDec.c,v 1.3 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#include "ffmpeg/avcodec.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBAudio * audio; - - AVCodecContext * context; -}; - -/* Local prototypes */ -static int MpgaDecWork( HBWork * ); - -HBWork * HBMpgaDecInit( HBHandle * handle, HBAudio * audio ) -{ - HBWork * w; - AVCodec * codec; - - if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) - { - HBLog( "HBMpgaDecInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "MpgaDec" ); - w->work = MpgaDecWork; - - w->handle = handle; - w->audio = audio; - - codec = avcodec_find_decoder( CODEC_ID_MP2 ); - if( !codec ) - { - HBLog( "HBMpgaDec: avcodec_find_decoder failed" ); - } - - w->context = avcodec_alloc_context(); - if( !w->context ) - { - HBLog( "HBMpgaDec: avcodec_alloc_context failed" ); - } - - if( avcodec_open( w->context, codec ) < 0 ) - { - HBLog( "HBMpgaDec: avcodec_open failed" ); - } - - return w; -} - -void HBMpgaDecClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - avcodec_close( w->context ); - free( w->name ); - free( w ); - *_w = NULL; -} - -static int MpgaDecWork( HBWork * w ) -{ - HBAudio * audio = w->audio; - - HBBuffer * mpgaBuffer; - HBBuffer * rawBuffer; - - int out_size, len, pos; - short buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; - - if( HBFifoIsHalfFull( audio->rawFifo ) ) - { - return 0; - } - - /* Get a new mpeg buffer */ - mpgaBuffer = HBFifoPop( audio->inFifo ); - if( !mpgaBuffer ) - { - return 0; - } - - pos = 0; - while( pos < mpgaBuffer->size ) - { - len = avcodec_decode_audio( w->context, buffer, &out_size, - mpgaBuffer->data + pos, - mpgaBuffer->size - pos ); - pos += len; - - if( !audio->inSampleRate ) - { - audio->inSampleRate = w->context->sample_rate; - HBLog( "HBMpgaDec: samplerate = %d", audio->inSampleRate ); - } - - if( out_size ) - { - int i; - rawBuffer = HBBufferInit( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE ); - rawBuffer->position = mpgaBuffer->position; - - /* s16 -> float */ - for( i = 0; i < out_size / 2; i++ ) - { - rawBuffer->dataf[i] = buffer[i]; - } - - rawBuffer->size = out_size * 2; - - if( !HBFifoPush( audio->rawFifo, &rawBuffer ) ) - { - HBLog( "HBMpgaDec: HBFifoPush failed" ); - } - } - } - - HBBufferClose( &mpgaBuffer ); - - return 1; -} - diff --git a/core/Mux.c b/core/Mux.c deleted file mode 100644 index c9449e7ff..000000000 --- a/core/Mux.c +++ /dev/null @@ -1,228 +0,0 @@ -/* $Id: Mux.c,v 1.9 2004/05/25 17:36:40 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include <sys/types.h> -#include <sys/stat.h> - -#include "HBInternal.h" - -HBMux * HBAviMuxInit( HBHandle * handle, HBTitle * title ); -void HBAviMuxClose( HBMux ** ); -HBMux * HBMp4MuxInit( HBHandle * handle, HBTitle * title ); -void HBMp4MuxClose( HBMux ** ); -HBMux * HBOgmMuxInit( HBHandle * handle, HBTitle * title ); -void HBOgmMuxClose( HBMux ** ); - -/* Local prototypes */ -static void MuxThread( void * t ); - -struct HBMux -{ - HB_MUX_COMMON_MEMBERS -}; - -struct HBMuxThread -{ - HBHandle * handle; - HBTitle * title; - HBMux * mux; - - uint64_t videoFrames; - uint64_t videoBytes; - uint64_t audioFrames; - uint64_t audioBytes; - - volatile int die; - HBThread * thread; -}; - -HBMuxThread * HBMuxThreadInit( HBHandle * handle, HBTitle * title ) -{ - HBMuxThread * t; - if( !( t = calloc( sizeof( HBMuxThread ), 1 ) ) ) - { - HBLog( "HBMuxThreadInit: malloc() failed, gonna crash" ); - return NULL; - } - t->handle = handle; - t->title = title; - - /* Init muxer */ - if( title->mux == HB_MUX_AVI ) - t->mux = HBAviMuxInit( handle, title ); - else if( title->mux == HB_MUX_MP4 ) - t->mux = HBMp4MuxInit( handle, title ); - else if( title->mux == HB_MUX_OGM ) - t->mux = HBOgmMuxInit( handle, title ); - - /* Launch the thread */ - t->thread = HBThreadInit( "mux thread", MuxThread, t, - HB_NORMAL_PRIORITY ); - - return t; -} - -void HBMuxThreadClose( HBMuxThread ** _t ) -{ - HBMuxThread * t = (*_t); - HBTitle * title = t->title; - struct stat sb; - - /* Stop the thread */ - t->die = 1; - HBThreadClose( &t->thread ); - - /* Close muxer */ - if( title->mux == HB_MUX_AVI ) - HBAviMuxClose( &t->mux ); - else if( title->mux == HB_MUX_MP4 ) - HBMp4MuxClose( &t->mux ); - else if( title->mux == HB_MUX_OGM ) - HBOgmMuxClose( &t->mux ); - - /* Stats */ - if( !stat( title->file, &sb ) ) - { - uint64_t overhead; - HBAudio * audio; - - overhead = (uint64_t) sb.st_size - t->videoBytes - t->audioBytes; - HBLog( "HBMuxThread: file size: "LLD" bytes", - (uint64_t) sb.st_size ); - HBLog( "HBMuxThread: video data: "LLD" bytes ("LLD" frames)", - t->videoBytes, t->videoFrames ); - HBLog( "HBMuxThread: audio data: "LLD" bytes ("LLD" frames)", - t->audioBytes, t->audioFrames ); - HBLog( "HBMuxThread: overhead: "LLD" bytes (%.2f bytes per " - "frame)", overhead, (float) overhead / ( t->videoFrames + - t->audioFrames ) ); - - HBLog( "HBMuxThread: video bitrate: %.2f kbps", - (float) t->videoBytes * title->rate / t->videoFrames / - title->rateBase / 128 ); - HBLog( "HBMuxThread: video error: "LLD" bytes", t->videoBytes - - t->videoFrames * title->bitrate * 128 * title->rateBase / - title->rate ); - - /* FIXME - handle multi-audio encoding */ - audio = (HBAudio *) HBListItemAt( title->ripAudioList, 0 ); - if( audio ) - { - int samplesPerFrame = ( audio->outCodec == HB_CODEC_MP3 ? - 1152 : 1024 ); - HBLog( "HBMuxThread: audio bitrate: %.2f kbps", - (float) t->audioBytes * audio->outSampleRate / - t->audioFrames / samplesPerFrame / 125 ); - HBLog( "HBMuxThread: audio error: "LLD" bytes", - t->audioBytes - audio->outBitrate * t->audioFrames * - 125 * samplesPerFrame / audio->outSampleRate ); - } - } - - free( t ); - - *_t = NULL; -} - -static int MuxWait( HBTitle * title ) -{ - int i; - HBAudio * audio; - - if( !HBFifoWait( title->outFifo ) ) - { - return 0; - } - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - if( !HBFifoWait( audio->outFifo ) ) - { - return 0; - } - } - return 1; -} - -static void MuxThread( void * _t ) -{ - HBMuxThread * t = (HBMuxThread*) _t; - HBTitle * title = t->title; - HBMux * m = t->mux; - HBAudio * audio; - HBBuffer * buffer; - int i; - - /* Remove the file if already existing */ - unlink( title->file ); - - /* Wait until we have at least one video frame and 3 audio frames - for each track (Vorbis...) */ - if( !HBFifoWait( title->outFifo ) ) - { - return; - } - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - while( !t->die && HBFifoSize( audio->outFifo ) < 3 ) - { - HBSnooze( 10000 ); - } - if( t->die ) - { - return; - } - } - - m->start( m ); - - /* Mux */ - for( ;; ) - { - /* Wait until we have one frame for each track */ - if( !MuxWait( title ) ) - { - break; - } - - /* Interleave frames in the same order than they were in the - original MPEG stream */ - audio = NULL; - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - HBAudio * otherAudio; - otherAudio = HBListItemAt( title->ripAudioList, i ); - if( !audio || HBFifoPosition( otherAudio->outFifo ) < - HBFifoPosition( audio->outFifo ) ) - { - audio = otherAudio; - } - } - if( !audio || HBFifoPosition( title->outFifo ) < - HBFifoPosition( audio->outFifo ) ) - { - /* Video */ - buffer = HBFifoPop( title->outFifo ); - m->muxVideo( m, title->muxData, buffer ); - t->videoBytes += buffer->size; - t->videoFrames++; - HBBufferClose( &buffer ); - } - else - { - /* Audio */ - buffer = HBFifoPop( audio->outFifo ); - m->muxAudio( m, audio->muxData, buffer ); - t->audioBytes += buffer->size; - t->audioFrames++; - HBBufferClose( &buffer ); - } - } - - m->end( m ); -} - diff --git a/core/Mux.h b/core/Mux.h deleted file mode 100644 index fbd1fd98f..000000000 --- a/core/Mux.h +++ /dev/null @@ -1,21 +0,0 @@ -/* $Id: Mux.h,v 1.2 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_MUX_H -#define HB_MUX_H - -#define HB_MUX_COMMON_MEMBERS \ - int (*start) ( HBMux * ); \ - int (*muxVideo) ( HBMux *, void *, HBBuffer * ); \ - int (*muxAudio) ( HBMux *, void *, HBBuffer * ); \ - int (*end) ( HBMux * ); - -typedef struct HBMux HBMux; - -HBMuxThread * HBMuxThreadInit( HBHandle *, HBTitle * ); -void HBMuxThreadClose( HBMuxThread ** ); - -#endif diff --git a/core/OgmMux.c b/core/OgmMux.c deleted file mode 100644 index e99a494f5..000000000 --- a/core/OgmMux.c +++ /dev/null @@ -1,396 +0,0 @@ -/* $Id: OgmMux.c,v 1.13 2004/05/13 21:10:56 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#include <ogg/ogg.h> - -static int OgmStart( HBMux * ); -static int OgmMux( HBMux *, void *, HBBuffer * ); -static int OgmEnd( HBMux * ); - -struct HBMux -{ - HB_MUX_COMMON_MEMBERS - - HBHandle * handle; - HBTitle * title; - FILE * file; -}; - -typedef struct -{ - int codec; - ogg_stream_state os; - int i_packet_no; - -} OgmMuxData; - -typedef struct __attribute__((__packed__)) -{ - uint8_t i_packet_type; - - char stream_type[8]; - char sub_type[4]; - - int32_t i_size; - - int64_t i_time_unit; - int64_t i_samples_per_unit; - int32_t i_default_len; - - int32_t i_buffer_size; - int16_t i_bits_per_sample; - int16_t i_padding_0; // hum hum - union - { - struct - { - int32_t i_width; - int32_t i_height; - - } video; - struct - { - int16_t i_channels; - int16_t i_block_align; - int32_t i_avgbytespersec; - } audio; - } header; - -} ogg_stream_header_t; - -#define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v) -static void _SetWLE( uint8_t *p, uint16_t i_dw ) -{ - p[1] = ( i_dw >> 8 )&0xff; - p[0] = ( i_dw )&0xff; -} - -#define SetDWLE( p, v ) _SetDWLE( (uint8_t*)p, v) -static void _SetDWLE( uint8_t *p, uint32_t i_dw ) -{ - p[3] = ( i_dw >> 24 )&0xff; - p[2] = ( i_dw >> 16 )&0xff; - p[1] = ( i_dw >> 8 )&0xff; - p[0] = ( i_dw )&0xff; -} -#define SetQWLE( p, v ) _SetQWLE( (uint8_t*)p, v) -static void _SetQWLE( uint8_t *p, uint64_t i_qw ) -{ - SetDWLE( p, i_qw&0xffffffff ); - SetDWLE( p+4, ( i_qw >> 32)&0xffffffff ); -} - -HBMux * HBOgmMuxInit( HBHandle * handle, HBTitle * title ) -{ - HBMux * m; - HBAudio * audio; - int i; - - if( !( m = calloc( sizeof( HBMux ), 1 ) ) ) - { - HBLog( "HBOgmMux: malloc failed, gonna crash" ); - return NULL; - } - m->start = OgmStart; - m->muxVideo = OgmMux; - m->muxAudio = OgmMux; - m->end = OgmEnd; - - m->handle = handle; - m->title = title; - - /* Alloc muxer data */ - title->muxData = calloc( sizeof( OgmMuxData ), 1 ); - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - audio->muxData = calloc( sizeof( OgmMuxData ), 1 ); - } - - return m; -} - -void HBOgmMuxClose( HBMux ** _m ) -{ - HBMux * m = *_m; - HBTitle * title = m->title; - HBAudio * audio; - int i; - - /* Free muxer data */ - free( title->muxData ); - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - free( audio->muxData ); - } - - free( m ); - *_m = NULL; -} - -static int OgmFlush( HBMux * m, OgmMuxData * muxData ) -{ - for( ;; ) - { - ogg_page og; - if( ogg_stream_flush( &muxData->os, &og ) == 0 ) - { - break; - } - if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || - fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) - { - return -1; - } - } - return 0; -} - -static int OgmStart( HBMux * m ) -{ - HBTitle * title = m->title; - HBAudio * audio; - OgmMuxData * muxData; - ogg_packet op; - ogg_stream_header_t h; - int i; - - /* Open output file */ - if( ( m->file = fopen( title->file, "wb" ) ) == NULL ) - { - HBLog( "HBOgmMux: failed to open `%s'", title->file ); - /* FIXME */ - HBErrorOccured( m->handle, HB_ERROR_AVI_WRITE ); - return -1; - } - HBLog( "HBOgmMux: `%s' opened", title->file ); - - /* Init tracks */ - - /* Video */ - muxData = (OgmMuxData *) title->muxData; - muxData->codec = title->codec; - muxData->i_packet_no = 0; - ogg_stream_init( &muxData->os, 0 ); - - /* Audio */ - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - HBAudio * audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - muxData = (OgmMuxData *) audio->muxData; - - muxData->codec = audio->outCodec; - muxData->i_packet_no = 0; - ogg_stream_init( &muxData->os, i + 1 ); - - } - - /* First pass: all b_o_s packets */ - - /* Video */ - muxData = (OgmMuxData *) title->muxData; - memset( &h, 0, sizeof( ogg_stream_header_t ) ); - h.i_packet_type = 0x01; - memcpy( h.stream_type, "video ", 8 ); - if( muxData->codec == HB_CODEC_X264 ) - { - memcpy( h.sub_type, "H264", 4 ); - } - else - { - memcpy( h.sub_type, "XVID", 4 ); - } - SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); - SetQWLE( &h.i_time_unit, (int64_t)10*1000*1000*(int64_t)title->rateBase/(int64_t)title->rate ); - SetQWLE( &h.i_samples_per_unit, 1 ); - SetDWLE( &h.i_default_len, 0 ); - SetDWLE( &h.i_buffer_size, 1024*1024 ); - SetWLE ( &h.i_bits_per_sample, 0 ); - SetDWLE( &h.header.video.i_width, title->outWidth ); - SetDWLE( &h.header.video.i_height, title->outHeight ); - op.packet = (char*)&h; - op.bytes = sizeof( ogg_stream_header_t ); - op.b_o_s = 1; - op.e_o_s = 0; - op.granulepos = 0; - op.packetno = muxData->i_packet_no++; - ogg_stream_packetin( &muxData->os, &op ); - OgmFlush( m, muxData ); - - /* Audio */ - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - muxData = (OgmMuxData *) audio->muxData; - memset( &h, 0, sizeof( ogg_stream_header_t ) ); - switch( muxData->codec ) - { - case HB_CODEC_MP3: - { - h.i_packet_type = 0x01; - memcpy( h.stream_type, "audio ", 8 ); - memcpy( h.sub_type, "55 ", 4 ); - - SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); - SetQWLE( &h.i_time_unit, 0 ); - SetQWLE( &h.i_samples_per_unit, audio->outSampleRate ); - SetDWLE( &h.i_default_len, 1 ); - SetDWLE( &h.i_buffer_size, 30*1024 ); - SetWLE ( &h.i_bits_per_sample, 0 ); - - SetDWLE( &h.header.audio.i_channels, 2 ); - SetDWLE( &h.header.audio.i_block_align, 0 ); - SetDWLE( &h.header.audio.i_avgbytespersec, - audio->outBitrate / 8 ); - - op.packet = (char*)&h; - op.bytes = sizeof( ogg_stream_header_t ); - op.b_o_s = 1; - op.e_o_s = 0; - op.granulepos = 0; - op.packetno = muxData->i_packet_no++; - ogg_stream_packetin( &muxData->os, &op ); - break; - } - case HB_CODEC_VORBIS: - { - HBBuffer *h = HBFifoPop( audio->outFifo ); - - memcpy( &op, h->data, sizeof( ogg_packet ) ); - op.packet = h->data + sizeof( ogg_packet ); - ogg_stream_packetin( &muxData->os, &op ); - break; - } - default: - HBLog( "HBOgmMux: unhandled codec" ); - break; - } - OgmFlush( m, muxData ); - } - - /* second pass: all non b_o_s packets */ - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - if( audio->outCodec == HB_CODEC_VORBIS ) - { - HBBuffer *h; - int j; - muxData = (OgmMuxData *) audio->muxData; - - for( j = 0; j < 2; j++ ) - { - h = HBFifoPop( audio->outFifo ); - - memcpy( &op, h->data, sizeof( ogg_packet ) ); - op.packet = h->data + sizeof( ogg_packet ); - ogg_stream_packetin( &muxData->os, &op ); - - OgmFlush( m, muxData ); - } - } - } - - HBLog( "HBOgmMux: headers written" ); - return 0; -} - -static int OgmMux( HBMux * m, void * _muxData, HBBuffer * buffer ) -{ - OgmMuxData * muxData = (OgmMuxData *) _muxData; - ogg_packet op; - - switch( muxData->codec ) - { - case HB_CODEC_FFMPEG: - case HB_CODEC_XVID: - case HB_CODEC_X264: - op.bytes = buffer->size + 1; - op.packet = malloc( op.bytes ); - op.packet[0] = buffer->keyFrame ? 0x08 : 0x00; - memcpy( &op.packet[1], buffer->data, buffer->size ); - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = muxData->i_packet_no; - op.packetno = muxData->i_packet_no++; - break; - case HB_CODEC_MP3: - op.bytes = buffer->size + 1; - op.packet = malloc( op.bytes ); - op.packet[0] = 0x08; - memcpy( &op.packet[1], buffer->data, buffer->size ); - op.b_o_s = 0; - op.e_o_s = 0; - op.granulepos = muxData->i_packet_no * 1152; - op.packetno = muxData->i_packet_no++; - break; - case HB_CODEC_VORBIS: - memcpy( &op, buffer->data, sizeof( ogg_packet ) ); - op.packet = malloc( op.bytes ); - memcpy( op.packet, buffer->data + sizeof( ogg_packet ), op.bytes ); - break; - - default: - HBLog( "HBOgmMux: unhandled codec" ); - op.bytes = 0; - op.packet = NULL; - break; - } - - if( op.packet ) - { - ogg_stream_packetin( &muxData->os, &op ); - - for( ;; ) - { - ogg_page og; - if( ogg_stream_pageout( &muxData->os, &og ) == 0 ) - { - break; - } - - if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || - fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) - { - HBLog( "HBOgmMux: write failed" ); - break; - } - } - free( op.packet ); - } - return 0; -} - -static int OgmEnd( HBMux * m ) -{ - HBTitle * title = m->title; - HBAudio * audio; - OgmMuxData * muxData; - int i; - - muxData = (OgmMuxData *) title->muxData; - if( OgmFlush( m, muxData ) < 0 ) - { - return -1; - } - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = (HBAudio *) HBListItemAt( title->ripAudioList, i ); - muxData = (OgmMuxData *) audio->muxData; - if( OgmFlush( m, muxData ) < 0 ) - { - return -1; - } - } - - fclose( m->file ); - HBLog( "HBOgmMux: `%s' closed", title->file ); - return 0; -} - diff --git a/core/Resample.c b/core/Resample.c deleted file mode 100644 index f3632b371..000000000 --- a/core/Resample.c +++ /dev/null @@ -1,159 +0,0 @@ -/* $Id: Resample.c,v 1.4 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#include "samplerate.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBAudio * audio; - - float * samples; - SRC_STATE * state; - SRC_DATA data; - - uint64_t in; - uint64_t out; -}; - -/* Local prototypes */ -static int ResampleWork( HBWork * ); - -HBWork * HBResampleInit( HBHandle * handle, HBAudio * audio ) -{ - HBWork * w; - if( !( w = calloc( sizeof( HBWork ), 1 ) ) ) - { - HBLog( "HBResampleInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "Resample" ); - w->work = ResampleWork; - - w->handle = handle; - w->audio = audio; - - return w; -} - -void HBResampleClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - if( w->samples ) free( w->samples ); - if( w->state ) src_delete( w->state ); - - free( w->name ); - free( w ); - *_w = NULL; -} - -static int ResampleWork( HBWork * w ) -{ - HBAudio * audio = w->audio; - - HBBuffer * resampleBuffer; - float position; - - if( HBFifoIsHalfFull( audio->resampleFifo ) ) - { - return 0; - } - - /* Initialization */ - if( !w->samples ) - { - int error; - - /* Until a first packet comes, audio->inSampleRate is - undefined */ - if( !HBFifoSize( audio->rawFifo ) ) - { - return 0; - } - - /* No, the user can't choose. 44100 Hz, take it or leave it */ - audio->outSampleRate = 44100; - HBLog( "HBResample: in = %d Hz, out = %d Hz", - audio->inSampleRate, audio->outSampleRate ); - - /* Buffer in which we'll pop the samples from the decoder */ - w->samples = malloc( audio->inSampleRate * 2 * - sizeof( float ) / 10 ); - - /* Init libsamplerate */ - w->state = src_new( SRC_SINC_FASTEST, 2, &error ); - - /* Prepare the SRC_DATA structure */ - w->data.data_in = w->samples; - w->data.input_frames = audio->inSampleRate / 10; - w->data.output_frames = audio->outSampleRate / 10; - w->data.src_ratio = (double) audio->outSampleRate / - (double) audio->inSampleRate; - w->data.end_of_input = 0; - } - - /* Fix A/V synchro in case the audio track starts later than the - video */ - if( audio->delay > 0 ) - { - HBLog( "HBResample: adding %d ms of silence", audio->delay ); - - resampleBuffer = HBBufferInit( audio->delay * - audio->outSampleRate * 2 * sizeof( float ) / 1000 ); - memset( resampleBuffer->data, 0, resampleBuffer->size ); - if( !HBFifoPush( audio->resampleFifo, &resampleBuffer ) ) - { - HBLog( "HBResample: HBFifoPush failed" ); - } - - audio->delay = 0; - return 1; - } - - /* Get samples from the decoder */ - if( !HBFifoGetBytes( audio->rawFifo, (uint8_t *) w->samples, - audio->inSampleRate * 2 * sizeof( float ) / 10, - &position ) ) - { - return 0; - } - - /* Init resampled buffer */ - resampleBuffer = HBBufferInit( audio->outSampleRate * 2 * - sizeof( float ) / 10 ); - resampleBuffer->position = position; - - /* Resample */ - w->data.data_out = resampleBuffer->dataf; - if( src_process( w->state, &w->data ) ) - { - HBLog( "HBResample: src_process failed" ); - } - resampleBuffer->size = w->data.output_frames_gen * 2 * - sizeof( float ); - - if( w->data.input_frames_used != w->data.input_frames ) - { - /* Here we're basically f*cked */ - HBLog( "HBResample: ohoh, %d/%d used", - w->data.input_frames_used, w->data.input_frames ); - } - - /* Send resampled data to the encoder */ - if( !HBFifoPush( audio->resampleFifo, &resampleBuffer ) ) - { - HBLog( "HBResample: HBFifoPush failed" ); - } - - return 1; -} - diff --git a/core/Scale.c b/core/Scale.c deleted file mode 100644 index 2908d6456..000000000 --- a/core/Scale.c +++ /dev/null @@ -1,140 +0,0 @@ -/* $Id: Scale.c,v 1.14 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#include "ffmpeg/avcodec.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBTitle * title; - - HBBuffer * deintBuffer; - ImgReSampleContext * context; - AVPicture rawPicture; - AVPicture deintPicture; - AVPicture scaledPicture; -}; - -/* Local prototypes */ -static int ScaleWork( HBWork * ); - -HBWork * HBScaleInit( HBHandle * handle, HBTitle * title ) -{ - HBWork * w; - if( !( w = malloc( sizeof( HBWork ) ) ) ) - { - HBLog( "HBScaleInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "Scale" ); - w->work = ScaleWork; - - w->handle = handle; - w->title = title; - - /* Allocate a constant buffer used for deinterlacing */ - w->deintBuffer = HBBufferInit( 3 * title->inWidth * - title->inHeight / 2 ); - - avpicture_fill( &w->deintPicture, w->deintBuffer->data, - PIX_FMT_YUV420P, title->inWidth, title->inHeight ); - - /* Init libavcodec */ - w->context = - img_resample_full_init( title->outWidth, title->outHeight, - title->inWidth, title->inHeight, - title->topCrop, title->bottomCrop, - title->leftCrop, title->rightCrop ); - - return w; -} - -void HBScaleClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - img_resample_close( w->context ); - HBBufferClose( &w->deintBuffer ); - free( w->name ); - free( w ); - *_w = NULL; -} - -static int ScaleWork( HBWork * w ) -{ - HBTitle * title = w->title; - HBBuffer * rawBuffer; - HBBuffer * scaledBuffer; - HBBuffer * tmpBuffer; - - if( HBFifoIsHalfFull( title->scaledFifo ) ) - { - return 0; - } - - /* Get a new raw picture */ - if( !( rawBuffer = HBFifoPop( title->rawFifo ) ) ) - { - return 0; - } - - /* Allocate new buffer for the scaled picture */ - scaledBuffer = HBBufferInit( 3 * title->outWidth * - title->outHeight / 2 ); - scaledBuffer->position = rawBuffer->position; - scaledBuffer->pass = rawBuffer->pass; - - /* libavcodec stuff */ - avpicture_fill( &w->rawPicture, rawBuffer->data, PIX_FMT_YUV420P, - title->inWidth, title->inHeight ); - avpicture_fill( &w->scaledPicture, scaledBuffer->data, - PIX_FMT_YUV420P, title->outWidth, - title->outHeight ); - - /* Do the job */ - if( title->deinterlace ) - { - avpicture_deinterlace( &w->deintPicture, &w->rawPicture, - PIX_FMT_YUV420P, title->inWidth, - title->inHeight ); - img_resample( w->context, &w->scaledPicture, - &w->deintPicture ); - } - else - { - img_resample( w->context, &w->scaledPicture, &w->rawPicture ); - } - - if( rawBuffer->repeat ) - { - tmpBuffer = HBBufferInit( scaledBuffer->size ); - tmpBuffer->position = scaledBuffer->position; - tmpBuffer->pass = scaledBuffer->pass; - memcpy( tmpBuffer->data, scaledBuffer->data, - scaledBuffer->size ); - - if( !HBFifoPush( title->scaledFifo, &tmpBuffer ) ) - { - HBLog( "HBScale: HBFifoPush failed" ); - } - } - - if( !HBFifoPush( title->scaledFifo, &scaledBuffer ) ) - { - HBLog( "HBScale: HBFifoPush failed" ); - } - - /* Free memory */ - HBBufferClose( &rawBuffer ); - - return 1; -} - diff --git a/core/Scan.c b/core/Scan.c deleted file mode 100644 index 9315e59d0..000000000 --- a/core/Scan.c +++ /dev/null @@ -1,597 +0,0 @@ -/* $Id: Scan.c,v 1.26 2004/05/12 18:02:35 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" -#include "Languages.h" - -#include "dvdread/ifo_read.h" - -#include "mpeg2dec/mpeg2.h" - -/* Local prototypes */ -static void ScanThread( void * ); -static HBTitle * ScanTitle( HBScan *, dvd_reader_t * reader, - ifo_handle_t * vmg, int index ); -static int DecodeFrame( HBScan * s, dvd_file_t * dvdFile, - HBTitle * title, int which ); -static char * LanguageForCode( int code ); - -struct HBScan -{ - HBHandle * handle; - char * device; - int title; - volatile int die; - HBThread * thread; - HBList * titleList; -}; - -HBScan * HBScanInit( HBHandle * handle, const char * device, int title ) -{ - HBScan * s; - if( !( s = malloc( sizeof( HBScan ) ) ) ) - { - HBLog( "HBScanInit: malloc() failed, gonna crash" ); - return NULL; - } - - s->handle = handle; - s->device = strdup( device ); - s->title = title; - s->die = 0; - s->thread = HBThreadInit( "scan", ScanThread, s, - HB_NORMAL_PRIORITY ); - - return s; -} - -void HBScanClose( HBScan ** _s ) -{ - HBScan * s = *_s; - - s->die = 1; - HBThreadClose( &s->thread ); - - free( s->device ); - free( s ); - *_s = NULL; -} - -static void ScanThread( void * _s ) -{ - int i; - HBScan * s = (HBScan*) _s; - HBList * titleList = HBListInit(); - HBTitle * title; - dvd_reader_t * reader; - ifo_handle_t * vmg; - - s->titleList = titleList; - - HBLog( "HBScan: opening device %s", s->device ); - - reader = DVDOpen( s->device ); - if( !reader ) - { - HBLog( "HBScan: DVDOpen() failed (%s)", s->device ); - HBListClose( &titleList ); - HBScanDone( s->handle, NULL ); - return; - } - - vmg = ifoOpen( reader, 0 ); - - /* Detect titles */ - i = s->title ? ( s->title - 1 ) : 0; - while( !s->die ) - { - if( ( title = ScanTitle( s, reader, vmg, i + 1 ) ) ) - { - HBListAdd( titleList, title ); - } - if( s->title || i == vmg->tt_srpt->nr_of_srpts - 1 ) - { - break; - } - i++; - } - - ifoClose( vmg ); - - HBLog( "HBScan: closing device %s", s->device ); - DVDClose( reader ); - - if( s->die ) - { - while( ( title = HBListItemAt( titleList, 0 ) ) ) - { - HBListRemove( titleList, title ); - HBTitleClose( &title ); - } - HBListClose( &titleList ); - return; - } - - if( !HBListCount( titleList ) ) - { - HBListClose( &titleList ); - } - HBScanDone( s->handle, titleList ); -} - - -static unsigned int convert_bcd( unsigned int i_x ) -{ - int y = 0, z = 1; - - for( ; i_x ; ) - { - y += z * ( i_x & 0xf ); - i_x = i_x >> 4; - z = z * 10; - } - - return y; -} - -static HBTitle * ScanTitle( HBScan * s, dvd_reader_t * reader, - ifo_handle_t * vmg, int index ) -{ - HBTitle * title; - HBTitle * title2; - HBAudio * audio; - int i, audio_nr; - int ttn; - ifo_handle_t * vts; - int pgc_id, pgn, cell; - pgc_t * pgc; - dvd_file_t * dvdFile; - - HBScanning( s->handle, index, vmg->tt_srpt->nr_of_srpts ); - - title = HBTitleInit( s->device, index ); - - /* VTS in which our title is */ - title->vts_id = vmg->tt_srpt->title[index-1].title_set_nr; - - vts = ifoOpen( reader, title->vts_id ); - if( !vts ) - { - HBLog( "HBScan: ifoOpen failed (vts %d)", title->vts_id ); - HBTitleClose( &title ); - return NULL; - } - - /* Position of the title in the VTS */ - ttn = vmg->tt_srpt->title[index-1].vts_ttn; - - /* Get pgc */ - pgc_id = vts->vts_ptt_srpt->title[ttn-1].ptt[0].pgcn; - pgn = vts->vts_ptt_srpt->title[ttn-1].ptt[0].pgn; - pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc; - - /* Start block */ - cell = pgc->program_map[pgn-1] - 1; - title->startBlock = pgc->cell_playback[cell].first_sector; - - /* End block */ - cell = pgc->nr_of_cells - 1; - title->endBlock = pgc->cell_playback[cell].last_sector; - - HBLog( "HBScan: vts=%d, ttn=%d, blocks %d to %d", title->vts_id, - ttn, title->startBlock, title->endBlock ); - - /* I've seen a DVD with strictly identical titles. Check this here, - and ignore it if redundant */ - title2 = NULL; - for( i = 0; i < HBListCount( s->titleList ); i++ ) - { - title2 = (HBTitle*) HBListItemAt( s->titleList, i ); - if( title->vts_id == title2->vts_id && - title->startBlock == title2->startBlock && - title->endBlock == title2->endBlock ) - { - break; - } - else - { - title2 = NULL; - } - } - if( title2 ) - { - HBLog( "HBScan: title %d is duplicate with title %d", - index, title2->title ); - HBTitleClose( &title ); - return NULL; - } - - /* Get time */ - title->hours = convert_bcd( pgc->playback_time.hour ); - title->minutes = convert_bcd( pgc->playback_time.minute ); - title->seconds = convert_bcd( pgc->playback_time.second ); - HBLog( "HBScan: title %d: length is %02d:%02d:%02d", index, - title->hours, title->minutes, title->seconds ); - - /* Discard titles under 10 seconds */ - if( !title->hours && !title->minutes && title->seconds < 10 ) - { - HBLog( "HBScan: ignoring title %d (too short)", index ); - HBTitleClose( &title ); - return NULL; - } - - /* Detect languages */ - audio_nr = vts->vtsi_mat->nr_of_vts_audio_streams; - - for( i = 0; i < audio_nr; i++ ) - { - uint32_t id = 0; - int j, codec; - int audio_format = vts->vtsi_mat->vts_audio_attr[i].audio_format; - int lang_code = vts->vtsi_mat->vts_audio_attr[i].lang_code; - int audio_control = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i]; - int i_position; - - if( s->die ) - { - break; - } - - if( !( audio_control & 0x8000 ) ) - { - continue; - } - - i_position = ( audio_control & 0x7F00 ) >> 8; - - switch( audio_format ) - { - case 0x00: /* A52 */ - codec = HB_CODEC_AC3; - id = ( ( 0x80 + i_position ) << 8 ) | 0xbd; - break; - - case 0x02: - case 0x03: - codec = HB_CODEC_MPGA; - id = 0xc0 + i_position; - break; - - case 0x04: /* LPCM */ - codec = HB_CODEC_LPCM; - id = ( ( 0xa0 + i_position ) << 8 ) | 0xbd; - break; - - default: - codec = 0; - id = 0; - HBLog( "HBScan: title %d: unknown audio codec (%x), " - "ignoring", index, audio_format ); - break; - } - - if( !id ) - { - continue; - } - - /* Check if we don't already found an track with the same id */ - audio = NULL; - for( j = 0; j < HBListCount( title->audioList ); j++ ) - { - audio = (HBAudio*) HBListItemAt( title->audioList, j ); - if( id == audio->id ) - { - break; - } - else - { - audio = NULL; - } - } - - if( audio ) - { - HBLog( "HBScan: title %d: discarding duplicate track %x", - index, id ); - continue; - } - - audio = HBAudioInit( id, LanguageForCode( lang_code ), codec ); - audio->inCodec = codec; - HBLog( "HBScan: title %d: new language (%x, %s)", index, id, - audio->language ); - HBListAdd( title->audioList, audio ); - } - - /* Discard titles with no audio tracks */ - if( !HBListCount( title->audioList ) ) - { - HBLog( "HBScan: ignoring title %d (no audio track)", index ); - HBTitleClose( &title ); - return NULL; - } - - ifoClose( vts ); - - dvdFile = DVDOpenFile( reader, title->vts_id, DVD_READ_TITLE_VOBS ); - if( !dvdFile ) - { - HBLog( "HBScan: DVDOpenFile failed" ); - HBTitleClose( &title ); - return NULL; - } - - for( i = 0; i < 10; i++ ) - { - if( s->die ) - { - break; - } - - if( !DecodeFrame( s, dvdFile, title, i ) ) - { - HBLog( "HBScan: ignoring title %d (could not decode)", - index ); - HBTitleClose( &title ); - return NULL; - } - } - - DVDCloseFile( dvdFile ); - - /* Handle ratio */ - if( title->inHeight * title->aspect > - title->inWidth * VOUT_ASPECT_FACTOR ) - { - title->outWidthMax = title->inWidth; - title->outHeightMax = MULTIPLE_16( (uint64_t)title->inWidth * - VOUT_ASPECT_FACTOR / title->aspect ); - } - else - { - title->outWidthMax = MULTIPLE_16( (uint64_t)title->inHeight * - title->aspect / VOUT_ASPECT_FACTOR ); - title->outHeightMax = title->inHeight; - } - - /* Default picture size */ - title->outWidth = title->outWidthMax; - title->outHeight = title->outHeightMax; - - return title; -} - -static HBBuffer * GetBuffer( HBList * esBufferList, - dvd_file_t * dvdFile, - int * pictureStart, int pictureEnd ) -{ - HBBuffer * esBuffer = NULL; - HBBuffer * psBuffer = NULL; - - while( !esBuffer ) - { - while( !HBListCount( esBufferList ) ) - { - psBuffer = HBBufferInit( DVD_VIDEO_LB_LEN ); - if( DVDReadBlocks( dvdFile, (*pictureStart)++, 1, - psBuffer->data ) != 1 ) - { - HBLog( "HBScan: DVDReadBlocks() failed" ); - HBBufferClose( &psBuffer ); - return NULL; - } - if( !HBPStoES( &psBuffer, esBufferList ) ) - { - HBLog( "HBScan: HBPStoES() failed" ); - return NULL; - } - if( *pictureStart >= pictureEnd ) - { - HBLog( "HBScan: gone too far, aborting" ); - return NULL; - } - } - - esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ); - HBListRemove( esBufferList, esBuffer ); - - if( esBuffer->streamId != 0xE0 ) - { - HBBufferClose( &esBuffer ); - } - } - - return esBuffer; -} - -static int DecodeFrame( HBScan * s, dvd_file_t * dvdFile, - HBTitle * title, int which ) -{ - int pictureStart = title->startBlock + ( which + 1 ) * - ( title->endBlock - title->startBlock ) / 11; - int pictureEnd = title->startBlock + ( which + 2 ) * - ( title->endBlock - title->startBlock ) / 11; - - mpeg2dec_t * handle; - const mpeg2_info_t * info; - mpeg2_state_t state; - char fileName[1024]; - FILE * file; - int ret = 0; - - HBList * esBufferList = HBListInit(); - HBBuffer * esBuffer = NULL; - - - /* Init libmpeg2 */ - handle = mpeg2_init(); - info = mpeg2_info( handle ); - - /* Init the destination file */ - memset( fileName, 0, 1024 ); -#ifndef HB_CYGWIN - sprintf( fileName, "/tmp/HB.%d.%d.%d", HBGetPid( s->handle ), - title->title, which ); -#else - sprintf( fileName, "C:\\HB.%d.%d.%d", HBGetPid( s->handle ), - title->title, which ); -#endif - file = fopen( fileName, "wb" ); - if( !file ) - { - HBLog( "HBScan: fopen failed" ); - HBListClose( &esBufferList ); - return 0; - } - - for( ;; ) - { - state = mpeg2_parse( handle ); - - if( state == STATE_BUFFER ) - { - /* Free the previous buffer */ - if( esBuffer ) - { - HBBufferClose( &esBuffer ); - } - - /* Get a new one */ - esBuffer = GetBuffer( esBufferList, dvdFile, &pictureStart, - pictureEnd ); - if( !esBuffer ) - { - break; - } - - /* Feed libmpeg2 */ - mpeg2_buffer( handle, esBuffer->data, - esBuffer->data + esBuffer->size ); - } - else if( state == STATE_SEQUENCE ) - { - if( !which ) - { - /* Get size & framerate info */ - title->inWidth = info->sequence->width; - title->inHeight = info->sequence->height; - title->aspect = (uint64_t)info->sequence->display_width * - info->sequence->pixel_width * VOUT_ASPECT_FACTOR / - ( info->sequence->display_height * - info->sequence->pixel_height ); - title->rate = 27000000; - title->rateBase = info->sequence->frame_period; - - title->autoTopCrop = title->inHeight / 2; - title->autoBottomCrop = title->inHeight / 2; - title->autoLeftCrop = title->inWidth / 2; - title->autoRightCrop = title->inWidth / 2; - } - } - else if( ( state == STATE_SLICE || state == STATE_END ) && - ( info->display_fbuf ) && - ( info->display_picture->flags & PIC_MASK_CODING_TYPE ) - == PIC_FLAG_CODING_TYPE_I ) - { -#define Y info->display_fbuf->buf[0] -#define DARK 64 - /* Detect black borders */ - int i, j; - for( i = 0; i < title->inWidth; i++ ) - { - for( j = 0; j < title->autoTopCrop; j++ ) - if( Y[ j * title->inWidth + i ] > DARK ) - { - title->autoTopCrop = j; - break; - } - for( j = 0; j < title->autoBottomCrop; j++ ) - if( Y[ ( title->inHeight - j - 1 ) * - title->inWidth + i ] > DARK ) - { - title->autoBottomCrop = j; - break; - } - } - for( i = 0; i < title->inHeight; i++ ) - { - for( j = 0; j < title->autoLeftCrop; j++ ) - if( Y[ i * title->inWidth + j ] > DARK ) - { - title->autoLeftCrop = j; - break; - } - for( j = 0; j < title->autoRightCrop; j++ ) - if( Y[ i * title->inWidth + - title->inWidth - j - 1 ] > DARK ) - { - title->autoRightCrop = j; - break; - } - } -#undef Y -#undef DARK - - /* Write the raw picture to a file */ - fwrite( info->display_fbuf->buf[0], - title->inWidth * title->inHeight, 1, file ); - fwrite( info->display_fbuf->buf[1], - title->inWidth * title->inHeight / 4, 1, file ); - fwrite( info->display_fbuf->buf[2], - title->inWidth * title->inHeight / 4, 1, file ); - ret = 1; - break; - } - else if( state == STATE_INVALID ) - { - /* Reset libmpeg2 */ - mpeg2_close( handle ); -#ifdef HB_NOMMX - mpeg2_accel( 0 ); -#endif - handle = mpeg2_init(); - } - } - - while( ( esBuffer = (HBBuffer*) HBListItemAt( esBufferList, 0 ) ) ) - { - HBListRemove( esBufferList, esBuffer ); - HBBufferClose( &esBuffer ); - } - HBListClose( &esBufferList ); - if( esBuffer ) HBBufferClose( &esBuffer ); - mpeg2_close( handle ); - fclose( file ); - - return ret; -} - -static char * LanguageForCode( int code ) -{ - char codeString[2]; - iso639_lang_t * lang; - - codeString[0] = ( code >> 8 ) & 0xFF; - codeString[1] = code & 0xFF; - - for( lang = languages; lang->engName; lang++ ) - { - if( !strncmp( lang->iso639_1, codeString, 2 ) ) - { - if( *lang->nativeName ) - { - return lang->nativeName; - } - - return lang->engName; - } - } - - return "Unknown"; -} - diff --git a/core/Thread.c b/core/Thread.c deleted file mode 100644 index 9379223f0..000000000 --- a/core/Thread.c +++ /dev/null @@ -1,187 +0,0 @@ -/* $Id: Thread.c,v 1.14 2004/04/27 19:30:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "Thread.h" - -/********************************************************************** - * HBThread implementation - **********************************************************************/ -struct HBThread -{ - /* User-friendly name */ - char * name; - - /* HB_(LOW|NORMAL)_PRIORITY */ - int priority; - - /* Thread function and argument */ - void (*function) ( void * ); - void * arg; - - /* OS-specific thread id */ -#if defined( HB_BEOS ) - int thread; -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_t thread; -#elif defined( HB_CYGWIN ) - HANDLE thread; -#endif -}; - -/* HBThreadInit actually starts this routine because - pthread_setschedparam() might fail if called from an external - thread (typically, because the thread exited immediatly). This isn't - really necessary, but I find it nicer that way */ -static void ThreadFunc( void * _t ) -{ - HBThread * t = (HBThread*) _t; - -#if defined( HB_MACOSX ) - /* Set the thread priority */ - struct sched_param param; - memset( ¶m, 0, sizeof( struct sched_param ) ); - param.sched_priority = t->priority; - if( pthread_setschedparam( pthread_self(), SCHED_OTHER, ¶m ) ) - { - HBLog( "HBThread: couldn't set thread priority" ); - } -#endif - - /* Start the real routine */ - t->function( t->arg ); -} - -HBThread * HBThreadInit( char * name, void (* function)(void *), - void * arg, int priority ) -{ - /* Initializations */ - HBThread * t; - if( !( t = malloc( sizeof( HBThread ) ) ) ) - { - HBLog( "HBThread: malloc() failed, gonna crash" ); - return NULL; - } - t->name = strdup( name ); - t->priority = priority; - t->function = function; - t->arg = arg; - - /* Create and start the thread */ -#if defined( HB_BEOS ) - t->thread = spawn_thread( (int32 (*)( void * )) ThreadFunc, - name, priority, t ); - resume_thread( t->thread ); -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_create( &t->thread, NULL, - (void * (*)( void * )) ThreadFunc, t ); -#elif defined( HB_CYGWIN ) - t->thread = CreateThread( NULL, 0, - (LPTHREAD_START_ROUTINE) ThreadFunc, t, 0, NULL ); -#endif - - HBLog( "HBThread: thread %d started (\"%s\")", - t->thread, t->name ); - - return t; -} - -void HBThreadClose( HBThread ** _t ) -{ - HBThread * t = *_t; - - /* Join the thread */ -#if defined( HB_BEOS ) - long exitValue; - wait_for_thread( t->thread, &exitValue ); -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_join( t->thread, NULL ); -#elif defined( HB_CYGWIN ) - WaitForSingleObject( t->thread, INFINITE ); -#endif - - HBLog( "HBThread: thread %d stopped (\"%s\")", - t->thread, t->name ); - - /* Clean up */ - free( t->name ); - free( t ); - *_t = NULL; -} - - -/********************************************************************** - * HBLock implementation - **********************************************************************/ -HBLock * HBLockInit() -{ - HBLock * l; - if( !( l = malloc( sizeof( HBLock ) ) ) ) - { - HBLog( "HBLock: malloc() failed, gonna crash" ); - return NULL; - } - -#if defined( HB_BEOS ) - l->sem = create_sem( 1, "sem" ); -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_mutex_init( &l->mutex, NULL ); -#elif defined( HB_CYGWIN ) - l->mutex = CreateMutex( 0, FALSE, 0 ); -#endif - - return l; -} - -void HBLockClose( HBLock ** _l ) -{ - HBLock * l = *_l; - -#if defined( HB_BEOS ) - delete_sem( l->sem ); -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_mutex_destroy( &l->mutex ); -#elif defined( HB_CYGWIN ) - CloseHandle( l->mutex ); -#endif - free( l ); - - *_l = NULL; -} - - -/********************************************************************** - * HBCond implementation - **********************************************************************/ -HBCond * HBCondInit() -{ - HBCond * c = malloc( sizeof( HBCond ) ); - -#if defined( HB_BEOS ) - c->thread = -1; -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_cond_init( &c->cond, NULL ); -#elif defined( HB_CYGWIN ) - c->event = CreateEvent( NULL, FALSE, FALSE, NULL ); -#endif - - return c; -} - -void HBCondClose( HBCond ** _c ) -{ - HBCond * c = *_c; - -#if defined( HB_BEOS ) -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_cond_destroy( &c->cond ); -#elif defined( HB_CYGWIN ) - CloseHandle( c->event ); -#endif - free( c ); - - *_c = NULL; -} - diff --git a/core/Thread.h b/core/Thread.h deleted file mode 100644 index bf343214d..000000000 --- a/core/Thread.h +++ /dev/null @@ -1,144 +0,0 @@ -/* $Id: Thread.h,v 1.10 2004/03/16 16:14:03 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_THREAD_H -#define HB_THREAD_H - -/* System headers */ -#if defined( HB_BEOS ) -# include <OS.h> -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) -# include <pthread.h> -#elif defined( HB_CYGWIN ) -# include <windows.h> -#endif - -#include "Utils.h" - -/* Thread priorities */ -#if defined( HB_BEOS ) -# define HB_LOW_PRIORITY 5 -# define HB_NORMAL_PRIORITY 10 -#elif defined( HB_MACOSX ) -# define HB_LOW_PRIORITY 0 -# define HB_NORMAL_PRIORITY 31 -#elif defined( HB_LINUX ) || defined( HB_CYGWIN ) -/* Actually unused */ -# define HB_LOW_PRIORITY 0 -# define HB_NORMAL_PRIORITY 0 -#endif - -/********************************************************************** - * HBThread/HBLock/HBCond declarations - **********************************************************************/ -HBThread * HBThreadInit( char * name, - void (* function)(void *), - void * arg, int priority ); -void HBThreadClose( HBThread ** ); - -HBLock * HBLockInit(); -static inline void HBLockLock( HBLock * ); -static inline void HBLockUnlock( HBLock * ); -void HBLockClose( HBLock ** ); - -HBCond * HBCondInit(); -static inline void HBCondWait( HBCond *, HBLock * ); -static inline void HBCondSignal( HBCond * ); -void HBCondClose( HBCond ** ); - - -/********************************************************************** - * HBLock implementation (inline functions) - **********************************************************************/ -struct HBLock -{ -#if defined( HB_BEOS ) - sem_id sem; -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_mutex_t mutex; -#elif defined( HB_CYGWIN ) - HANDLE mutex; -#endif -}; - -static inline void HBLockLock( HBLock * l ) -{ -#if defined( HB_BEOS ) - acquire_sem( l->sem ); -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_mutex_lock( &l->mutex ); -#elif defined( HB_CYGWIN ) - WaitForSingleObject( l->mutex, INFINITE ); -#endif -} - -static inline void HBLockUnlock( HBLock * l ) -{ -#if defined( HB_BEOS ) - release_sem( l->sem ); -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_mutex_unlock( &l->mutex ); -#elif defined( HB_CYGWIN ) - ReleaseMutex( l->mutex ); -#endif -} - - -/********************************************************************** - * HBCond implementation (inline functions) - **********************************************************************/ -struct HBCond -{ -#if defined( HB_BEOS ) - int thread; -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_cond_t cond; -#elif defined( HB_CYGWIN ) - HANDLE event; -#endif - -}; - -static inline void HBCondWait( HBCond * c, HBLock * lock ) -{ -#if defined( HB_BEOS ) - c->thread = find_thread( NULL ); - release_sem( lock->sem ); - suspend_thread( c->thread ); - acquire_sem( lock->sem ); - c->thread = -1; -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_cond_wait( &c->cond, &lock->mutex ); -#elif defined( HB_CYGWIN ) - SignalObjectAndWait( lock->mutex, c->event, INFINITE, FALSE ); - WaitForSingleObject( lock->mutex, INFINITE ); -#endif -} - -static inline void HBCondSignal( HBCond * c ) -{ -#if defined( HB_BEOS ) - while( c->thread != -1 ) - { - thread_info info; - get_thread_info( c->thread, &info ); - if( info.state == B_THREAD_SUSPENDED ) - { - resume_thread( c->thread ); - break; - } - /* In case HBCondSignal is called between HBCondWait's - release_sem() and suspend_thread() lines, wait a bit */ - snooze( 5000 ); - } -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - pthread_cond_signal( &c->cond ); -#elif defined( HB_CYGWIN ) - PulseEvent( c->event ); -#endif -} - -#endif diff --git a/core/Utils.c b/core/Utils.c deleted file mode 100644 index 45ebf7bd4..000000000 --- a/core/Utils.c +++ /dev/null @@ -1,379 +0,0 @@ -/* $Id: Utils.c,v 1.20 2004/05/12 17:21:24 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include <stdarg.h> -#include <time.h> -#include <sys/time.h> -#ifdef HB_CYGWIN -# include <windows.h> -#endif - -#include "Utils.h" -#include "Fifo.h" - -#ifdef HB_CYGWIN -int gettimeofday( struct timeval * tv, struct timezone * tz ) -{ - tv->tv_sec = 0; - tv->tv_usec = 0; - return 0; -} -void bcopy( const void * src, void * dest, size_t n ) -{ - memcpy( dest, src, n ); -} -#endif - -struct HBList -{ - void ** items; - int allocItems; - int nbItems; -}; - -void HBSnooze( int time ) -{ -#if defined( HB_BEOS ) - snooze( time ); -#elif defined( HB_MACOSX ) || defined( HB_LINUX ) - usleep( time ); -#elif defined( HB_CYGWIN ) - Sleep( time / 1000 ); -#endif -} - -void HBLog( char * log, ... ) -{ - char string[80]; - time_t _now; - struct tm * now; - va_list args; - - if( !getenv( "HB_DEBUG" ) ) - { - return; - } - - /* Show the time */ - _now = time( NULL ); - now = localtime( &_now ); - sprintf( string, "[%02d:%02d:%02d] ", - now->tm_hour, now->tm_min, now->tm_sec ); - - /* Convert the message to a string */ - va_start( args, log ); - vsnprintf( string + 11, 67, log, args ); - va_end( args ); - - /* Add the end of line */ - strcat( string, "\n" ); - - /* Print it */ - fprintf( stderr, "%s", string ); -} - -uint64_t HBGetDate() -{ -#ifndef HB_CYGWIN - struct timeval tv; - gettimeofday( &tv, NULL ); - return( (uint64_t) tv.tv_sec * 1000000 + (uint64_t) tv.tv_usec ); -#else - return( 1000 * GetTickCount() ); -#endif -} - -/* Basic MPEG demuxer - only works with DVDs ! (2048 bytes packets) */ -int HBPStoES( HBBuffer ** _psBuffer, HBList * esBufferList ) -{ - HBBuffer * psBuffer = *_psBuffer; - HBBuffer * esBuffer; - int pos = 0; - -#define d (psBuffer->data) - - /* pack_header */ - if( d[pos] != 0 || d[pos+1] != 0 || - d[pos+2] != 0x1 || d[pos+3] != 0xBA ) - { - HBLog( "HBPStoES: not a PS packet (%02x%02x%02x%02x)", - d[pos], d[pos+1], d[pos+2], d[pos+3] ); - HBBufferClose( _psBuffer ); - return 0; - } - pos += 4; /* pack_start_code */ - pos += 9; /* pack_header */ - pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */ - - /* system_header */ - if( d[pos] == 0 && d[pos+1] == 0 && - d[pos+2] == 0x1 && d[pos+3] == 0xBB ) - { - int header_length; - - pos += 4; /* system_header_start_code */ - header_length = ( d[pos] << 8 ) + d[pos+1]; - pos += 2 + header_length; - } - - /* PES */ - while( pos + 6 < psBuffer->size && - d[pos] == 0 && d[pos+1] == 0 && d[pos+2] == 0x1 ) - { - int streamId; - int PES_packet_length; - int PES_packet_end; - int PES_header_d_length; - int PES_header_end; - int hasPTS; - uint64_t PTS = 0; - - pos += 3; /* packet_start_code_prefix */ - streamId = d[pos]; - pos += 1; - - PES_packet_length = ( d[pos] << 8 ) + d[pos+1]; - pos += 2; /* PES_packet_length */ - PES_packet_end = pos + PES_packet_length; - - if( streamId != 0xE0 && streamId != 0xBD && - ( streamId & 0xC0 ) != 0xC0 ) - { - /* Not interesting */ - pos = PES_packet_end; - continue; - } - - hasPTS = ( ( d[pos+1] >> 6 ) & 0x2 ) ? 1 : 0; - pos += 2; /* Required headers */ - - PES_header_d_length = d[pos]; - pos += 1; - PES_header_end = pos + PES_header_d_length; - - if( hasPTS ) - { - PTS = ( ( ( (uint64_t) d[pos] >> 1 ) & 0x7 ) << 30 ) + - ( d[pos+1] << 22 ) + - ( ( d[pos+2] >> 1 ) << 15 ) + - ( d[pos+3] << 7 ) + - ( d[pos+4] >> 1 ); - } - - pos = PES_header_end; - - if( streamId == 0xBD ) - { - streamId |= ( d[pos] << 8 ); - if( ( streamId & 0xF0FF ) == 0x80BD ) - { - /* A52 */ - pos += 4; - } - else if( ( streamId & 0xF0FF ) == 0xA0BD ) - { - /* LPCM */ - pos += 1; - } - } - - /* Sanity check */ - if( pos >= PES_packet_end ) - { - pos = PES_packet_end; - continue; - } - - /* Here we hit we ES payload */ - esBuffer = HBBufferInit( PES_packet_end - pos ); - - esBuffer->position = psBuffer->position; - esBuffer->pass = psBuffer->pass; - esBuffer->streamId = streamId; - esBuffer->pts = PTS; - memcpy( esBuffer->data, d + pos, - PES_packet_end - pos ); - - HBListAdd( esBufferList, esBuffer ); - - pos = PES_packet_end; - } - -#undef d - - HBBufferClose( _psBuffer ); - - return 1; -} - -#define HBLIST_DEFAULT_SIZE 20 -HBList * HBListInit() -{ - HBList * l; - if( !( l = malloc( sizeof( HBList ) ) ) ) - { - HBLog( "HBListInit: malloc() failed, gonna crash" ); - return NULL; - } - - if( !( l->items = malloc( HBLIST_DEFAULT_SIZE * sizeof( void* ) ) ) ) - { - HBLog( "HBListInit: malloc() failed, gonna crash" ); - free( l ); - return NULL; - } - - l->allocItems = HBLIST_DEFAULT_SIZE; - l->nbItems = 0; - - return l; -} - -int HBListCount( HBList * l ) -{ - return l->nbItems; -} - -void HBListAdd( HBList * l, void * item ) -{ - if( !item ) - { - return; - } - - if( l->nbItems == l->allocItems ) - { - l->allocItems += HBLIST_DEFAULT_SIZE; - l->items = realloc( l->items, - l->allocItems * sizeof( void* ) ); - } - - l->items[l->nbItems] = item; - (l->nbItems)++; -} - -void HBListRemove( HBList * l, void * item ) -{ - int i; - - if( !item || !l->nbItems ) - { - return; - } - - for( i = 0; i < l->nbItems; i++ ) - { - if( l->items[i] == item ) - { - break; - } - } - - if( l->items[i] != item ) - { - HBLog( "HBListRemove: specified item is not in the list" ); - return; - } - - for( ; i < l->nbItems - 1; i++ ) - { - l->items[i] = l->items[i+1]; - } - - (l->nbItems)--; -} - -void * HBListItemAt( HBList * l, int index ) -{ - if( index < 0 || index >= l->nbItems ) - { - return NULL; - } - - return l->items[index]; -} - -void HBListClose( HBList ** _l ) -{ - HBList * l = *_l; - - free( l->items ); - free( l ); - - *_l = NULL; -} - -HBTitle * HBTitleInit( char * device, int index ) -{ - HBTitle * t; - - if( !( t = calloc( sizeof( HBTitle ), 1 ) ) ) - { - HBLog( "HBTitleInit: calloc() failed, gonna crash" ); - return NULL; - } - - t->device = strdup( device ); - t->title = index; - - t->codec = HB_CODEC_FFMPEG; - t->mux = HB_MUX_MP4; - - t->audioList = HBListInit(); - t->ripAudioList = HBListInit(); - - t->start = -1; - - return t; -} - -void HBTitleClose( HBTitle ** _t ) -{ - HBTitle * t = *_t; - - HBAudio * audio; - while( ( audio = HBListItemAt( t->audioList, 0 ) ) ) - { - HBListRemove( t->audioList, audio ); - HBAudioClose( &audio ); - } - HBListClose( &t->audioList ); - HBListClose( &t->ripAudioList ); - - if( t->file ) free( t->file ); - free( t->device ); - free( t ); - - *_t = NULL; -} - -HBAudio * HBAudioInit( int id, char * language, int codec ) -{ - HBAudio * a; - if( !( a = calloc( sizeof( HBAudio ), 1 ) ) ) - { - HBLog( "HBAudioInit: calloc() failed, gonna crash" ); - return NULL; - } - - a->id = id; - a->start = -1; - a->inCodec = codec; - - memset( a->language, 0, 512 ); - snprintf( a->language, 511, "%s (%s)", language, - ( codec == HB_CODEC_AC3 ) ? "AC3" : ( ( codec == - HB_CODEC_LPCM ? "LPCM" : "MPEG" ) ) ); - return a; -} - -void HBAudioClose( HBAudio ** _a ) -{ - HBAudio * a = *_a; - free( a ); - *_a = NULL; -} - diff --git a/core/Utils.h b/core/Utils.h deleted file mode 100644 index fce20e557..000000000 --- a/core/Utils.h +++ /dev/null @@ -1,219 +0,0 @@ -/* $Id: Utils.h,v 1.30 2004/05/04 12:50:52 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_UTILS_H -#define HB_UTILS_H - -/* Standard headers */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <inttypes.h> -typedef uint8_t byte_t; -#ifdef HB_BEOS -# include <OS.h> -#endif - -/* Handy macros */ -#ifndef MIN -#define MIN( a, b ) ( ( (a) > (b) ) ? (b) : (a) ) -#endif -#ifndef MAX -#define MAX( a, b ) ( ( (a) > (b) ) ? (a) : (b) ) -#endif -#ifndef EVEN -#define EVEN( a ) ( ( (a) & 0x1 ) ? ( (a) + 1 ) : (a) ) -#endif -#ifndef MULTIPLE_16 -#define MULTIPLE_16( a ) ( 16 * ( ( (a) + 8 ) / 16 ) ) -#endif -#ifndef VOUT_ASPECT_FACTOR -#define VOUT_ASPECT_FACTOR 432000 -#endif - -typedef struct HBHandle HBHandle; - -/* Utils */ -typedef struct HBAudio HBAudio; -typedef struct HBBuffer HBBuffer; -typedef struct HBCond HBCond; -typedef struct HBFifo HBFifo; -typedef struct HBList HBList; -typedef struct HBLock HBLock; -typedef struct HBTitle HBTitle; -typedef struct HBThread HBThread; - -/* (De)Muxers */ -typedef struct HBDVDRead HBDVDRead; -typedef struct HBScan HBScan; - -typedef struct HBWork HBWork; -typedef struct HBMuxThread HBMuxThread; -typedef struct HBWorkThread HBWorkThread; - -/* Misc functions which may be used from anywhere */ -void HBSnooze( int time ); -void HBLog( char * log, ... ); -uint64_t HBGetDate(); -int HBPStoES( HBBuffer ** psBuffer, HBList * esBufferList ); - -/* HBList functions */ -HBList * HBListInit(); -int HBListCount( HBList * ); -void HBListAdd( HBList *, void * item ); -void HBListRemove( HBList *, void * item ); -void * HBListItemAt( HBList *, int index ); -void HBListClose( HBList ** ); - -/* HBTitle function */ -HBTitle * HBTitleInit(); -void HBTitleClose( HBTitle ** ); - -/* HBAudio functions */ -HBAudio * HBAudioInit( int id, char * language, int codec ); -void HBAudioClose( HBAudio ** ); - -#define HB_SUCCESS 0x00 -#define HB_CANCELED 0x01 -#define HB_ERROR_A52_SYNC 0x02 -#define HB_ERROR_AVI_WRITE 0x04 -#define HB_ERROR_DVD_OPEN 0x08 -#define HB_ERROR_DVD_READ 0x10 -#define HB_ERROR_MP3_INIT 0x20 -#define HB_ERROR_MP3_ENCODE 0x40 -#define HB_ERROR_MPEG4_INIT 0x80 - -/* Possible codecs */ -#define HB_CODEC_MPEG2 0x000 -#define HB_CODEC_FFMPEG 0x001 -#define HB_CODEC_XVID 0x002 -#define HB_CODEC_AC3 0x004 -#define HB_CODEC_LPCM 0x008 -#define HB_CODEC_MP3 0x010 -#define HB_CODEC_AAC 0x020 -#define HB_CODEC_X264 0x040 -#define HB_CODEC_VORBIS 0x080 -#define HB_CODEC_MPGA 0x100 - -/* Possible muxers */ -#define HB_MUX_AVI 0x00 -#define HB_MUX_MP4 0x01 -#define HB_MUX_OGM 0x02 - -struct HBTitle -{ - /* DVD info */ - char * device; - int title; - int vts_id; - int startBlock; - int endBlock; - int hours; - int minutes; - int seconds; - - /* Audio infos */ - HBList * audioList; - HBList * ripAudioList; - - /* See DVDRead.c */ - int64_t start; - - /* Video input */ - int inWidth; - int inHeight; - int aspect; - int rate; - int rateBase; - - /* Video output */ - int outWidth; - int outHeight; - int outWidthMax; - int outHeightMax; - int topCrop; - int bottomCrop; - int leftCrop; - int rightCrop; - int deinterlace; - int autoTopCrop; - int autoBottomCrop; - int autoLeftCrop; - int autoRightCrop; - - /* Encoder settings */ - int codec; - int bitrate; - int twoPass; - - /* Muxer settings */ - char * file; - int mux; - - /* Muxer data */ - void * muxData; - - /* MP4 muxer specific */ - uint8_t * esConfig; - int esConfigLength; - - /* Fifos */ - HBFifo * inFifo; - HBFifo * rawFifo; - HBFifo * scaledFifo; - HBFifo * outFifo; - - /* Threads */ - HBDVDRead * dvdRead; - HBWorkThread * workThreads[8]; - HBMuxThread * muxThread; - - /* Work objects */ - HBWork * decoder; - HBWork * scale; - HBWork * encoder; -}; - -struct HBAudio -{ - /* Ident */ - uint32_t id; - char language[512]; - - /* Settings */ - int inCodec; - int outCodec; - int inSampleRate; - int outSampleRate; - int inBitrate; - int outBitrate; - - int delay; /* in ms */ - - /* See DVDRead.c */ - int64_t start; - - /* MPEG-4 config, used in the MP4 muxer */ - uint8_t * esConfig; - unsigned long esConfigLength; - - /* Muxer data */ - void * muxData; - - /* Fifos */ - HBFifo * inFifo; - HBFifo * rawFifo; - HBFifo * resampleFifo; - HBFifo * outFifo; - - /* Work objects */ - HBWork * decoder; - HBWork * resample; - HBWork * encoder; -}; - -#endif diff --git a/core/VorbisEnc.c b/core/VorbisEnc.c deleted file mode 100644 index 8b7b10f8f..000000000 --- a/core/VorbisEnc.c +++ /dev/null @@ -1,172 +0,0 @@ -/* $Id: VorbisEnc.c,v 1.9 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* libvorbis */ -#include <vorbis/vorbisenc.h> - -#define OGGVORBIS_FRAME_SIZE 1024 - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBAudio * audio; - - int inited; - vorbis_info vi; - vorbis_comment vc; - vorbis_dsp_state vd; - vorbis_block vb; - float position; - - int32_t * inputBuffer; - -}; - -/* Local prototypes */ -static int VorbisEncWork( HBWork * ); - -HBWork * HBVorbisEncInit ( HBHandle * handle, HBAudio * audio ) -{ - HBWork * w = calloc( sizeof( HBWork ), 1 ); - - w->name = strdup( "VorbisEnc" ); - w->work = VorbisEncWork; - - w->handle = handle; - w->audio = audio; - - w->inputBuffer = malloc( 2 * OGGVORBIS_FRAME_SIZE * sizeof( int32_t ) ); - - return w; -} - -void HBVorbisEncClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - if( w->inited ) - { - vorbis_block_clear( &w->vb ); - vorbis_dsp_clear( &w->vd ); - vorbis_comment_clear( &w->vc ); - vorbis_info_clear( &w->vi ); - } - - free( w->name ); - free( w ); - - *_w = NULL; -} - -static HBBuffer *PacketToBuffer( ogg_packet *op ) -{ - HBBuffer *buf = HBBufferInit( sizeof( ogg_packet ) + op->bytes ); - - memcpy( buf->data, op, sizeof( ogg_packet ) ); - memcpy( buf->data + sizeof( ogg_packet ), op->packet, op->bytes ); - - return buf; -} - -static int VorbisEncWork( HBWork * w ) -{ - HBAudio * audio = w->audio; - - float **buffer; - int i; - float inputBuffer[OGGVORBIS_FRAME_SIZE * 2]; - HBBuffer * vorbisBuffer; - - if( HBFifoIsHalfFull( audio->outFifo ) ) - { - return 0; - } - - if( !w->inited ) - { - ogg_packet header[3]; - - if( !HBFifoSize( audio->resampleFifo ) ) - { - return 0; - } - - w->inited = 1; - - /* init */ - vorbis_info_init( &w->vi ); - if( vorbis_encode_setup_managed( &w->vi, 2, - audio->outSampleRate, -1, 1000 * audio->outBitrate, -1 ) || - vorbis_encode_ctl( &w->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) || - vorbis_encode_setup_init( &w->vi ) ) - { - HBLog( "HBVorbisEnc: vorbis_encode_setup_managed failed" ); - return 0; - } - /* add a comment */ - vorbis_comment_init( &w->vc ); - vorbis_comment_add_tag( &w->vc, "ENCODER", "HandBrake"); - - /* set up the analysis state and auxiliary encoding storage */ - vorbis_analysis_init( &w->vd, &w->vi); - vorbis_block_init( &w->vd, &w->vb); - - - /* get the 3 headers */ - vorbis_analysis_headerout( &w->vd, &w->vc, - &header[0], &header[1], &header[2] ); - for( i = 0; i < 3; i++ ) - { - vorbisBuffer = PacketToBuffer( &header[i] ); - if( !HBFifoPush( audio->outFifo, &vorbisBuffer ) ) - { - HBLog( "HBVorbisEnc: HBFifoPush failed" ); - } - } - } - - /* Try to extract more data */ - if( vorbis_analysis_blockout( &w->vd, &w->vb ) == 1 ) - { - ogg_packet op; - - vorbis_analysis( &w->vb, NULL ); - vorbis_bitrate_addblock( &w->vb ); - - if( vorbis_bitrate_flushpacket( &w->vd, &op ) ) - { - vorbisBuffer = PacketToBuffer( &op ); - vorbisBuffer->position = w->position; - if( !HBFifoPush( audio->outFifo, &vorbisBuffer ) ) - { - HBLog( "HBVorbisEnc: HBFifoPush failed" ); - } - return 1; - } - } - - if( !HBFifoGetBytes( audio->resampleFifo, (uint8_t*) inputBuffer, - OGGVORBIS_FRAME_SIZE * 2 * sizeof( float ), - &w->position ) ) - { - return 0; - } - - buffer = vorbis_analysis_buffer( &w->vd, OGGVORBIS_FRAME_SIZE ); - for( i = 0; i < OGGVORBIS_FRAME_SIZE; i++ ) - { - buffer[0][i] = inputBuffer[2*i] / 32768.f; - buffer[1][i] = inputBuffer[2*i+1] / 32768.f; - } - vorbis_analysis_wrote( &w->vd, OGGVORBIS_FRAME_SIZE ); - - return 1; -} - diff --git a/core/Work.c b/core/Work.c deleted file mode 100644 index e23af2421..000000000 --- a/core/Work.c +++ /dev/null @@ -1,176 +0,0 @@ -/* $Id: Work.c,v 1.14 2004/04/27 19:30:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* Local prototypes */ -static void WorkThread( void * t ); - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS -}; - -struct HBWorkThread -{ - HBHandle * handle; - - HBList * workList; - int firstThread; - - volatile int die; - HBThread * thread; -}; - -HBWorkThread * HBWorkThreadInit( HBHandle * handle, HBTitle * title, - int firstThread ) -{ - int i; - HBWork * w; - HBAudio * audio; - - HBWorkThread * t; - if( !( t = malloc( sizeof( HBWorkThread ) ) ) ) - { - HBLog( "HBWorkThreadInit: malloc() failed, gonna crash" ); - return NULL; - } - - t->handle = handle; - - /* Build a list of work objects. They all include - HB_WORK_COMMON_MEMBERS, so we'll be able to do the job without - knowing what each one actually does */ - t->workList = HBListInit(); - HBListAdd( t->workList, title->decoder ); - HBListAdd( t->workList, title->scale ); - HBListAdd( t->workList, title->encoder ); - - for( i = 0; i < HBListCount( title->ripAudioList ); i++ ) - { - audio = HBListItemAt( title->ripAudioList, i ); - HBListAdd( t->workList, audio->decoder ); - HBListAdd( t->workList, audio->resample ); - HBListAdd( t->workList, audio->encoder ); - } - - t->firstThread = firstThread; - - /* Work objects are not thread-safe, so let's init locks so each - one can not be called anymore when it's doing something. This - is done by the first worker thread (see HBStartRip) */ - if( t->firstThread ) - { - for( i = 0; i < HBListCount( t->workList ); i++ ) - { - w = (HBWork*) HBListItemAt( t->workList, i ); - w->lock = HBLockInit(); - w->used = 0; - w->time = 0; - } - } - - /* Actually launch the thread */ - t->die = 0; - t->thread = HBThreadInit( "work thread", WorkThread, t, - HB_LOW_PRIORITY ); - - return t; -} - -void HBWorkThreadClose( HBWorkThread ** _t ) -{ - HBWorkThread * t = (*_t); - HBWork * w; - - /* Stop the thread */ - t->die = 1; - HBThreadClose( &t->thread ); - - /* Destroy locks, show stats */ - if( t->firstThread ) - { - int i; - uint64_t total = 0; - - for( i = 0; i < HBListCount( t->workList ); i++ ) - { - w = (HBWork*) HBListItemAt( t->workList, i ); - HBLockClose( &w->lock ); - total += w->time; - } - - for( i = 0; i < HBListCount( t->workList ); i++ ) - { - w = (HBWork*) HBListItemAt( t->workList, i ); - HBLog( "HBWorkThread: %- 9s = %05.2f %%", w->name, - 100.0 * w->time / total ); - } - - } - - /* Free memory */ - HBListClose( &t->workList ); - free( t ); - - *_t = NULL; -} - -static void WorkThread( void * _t ) -{ - HBWorkThread * t = (HBWorkThread*) _t; - HBWork * w; - int didSomething, i; - uint64_t date; - - didSomething = 0; - - for( i = 0; !t->die; i++ ) - { - HBCheckPaused( t->handle ); - - if( i == HBListCount( t->workList ) ) - { - /* If nothing could be done, wait a bit to prevent a useless - CPU-consuming loop */ - if( !didSomething ) - { - HBSnooze( 5000 ); - } - didSomething = 0; - i = 0; - } - - w = (HBWork*) HBListItemAt( t->workList, i ); - - /* Check if another thread isn't using this work object */ - HBLockLock( w->lock ); - if( w->used ) - { - /* It's in use. Forget about this one and try the next - one */ - HBLockUnlock( w->lock ); - continue; - } - /* It's unused, lock it */ - w->used = 1; - HBLockUnlock( w->lock ); - - /* Do the job */ - date = HBGetDate(); - if( w->work( w ) ) - { - w->time += HBGetDate() - date; - didSomething = 1; - } - - /* Unlock it */ - HBLockLock( w->lock ); - w->used = 0; - HBLockUnlock( w->lock ); - } -} - diff --git a/core/Work.h b/core/Work.h deleted file mode 100644 index b764e1160..000000000 --- a/core/Work.h +++ /dev/null @@ -1,21 +0,0 @@ -/* $Id: Work.h,v 1.4 2003/12/26 20:03:27 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#ifndef HB_WORK_H -#define HB_WORK_H - -#define HB_WORK_COMMON_MEMBERS \ - char * name; \ - HBLock * lock; \ - int used; \ - uint64_t time; \ - int (*work) ( HBWork * ); - -HBWorkThread * HBWorkThreadInit( HBHandle *, HBTitle *, - int firstThread ); -void HBWorkThreadClose( HBWorkThread ** ); - -#endif diff --git a/core/X264Enc.c b/core/X264Enc.c deleted file mode 100644 index be8d76709..000000000 --- a/core/X264Enc.c +++ /dev/null @@ -1,155 +0,0 @@ -/* $Id: X264Enc.c,v 1.8 2004/05/02 16:25:00 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -/* x264 */ -#include "x264.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle *handle; - HBTitle *title; - - x264_t *h; - x264_picture_t picture; -}; - -/* Local prototypes */ -static int HBX264EncWork( HBWork * ); - -HBWork * HBX264EncInit( HBHandle * handle, HBTitle * title ) -{ - HBWork * w = malloc( sizeof( HBWork ) ); - - if( w ) - { - x264_param_t param; - - w->name = strdup( "X264Enc" ); - w->work = HBX264EncWork; - - w->handle = handle; - w->title = title; - - x264_param_default( ¶m ); - - param.i_width = title->outWidth; - param.i_height= title->outHeight; - param.i_iframe = 20 * title->rate / title->rateBase; - param.i_idrframe = 1; - param.b_cabac = 0; - param.analyse.inter = - X264_ANALYSE_I16x16|X264_ANALYSE_I4x4|X264_ANALYSE_P16x16| - X264_ANALYSE_P16x8|X264_ANALYSE_P8x16|X264_ANALYSE_P8x8| - X264_ANALYSE_SMART_PSUB; - - if( ( w->h = x264_encoder_open( ¶m ) ) == NULL ) - { - HBLog( "x264: x264_encoder_new failed" ); - return NULL; - } - memset( &w->picture, 0, sizeof( x264_picture_t ) ); - w->picture.i_width = param.i_width; - w->picture.i_height = param.i_height; - w->picture.i_plane = 3; - - HBLog( "x264: opening with %dx%d iframes=%d", param.i_width, param.i_height, param.i_iframe ); - } - - return w; -} - -void HBX264EncClose( HBWork ** _w ) -{ - HBWork * w = *_w; - x264_encoder_close( w->h ); - free( w->name ); - free( w ); - *_w = NULL; -} - -/* TODO trash buffer->pass == 1 - * return 0 ->rien fait - * 1 -> sinon - */ -static int HBX264EncWork( HBWork * w ) -{ - HBTitle * title = w->title; - - HBBuffer * frame, * buffer; - - x264_nal_t *nal; - int i_nal; - int i; - - if( HBFifoIsHalfFull( title->outFifo ) ) - { - return 0; - } - - if( !( frame = HBFifoPop( title->scaledFifo ) ) ) - { - return 0; - } - - if( frame->pass == 1 ) - { - /* Trash all first pass buffer */ - HBBufferClose( &frame ); - return 1; - } - - w->picture.i_stride[0] = title->outWidth; - w->picture.i_stride[1] = title->outWidth/2; - w->picture.i_stride[2] = title->outWidth/2; - - w->picture.plane[0] = frame->data; - w->picture.plane[1] = &w->picture.plane[0][title->outWidth*title->outHeight]; - w->picture.plane[2] = &w->picture.plane[1][title->outWidth*title->outHeight/4]; - - x264_encoder_encode( w->h, &nal, &i_nal, &w->picture ); - - buffer = HBBufferInit( 3 * title->outWidth * title->outHeight / 2 ); /* FIXME */ - buffer->keyFrame = 0; - buffer->position = frame->position; - buffer->size = 0; - - for( i = 0; i < i_nal; i++ ) - { - int i_data = buffer->alloc - buffer->size; - int i_size; - - i_size = x264_nal_encode( &buffer->data[buffer->size], - &i_data, 1, &nal[i] ); - if( i_size <= 0 ) - { - fprintf( stderr, "#################### error" ); - } - - buffer->size += i_size; - - if( nal[i].i_ref_idc == NAL_PRIORITY_HIGH || - nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) - { - buffer->keyFrame = 1; - } - } - - /* Inform the GUI about the current position */ - HBPosition( w->handle, frame->position ); - - HBBufferClose( &frame ); - - if( !HBFifoPush( title->outFifo, &buffer ) ) - { - HBLog( "HBX264Enc: HBFifoPush failed" ); - } - - return 1; -} diff --git a/core/XvidEnc.c b/core/XvidEnc.c deleted file mode 100644 index 4c06da69e..000000000 --- a/core/XvidEnc.c +++ /dev/null @@ -1,247 +0,0 @@ -/* $Id: XvidEnc.c,v 1.26 2004/05/12 17:21:24 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "HBInternal.h" - -#include "xvid.h" - -struct HBWork -{ - HB_WORK_COMMON_MEMBERS - - HBHandle * handle; - HBTitle * title; - - char file[1024]; - void * xvid; - xvid_enc_frame_t frame; - int pass; -}; - -/* Local prototypes */ -static int XvidEncWork( HBWork * ); - -HBWork * HBXvidEncInit( HBHandle * handle, HBTitle * title ) -{ - HBWork * w; - if( !( w = malloc( sizeof( HBWork ) ) ) ) - { - HBLog( "HBXvidEncInit: malloc() failed, gonna crash" ); - return NULL; - } - - w->name = strdup( "XvidEnc" ); - w->work = XvidEncWork; - - w->handle = handle; - w->title = title; - - memset( w->file, 0, 1024 ); -#ifndef HB_CYGWIN - snprintf( w->file, 1023, "/tmp/HB.%d.xvid.log", - HBGetPid( w->handle ) ); -#else - snprintf( w->file, 1023, "C:\\HB.%d.xvid.log", - HBGetPid( w->handle ) ); -#endif - - w->xvid = NULL; - w->pass = 42; - - return w; -} - -void HBXvidEncClose( HBWork ** _w ) -{ - HBWork * w = *_w; - - if( w->xvid ) - { - HBLog( "HBXvidEnc: closing libxvidcore (pass %d)", - w->pass ); - xvid_encore( w->xvid, XVID_ENC_DESTROY, NULL, NULL); - } - if( w->title->esConfig ) - { - free( w->title->esConfig ); - w->title->esConfig = NULL; - w->title->esConfigLength = 0; - } - - free( w->name ); - free( w ); - *_w = NULL; -} - -static int XvidEncWork( HBWork * w ) -{ - HBTitle * title = w->title; - HBBuffer * scaledBuffer; - HBBuffer * mpeg4Buffer; - - if( HBFifoIsHalfFull( title->outFifo ) ) - { - return 0; - } - - if( !( scaledBuffer = HBFifoPop( title->scaledFifo ) ) ) - { - return 0; - } - - /* Init or re-init if needed */ - if( scaledBuffer->pass != w->pass ) - { - xvid_gbl_init_t xvid_gbl_init; - xvid_enc_create_t xvid_enc_create; - xvid_plugin_single_t single; - xvid_plugin_2pass1_t rc2pass1; - xvid_plugin_2pass2_t rc2pass2; - xvid_enc_plugin_t plugins[7]; - - if( w->xvid ) - { - HBLog( "HBXvidEnc: closing libxvidcore (pass %d)", - w->pass ); - xvid_encore( w->xvid, XVID_ENC_DESTROY, NULL, NULL); - } - - w->pass = scaledBuffer->pass; - HBLog( "HBXvidEnc: opening libxvidcore (pass %d)", w->pass ); - - memset( &xvid_gbl_init, 0, sizeof( xvid_gbl_init ) ); - xvid_gbl_init.version = XVID_VERSION; - xvid_global( NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL ); - - memset(&xvid_enc_create, 0, sizeof(xvid_enc_create)); - xvid_enc_create.version = XVID_VERSION; - xvid_enc_create.width = title->outWidth; - xvid_enc_create.height = title->outHeight; - xvid_enc_create.zones = NULL; - xvid_enc_create.num_zones = 0; - xvid_enc_create.plugins = plugins; - xvid_enc_create.num_plugins = 0; - - if( !w->pass ) - { - memset( &single, 0, sizeof( single ) ); - single.version = XVID_VERSION; - single.bitrate = 1024 * title->bitrate; - plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single; - plugins[xvid_enc_create.num_plugins].param = &single; - xvid_enc_create.num_plugins++; - } - else if( w->pass == 1 ) - { - memset( &rc2pass1, 0, sizeof( rc2pass1 ) ); - rc2pass1.version = XVID_VERSION; - rc2pass1.filename = w->file; - plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass1; - plugins[xvid_enc_create.num_plugins].param = &rc2pass1; - xvid_enc_create.num_plugins++; - } - else if( w->pass == 2 ) - { - memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t)); - rc2pass2.version = XVID_VERSION; - rc2pass2.filename = w->file; - rc2pass2.bitrate = 1024 * title->bitrate; - plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; - plugins[xvid_enc_create.num_plugins].param = &rc2pass2; - xvid_enc_create.num_plugins++; - } - - xvid_enc_create.num_threads = 0; - xvid_enc_create.fincr = title->rateBase; - xvid_enc_create.fbase = title->rate; - xvid_enc_create.max_key_interval = 10 * title->rate / title->rateBase; - xvid_enc_create.max_bframes = 0; - xvid_enc_create.bquant_ratio = 150; - xvid_enc_create.bquant_offset = 100; - xvid_enc_create.frame_drop_ratio = 0; - xvid_enc_create.global = 0; - - xvid_encore( NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL ); - w->xvid = xvid_enc_create.handle; - } - - mpeg4Buffer = HBBufferInit( title->outWidth * - title->outHeight * 3 / 2 ); - mpeg4Buffer->position = scaledBuffer->position; - - memset( &w->frame, 0, sizeof( w->frame ) ); - w->frame.version = XVID_VERSION; - w->frame.bitstream = mpeg4Buffer->data; - w->frame.length = -1; - w->frame.input.plane[0] = scaledBuffer->data; - w->frame.input.csp = XVID_CSP_I420; - w->frame.input.stride[0] = title->outWidth; - w->frame.vol_flags = 0; - w->frame.vop_flags = XVID_VOP_HALFPEL | XVID_VOP_INTER4V | - XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED; - w->frame.type = XVID_TYPE_AUTO; - w->frame.quant = 0; - w->frame.motion = XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | - XVID_ME_EXTSEARCH16 | XVID_ME_ADVANCEDDIAMOND8 | - XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 | - XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP; - w->frame.quant_intra_matrix = NULL; - w->frame.quant_inter_matrix = NULL; - - mpeg4Buffer->size = xvid_encore( w->xvid, XVID_ENC_ENCODE, - &w->frame, NULL ); - mpeg4Buffer->keyFrame = ( w->frame.out_flags & XVID_KEYFRAME ); - - /* Inform the GUI about the current position */ - HBPosition( w->handle, scaledBuffer->position ); - - HBBufferClose( &scaledBuffer ); - - if( w->pass == 1 ) - { - HBBufferClose( &mpeg4Buffer ); - return 1; - } - - if( !title->esConfig ) - { - int volStart, vopStart; - for( volStart = 0; ; volStart++ ) - { - if( mpeg4Buffer->data[volStart] == 0x0 && - mpeg4Buffer->data[volStart+1] == 0x0 && - mpeg4Buffer->data[volStart+2] == 0x1 && - mpeg4Buffer->data[volStart+3] == 0x20 ) - { - break; - } - } - for( vopStart = volStart + 4; ; vopStart++ ) - { - if( mpeg4Buffer->data[vopStart] == 0x0 && - mpeg4Buffer->data[vopStart+1] == 0x0 && - mpeg4Buffer->data[vopStart+2] == 0x1 && - mpeg4Buffer->data[vopStart+3] == 0xB6 ) - { - break; - } - } - - HBLog( "XvidEnc: VOL size is %d bytes", vopStart - volStart ); - title->esConfig = malloc( vopStart - volStart ); - title->esConfigLength = vopStart - volStart; - memcpy( title->esConfig, mpeg4Buffer->data + volStart, - vopStart - volStart ); - } - - if( !HBFifoPush( title->outFifo, &mpeg4Buffer ) ) - { - HBLog( "HBXvidEnc: HBFifoPush failed" ); - } - - return 1; -} - diff --git a/doc/faq.txt b/doc/faq.txt deleted file mode 100644 index 6375637de..000000000 --- a/doc/faq.txt +++ /dev/null @@ -1,147 +0,0 @@ -$Id: faq.txt,v 1.14 2004/04/22 22:22:07 titer Exp $ - -<h2>HandBrake FAQ</h2> - -<h4>1. Troubleshooting</h4> -<p><a href="#A001001">1.1. Encoding seemed to work fine, but I don't -get any sound</a></p> -<p><a href="#A001002">1.2. Not every title of the DVD shows up in -HandBrake</a></p> -<p><a href="#A001003">1.3. Rip exits after a while with a AC3 error. -What does that mean?</a></p> - -<h4>2. Features</h4> -<p><a href="#A002001">2.1 I want to convert a movie so I can burn it on -a VCD or a DVD-R. Is HandBrake the right application to do this?</a></p> -<p><a href="#A002002">2.2. I want to to convert a movie so I can edit it -in iMovie. Is HandBrake the right application to do this?</a></p> -<p><a href="#A002003">2.3. I wish HandBrake could support subtitles, rip -a 30 seconds sample, [...]</a></p> -<p><a href="#A002004">2.4. Any plan to include 3ivx / DivX 5 -encoding?</a></p> - -<h4>3. Technical</h4> -<p><a href="#A003001">3.1 What's the difference between Ffmpeg and -XviD?</a></p> -<p><a href="#A003002">3.2 What is 2-pass encoding?</a></p> - -<h4>4. Misc</h4> -<p><a href="#A004001">4.1. How do I donate for HandBrake?</a></p> -<p><a href="#A004002">4.2. Where does this stupid name / icon come -from?</a></p> - -<hr> - -<h3>1. Troubleshooting</h3> - -<a name="A001001"></a> -<h4>1.1 Encoding seemed to work fine, but I don't get any sound</h4> -<p>I guess you are trying to read an AVI file with OS X -/ Quicktime. Try installing the latest DivX codec from -<a href="http://www.divx.com/divx/mac/">DivX.com</a>, -or use <a href="http://videolan.org/vlc/">VLC</a>.</p> - -<a name="A001002"></a> -<h4>1.2. Not every title of the DVD shows up in HandBrake</h4> -<p>There are 3 reasons why HandBrake might not show a title: it is a -menu, it has no audio track HandBrake can handle (only AC3 is supported) -or there was a problem when trying to decode data from it (e.g. a -decryption problem). There is no way to workaround this, these titles -don't show up just because you can't rip them. You might check HandBrake -logs in a terminal to know what's happening on your particular DVD.</p> - -<a name="A001003"></a> -<h4>1.3. Rip exits after a while with a AC3 error. What does that -mean?</h4> -<p>It means HandBrake had to deal with corrupted data. It usually -happens when your DVD drive is over-heating after a X-hours long rip. -Though it is handy to directly rip from the DVD, I recommend that you -copy it first to the hard drive whenever possible (for example with -MacTheRipper, using "Extract Complete Disc") then you can open the -folder with HandBrake. You have to keep the DVD folder organization -(multiple VOB and IFO files), HandBrake won't open single VOB files.</p> - -<h3>2. Features</h3> - -<a name="A002001"></a> -<h4>2.1 I want to convert a movie so I can burn it on a VCD or a DVD-R. -Is HandBrake the right application to do this?</h4> -<p>No. HandBrake only outputs MPEG-4, no MPEG-1 or MPEG-2. If you are -using OS X, have a look at <a -href="http://www.versiontracker.com/dyn/moreinfo/macosx/18193"> -forty-two</a>, <a -href="http://www.versiontracker.com/dyn/moreinfo/macosx/15473"> -ffmpegX</a>, <a -href="http://www.versiontracker.com/dyn/moreinfo/macosx/20778"> -DVDRemaster</a> or <a -href="http://www.versiontracker.com/dyn/moreinfo/macosx/19238"> -DVD2oneX</a>. This will save you time and quality.</p> - -<a name="A002002"></a> -<h4>2.2 I want to to convert a movie so I can edit it in iMovie. Is -HandBrake the right application to do this?</h4> -<p>No. MPEG-4 isn't a good format for editing, you'd better find a way -to extract it as MJPEG or something, or edit the MPEG-2 directly.</p> - -<a name="A002003"></a> -<h4>2.3. I wish HandBrake could support subtitles, rip a 30 seconds -sample, [...]</h4> -<p>Check the <a href="http://handbrake.m0k.org/TODO">TODO</a> list to -see what's on the roadmap. If you wish to see a feature which isn't -already in it, mail me and, if I think I can do it someday, I'll add -it to the list.</p> - -<a name="A002004"></a> -<h4>2.4 Any plan to include 3ivx / DivX 5 encoding?</h4> - -<p>No. 3ivx/DivX aren't free software and have no multi-platform API. -Moreover, they don't bring any noticeable quality improvement to XviD -or FFmpeg. Though, you might consider using the 3ivX decoder to play -the created files as its post-processing engine is known to be pretty -good.</p> - -<h3>3. Technical</h3> - -<a name="A003001"></a> -<h4>3.1 What's the difference between Ffmpeg and XviD?</h4> -<p>Both are MPEG-4 compliant encoders, so you may choose whichever you -want. However, I would recommend Ffmpeg as it is pretty faster on BeOS -and OS X.</p> - -<a name="A003002"></a> -<h4>3.2 What is 2-pass encoding?</h4> -<p>It performs a slower but better compression - basically it makes -sure you'll get a constant quality so you won't see blocks in fast -motion scenes. Though it's disabled by default, I would strongly -recommend to use it except if you really care about time.</p> - -<h3>4. Misc</h3> - -<a name="A004001"></a> -<h4>4.1. How do I donate for HandBrake?</h4> - -<p>I'm working on HandBrake for fun, therefore I haven't set up a -paypal account or anything (and I won't). Thanks anyway to people who -wanted to give me money ;p<br> -There are still two ways to make me happy:</p> -<ul> -<li>Send me a friendly email</li> -<li>You may send me a DVD (for example, a DVD HandBrake has problems -with so I can work it out). Sending a DVD through the world isn't really -handy though (the cheapest way is probably to order it online in a -french store with my address for shipping), so if it's a problem, you -can just fall back on the friendly mail ;)<br> -<br> -Here's the address:<br> -Eric Petit<br> -R�sidence ECP - H211<br> -2 avenue Sully Prudhomme<br> -92290 Chatenay Malabry<br> -France<br> -</li> -</ul> - -<a name="A004002"></a> -<h4>4.2 Where does this stupid name / icon come from?</h4> -<p>Don't ask.</p> - diff --git a/doc/genhtml.sh b/doc/genhtml.sh deleted file mode 100755 index a88d4149a..000000000 --- a/doc/genhtml.sh +++ /dev/null @@ -1,42 +0,0 @@ -#! /bin/sh - -rm -f faq.html - -DATE=$( grep "^\$Id" faq.txt | awk '{ print $4 " " $5; }' ) - -cat > faq.html << EOF -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> -<title>HandBrake FAQ</title> -<style type="text/css"> -body,p,th,td { font-family: Verdana,Arial,Helvetica,sans-serif; - font-size: 8pt; - font-weight: normal; - color: #000000; } -body { margin-left: 10; - margin-top: 10; - margin-right: 10; - margin-bottom: 10; - background-color: #FFFFFF; } -a { color: #000000; - text-decoration: underline; } -a:hover { color: #888888; } -</style> -</head> -<body bgcolor="#ffffff"> - -<p> -Last updated: ${DATE}<br> -The latest version of this FAQ can be found <a -href="http://handbrake.m0k.org/faq.php">here</a>. -</p> -EOF - -cat faq.txt | grep -v "^\$Id" >> faq.html - -cat >> faq.html << EOF -</body> -</html> -EOF - diff --git a/libhb/Jamfile b/libhb/Jamfile new file mode 100644 index 000000000..29f9c7774 --- /dev/null +++ b/libhb/Jamfile @@ -0,0 +1,18 @@ +# $Id: Jamfile,v 1.34 2005/10/15 18:05:03 titer Exp $ +# +# This file is part of the HandBrake source code. +# Homepage: <http://handbrake.m0k.org/>. +# It may be used under the terms of the GNU General Public License. + +SubDir TOP libhb ; + +LIBHB_SRC = +common.c hb.c ports.c scan.c work.c decmpeg2.c encavcodec.c update.c +demuxmpeg.c fifo.c render.c reader.c muxcommon.c muxmp4.c sync.c +decsub.c deca52.c encfaac.c declpcm.c encx264.c decavcodec.c encxvid.c +muxavi.c enclame.c muxogm.c encvorbis.c dvd.c ; + +Library libhb : $(LIBHB_SRC) ; + +ObjectCcFlags $(LIBHB_SRC) : -I$(TOP)/contrib/include ; +ObjectDefines $(LIBHB_SRC) : __LIBHB__ ; diff --git a/libhb/common.c b/libhb/common.c new file mode 100644 index 000000000..7bd125c84 --- /dev/null +++ b/libhb/common.c @@ -0,0 +1,502 @@ +/* $Id: common.c,v 1.15 2005/03/17 19:22:47 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include <stdarg.h> +#include <time.h> +#include <sys/time.h> + +#include "common.h" + +/********************************************************************** + * Global variables + *********************************************************************/ +hb_rate_t hb_video_rates[] = +{ { "5", 5400000 }, { "10", 2700000 }, { "12", 2250000 }, + { "15", 1800000 }, { "23.976", 1126125 }, { "24", 1125000 }, + { "25", 1080000 }, { "29.97", 900900 } }; +int hb_video_rates_count = sizeof( hb_video_rates ) / + sizeof( hb_rate_t ); + +hb_rate_t hb_audio_rates[] = +{ { "22050", 22050 }, { "24000", 24000 }, + { "44100", 44100 }, { "48000", 48000 } }; +int hb_audio_rates_count = sizeof( hb_audio_rates ) / + sizeof( hb_rate_t ); +int hb_audio_rates_default = 2; /* 44100 Hz */ + +hb_rate_t hb_audio_bitrates[] = +{ { "32", 32 }, { "40", 40 }, { "48", 48 }, { "56", 56 }, + { "64", 64 }, { "80", 80 }, { "96", 96 }, { "112", 112 }, + { "128", 128 }, { "160", 160 }, { "192", 192 }, { "224", 224 }, + { "256", 256 }, { "320", 320 } }; +int hb_audio_bitrates_count = sizeof( hb_audio_bitrates ) / + sizeof( hb_rate_t ); +int hb_audio_bitrates_default = 8; /* 128 kbps */ + +/********************************************************************** + * hb_fix_aspect + ********************************************************************** + * Given the output width (if HB_KEEP_WIDTH) or height + * (HB_KEEP_HEIGHT) and the current crop values, calculates the + * correct height or width in order to respect the DVD aspect ratio + *********************************************************************/ +void hb_fix_aspect( hb_job_t * job, int keep ) +{ + hb_title_t * title = job->title; + int i; + + /* Sanity checks: + Widths and heights must be multiples of 16 and greater than or + equal to 16 + Crop values must be multiples of 2, greater than or equal to 0 + and less than half of the dimension */ + job->width = MULTIPLE_16( job->width ); + job->height = MULTIPLE_16( job->height ); + job->width = MAX( 16, job->width ); + job->height = MAX( 16, job->height ); + for( i = 0; i < 4; i++ ) + { + job->crop[i] = EVEN( job->crop[i] ); + job->crop[i] = MAX( 0, job->crop[i] ); + if( i < 2 ) + { + /* Top, bottom */ + job->crop[i] = MIN( job->crop[i], ( title->height / 2 ) - 2 ); + } + else + { + /* Left, right */ + job->crop[i] = MIN( job->crop[i], ( title->width / 2 ) - 2 ); + } + } + + if( keep == HB_KEEP_WIDTH ) + { + job->height = MULTIPLE_16( + (uint64_t) job->width * title->width * HB_ASPECT_BASE * + ( title->height - job->crop[0] - job->crop[1] ) / + ( (uint64_t) title->height * title->aspect * + ( title->width - job->crop[2] - job->crop[3] ) ) ); + job->height = MAX( 16, job->height ); + } + else + { + job->width = MULTIPLE_16( + (uint64_t) job->height * title->height * title->aspect * + ( title->width - job->crop[2] - job->crop[3] ) / + ( (uint64_t) title->width * HB_ASPECT_BASE * + ( title->height - job->crop[0] - job->crop[1] ) ) ); + job->width = MAX( 16, job->width ); + } +} + +/********************************************************************** + * hb_calc_bitrate + ********************************************************************** + * size: in megabytes + *********************************************************************/ +int hb_calc_bitrate( hb_job_t * job, int size ) +{ + int64_t avail = (int64_t) size * 1024 * 1024; + int64_t length; + int overhead; + int samples_per_frame; + int i; + + hb_title_t * title = job->title; + hb_chapter_t * chapter; + hb_audio_t * audio; + + /* How many overhead bytes are used for each frame + (quite guessed) */ + switch( job->mux ) + { + case HB_MUX_MP4: + overhead = 6; + break; + case HB_MUX_AVI: + overhead = 24; + break; + case HB_MUX_OGM: + overhead = 6; + break; + default: + return 0; + } + + /* How many audio samples we put in each frame */ + switch( job->acodec ) + { + case HB_ACODEC_FAAC: + case HB_ACODEC_VORBIS: + samples_per_frame = 1024; + break; + case HB_ACODEC_LAME: + samples_per_frame = 1152; + break; + case HB_ACODEC_AC3: + samples_per_frame = 1536; + break; + default: + return 0; + } + + /* Get the duration in seconds */ + length = 0; + for( i = job->chapter_start; i <= job->chapter_end; i++ ) + { + chapter = hb_list_item( title->list_chapter, i - 1 ); + length += chapter->duration; + } + length += 135000; + length /= 90000; + + /* Video overhead */ + avail -= length * job->vrate * overhead / job->vrate_base; + + for( i = 0; job->audios[i] >= 0; i++ ) + { + /* Audio data */ + int abitrate; + if( job->acodec & HB_ACODEC_AC3 ) + { + audio = hb_list_item( title->list_audio, job->audios[i] ); + abitrate = audio->bitrate / 8; + } + else + { + abitrate = job->abitrate * 1000 / 8; + } + avail -= length * abitrate; + + /* Audio overhead */ + avail -= length * job->arate * overhead / samples_per_frame; + } + + if( avail < 0 ) + { + return 0; + } + + return ( avail / ( 125 * length ) ); +} + +/********************************************************************** + * hb_list implementation + ********************************************************************** + * Basic and slow, but enough for what we need + *********************************************************************/ + +#define HB_LIST_DEFAULT_SIZE 20 + +struct hb_list_s +{ + /* Pointers to items in the list */ + void ** items; + + /* How many (void *) allocated in 'items' */ + int items_alloc; + + /* How many valid pointers in 'items' */ + int items_count; +}; + +/********************************************************************** + * hb_list_init + ********************************************************************** + * Allocates an empty list ready for HB_LIST_DEFAULT_SIZE items + *********************************************************************/ +hb_list_t * hb_list_init() +{ + hb_list_t * l; + + l = calloc( sizeof( hb_list_t ), 1 ); + l->items = calloc( HB_LIST_DEFAULT_SIZE * sizeof( void * ), 1 ); + l->items_alloc = HB_LIST_DEFAULT_SIZE; + + return l; +} + +/********************************************************************** + * hb_list_count + ********************************************************************** + * Returns the number of items currently in the list + *********************************************************************/ +int hb_list_count( hb_list_t * l ) +{ + return l->items_count; +} + +/********************************************************************** + * hb_list_add + ********************************************************************** + * Adds an item at the end of the list, making it bigger if necessary. + * Can safely be called with a NULL pointer to add, it will be ignored. + *********************************************************************/ +void hb_list_add( hb_list_t * l, void * p ) +{ + if( !p ) + { + return; + } + + if( l->items_count == l->items_alloc ) + { + /* We need a bigger boat */ + l->items_alloc += HB_LIST_DEFAULT_SIZE; + l->items = realloc( l->items, + l->items_alloc * sizeof( void * ) ); + } + + l->items[l->items_count] = p; + (l->items_count)++; +} + +/********************************************************************** + * hb_list_rem + ********************************************************************** + * Remove an item from the list. Bad things will happen if called + * with a NULL pointer or if the item is not in the list. + *********************************************************************/ +void hb_list_rem( hb_list_t * l, void * p ) +{ + int i; + + /* Find the item in the list */ + for( i = 0; i < l->items_count; i++ ) + { + if( l->items[i] == p ) + { + break; + } + } + + /* Shift all items after it sizeof( void * ) bytes earlier */ + memmove( &l->items[i], &l->items[i+1], + ( l->items_count - i - 1 ) * sizeof( void * ) ); + + (l->items_count)--; +} + +/********************************************************************** + * hb_list_item + ********************************************************************** + * Returns item at position i, or NULL if there are not that many + * items in the list + *********************************************************************/ +void * hb_list_item( hb_list_t * l, int i ) +{ + if( i < 0 || i >= l->items_count ) + { + return NULL; + } + + return l->items[i]; +} + +/********************************************************************** + * hb_list_bytes + ********************************************************************** + * Assuming all items are of type hb_buffer_t, returns the total + * number of bytes in the list + *********************************************************************/ +int hb_list_bytes( hb_list_t * l ) +{ + hb_buffer_t * buf; + int ret; + int i; + + ret = 0; + for( i = 0; i < hb_list_count( l ); i++ ) + { + buf = hb_list_item( l, i ); + ret += buf->size - buf->cur; + } + + return ret; +} + +/********************************************************************** + * hb_list_seebytes + ********************************************************************** + * Assuming all items are of type hb_buffer_t, copy <size> bytes from + * the list to <dst>, keeping the list unmodified. + *********************************************************************/ +void hb_list_seebytes( hb_list_t * l, uint8_t * dst, int size ) +{ + hb_buffer_t * buf; + int copied; + int copying; + int i; + + for( i = 0, copied = 0; copied < size; i++ ) + { + buf = hb_list_item( l, i ); + copying = MIN( buf->size - buf->cur, size - copied ); + memcpy( &dst[copied], &buf->data[buf->cur], copying ); + copied += copying; + } +} + +/********************************************************************** + * hb_list_getbytes + ********************************************************************** + * Assuming all items are of type hb_buffer_t, copy <size> bytes from + * the list to <dst>. What's copied is removed from the list. + * The variable pointed by <pts> is set to the PTS of the buffer the + * first byte has been got from. + * The variable pointed by <pos> is set to the position of that byte + * in that buffer. + *********************************************************************/ +void hb_list_getbytes( hb_list_t * l, uint8_t * dst, int size, + uint64_t * pts, int * pos ) +{ + hb_buffer_t * buf; + int copied; + int copying; + uint8_t has_pts; + + /* So we won't have to deal with NULL pointers */ + uint64_t dummy1; + int dummy2; + if( !pts ) pts = &dummy1; + if( !pos ) pos = &dummy2; + + for( copied = 0, has_pts = 0; copied < size; ) + { + buf = hb_list_item( l, 0 ); + copying = MIN( buf->size - buf->cur, size - copied ); + memcpy( &dst[copied], &buf->data[buf->cur], copying ); + + if( !has_pts ) + { + *pts = buf->start; + *pos = buf->cur; + has_pts = 1; + } + + buf->cur += copying; + if( buf->cur >= buf->size ) + { + hb_list_rem( l, buf ); + hb_buffer_close( &buf ); + } + + copied += copying; + } +} + +/********************************************************************** + * hb_list_empty + ********************************************************************** + * Assuming all items are of type hb_buffer_t, close them all and + * close the list. + *********************************************************************/ +void hb_list_empty( hb_list_t ** _l ) +{ + hb_list_t * l = *_l; + hb_buffer_t * b; + + while( ( b = hb_list_item( l, 0 ) ) ) + { + hb_list_rem( l, b ); + hb_buffer_close( &b ); + } + + hb_list_close( _l ); +} + +/********************************************************************** + * hb_list_close + ********************************************************************** + * Free memory allocated by hb_list_init. Does NOT free contents of + * items still in the list. + *********************************************************************/ +void hb_list_close( hb_list_t ** _l ) +{ + hb_list_t * l = *_l; + + free( l->items ); + free( l ); + + *_l = NULL; +} + +/********************************************************************** + * hb_log + ********************************************************************** + * If verbose mode is one, print message with timestamp. Messages + * longer than 80 characters are stripped ;p + *********************************************************************/ +void hb_log( char * log, ... ) +{ + char string[82]; /* 80 chars + \n + \0 */ + time_t _now; + struct tm * now; + va_list args; + + if( !getenv( "HB_DEBUG" ) ) + { + /* We don't want to print it */ + return; + } + + /* Get the time */ + _now = time( NULL ); + now = localtime( &_now ); + sprintf( string, "[%02d:%02d:%02d] ", + now->tm_hour, now->tm_min, now->tm_sec ); + + /* Convert the message to a string */ + va_start( args, log ); + vsnprintf( string + 11, 69, log, args ); + va_end( args ); + + /* Add the end of line */ + strcat( string, "\n" ); + + /* Print it */ + fprintf( stderr, "%s", string ); +} + +/********************************************************************** + * hb_title_init + ********************************************************************** + * + *********************************************************************/ +hb_title_t * hb_title_init( char * dvd, int index ) +{ + hb_title_t * t; + + t = calloc( sizeof( hb_title_t ), 1 ); + + t->index = index; + t->list_audio = hb_list_init(); + t->list_chapter = hb_list_init(); + t->list_subtitle = hb_list_init(); + strcat( t->dvd, dvd ); + + return t; +} + +/********************************************************************** + * hb_title_close + ********************************************************************** + * + *********************************************************************/ +void hb_title_close( hb_title_t ** _t ) +{ + hb_title_t * t = *_t; + + hb_list_close( &t->list_audio ); + hb_list_close( &t->list_chapter ); + hb_list_close( &t->list_subtitle ); + free( t->job ); + + free( t ); + *_t = NULL; +} + diff --git a/libhb/common.h b/libhb/common.h new file mode 100644 index 000000000..402ae7f29 --- /dev/null +++ b/libhb/common.h @@ -0,0 +1,349 @@ +/* $Id: common.h,v 1.51 2005/11/04 13:09:40 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#ifndef HB_COMMON_H +#define HB_COMMON_H + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <inttypes.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> + +#ifndef MIN +#define MIN( a, b ) ( (a) > (b) ? (b) : (a) ) +#endif +#ifndef MAX +#define MAX( a, b ) ( (a) > (b) ? (a) : (b) ) +#endif + +#define EVEN( a ) ( (a) + ( (a) & 1 ) ) +#define MULTIPLE_16( a ) ( 16 * ( ( (a) + 8 ) / 16 ) ) + +typedef struct hb_handle_s hb_handle_t; +typedef struct hb_list_s hb_list_t; +typedef struct hb_rate_s hb_rate_t; +typedef struct hb_job_s hb_job_t; +typedef struct hb_title_s hb_title_t; +typedef struct hb_chapter_s hb_chapter_t; +typedef struct hb_audio_s hb_audio_t; +typedef struct hb_subtitle_s hb_subtitle_t; +typedef struct hb_state_s hb_state_t; + +#include "ports.h" +#ifdef __LIBHB__ +#include "internal.h" +#endif + +hb_list_t * hb_list_init(); +int hb_list_count( hb_list_t * ); +void hb_list_add( hb_list_t *, void * ); +void hb_list_rem( hb_list_t *, void * ); +void * hb_list_item( hb_list_t *, int ); +void hb_list_close( hb_list_t ** ); + +#define HB_KEEP_WIDTH 0 +#define HB_KEEP_HEIGHT 1 +void hb_fix_aspect( hb_job_t * job, int keep ); + +int hb_calc_bitrate( hb_job_t *, int size ); + +struct hb_rate_s +{ + char * string; + int rate; +}; + +#define HB_ASPECT_BASE 9 +#define HB_VIDEO_RATE_BASE 27000000 + +extern hb_rate_t hb_video_rates[]; +extern int hb_video_rates_count; +extern hb_rate_t hb_audio_rates[]; +extern int hb_audio_rates_count; +extern int hb_audio_rates_default; +extern hb_rate_t hb_audio_bitrates[]; +extern int hb_audio_bitrates_count; +extern int hb_audio_bitrates_default; + +/****************************************************************************** + * hb_job_t: settings to be filled by the UI + *****************************************************************************/ +struct hb_job_s +{ + /* Pointer to the title to be ripped */ + hb_title_t * title; + + /* Chapter selection */ + int chapter_start; + int chapter_end; + + /* Picture settings: + crop: must be multiples of 2 (top/bottom/left/right) + deinterlace: 0 or 1 + width: must be a multiple of 16 + height: must be a multiple of 16 + keep_ratio: used by UIs */ + int crop[4]; + int deinterlace; + int width; + int height; + int keep_ratio; + int grayscale; + + /* Video settings: + vcodec: output codec + vquality: output quality (0.0..1.0) + if < 0.0 or > 1.0, bitrate is used instead + vbitrate: output bitrate (kbps) + pass: 0, 1 or 2 + vrate, vrate_base: output framerate is vrate / vrate_base */ +#define HB_VCODEC_MASK 0x0000FF +#define HB_VCODEC_FFMPEG 0x000001 +#define HB_VCODEC_XVID 0x000002 +#define HB_VCODEC_X264 0x000004 + int vcodec; + float vquality; + int vbitrate; + int vrate; + int vrate_base; + int pass; + int h264_13; + + /* Audio tracks: + Indexes in hb_title_t's audios list, starting from 0. + -1 indicates the end of the list */ + int audios[8]; + + /* Audio settings: + acodec: output codec + abitrate: output bitrate (kbps) + arate: output samplerate (Hz) + HB_ACODEC_AC3 means pass-through, then abitrate and arate are + ignored */ +#define HB_ACODEC_MASK 0x00FF00 +#define HB_ACODEC_FAAC 0x000100 +#define HB_ACODEC_LAME 0x000200 +#define HB_ACODEC_VORBIS 0x000400 +#define HB_ACODEC_AC3 0x000800 +#define HB_ACODEC_MPGA 0x001000 +#define HB_ACODEC_LPCM 0x002000 + int acodec; + int abitrate; + int arate; + + /* Subtitle settings: + subtitle: index in hb_title_t's subtitles list, starting + from 0. -1 means no subtitle */ + int subtitle; + + /* Muxer settings + mux: output file format + file: file path */ +#define HB_MUX_MASK 0xFF0000 +#define HB_MUX_MP4 0x010000 +#define HB_MUX_AVI 0x020000 +#define HB_MUX_OGM 0x040000 + int mux; + char * file; + +#ifdef __LIBHB__ + /* Internal data */ + hb_handle_t * h; + hb_lock_t * pause; + volatile int * die; + volatile int done; + + hb_fifo_t * fifo_mpeg2; /* MPEG-2 video ES */ + hb_fifo_t * fifo_raw; /* Raw pictures */ + hb_fifo_t * fifo_sync; /* Raw pictures, framerate corrected */ + hb_fifo_t * fifo_render; /* Raw pictures, scaled */ + hb_fifo_t * fifo_mpeg4; /* MPEG-4 video ES */ + + hb_thread_t * reader; + hb_thread_t * muxer; + + hb_list_t * list_work; + + union + { + struct + { + uint8_t * config; + int config_length; + } mpeg4; + + struct + { + uint8_t * sps; + int sps_length; + uint8_t * pps; + int pps_length; + } h264; + + } config; + + /* MPEG-4 / AVC */ + uint8_t * es_config; + int es_config_length; + + hb_mux_data_t * mux_data; +#endif +}; + +struct hb_audio_s +{ + int id; + char lang[1024]; + int codec; + int rate; + int bitrate; + int channels; + +#ifdef __LIBHB__ + /* Internal data */ + hb_fifo_t * fifo_in; /* AC3/MPEG/LPCM ES */ + hb_fifo_t * fifo_raw; /* Raw audio */ + hb_fifo_t * fifo_sync; /* Resampled, synced raw audio */ + hb_fifo_t * fifo_out; /* MP3/AAC/Vorbis ES */ + + union + { + struct + { + uint8_t * decinfo; + unsigned long size; + } faac; + + struct + { + uint8_t * headers[3]; + int sizes[3]; + } vorbis; + + } config; + + hb_mux_data_t * mux_data; +#endif +}; + +struct hb_chapter_s +{ + int index; + int cell_start; + int cell_end; + int block_start; + int block_end; + int block_count; + + /* Visual-friendly duration */ + int hours; + int minutes; + int seconds; + + /* Exact duration (in 1/90000s) */ + uint64_t duration; +}; + +struct hb_subtitle_s +{ + int id; + char lang[1024]; + +#ifdef __LIBHB__ + /* Internal data */ + hb_fifo_t * fifo_in; /* SPU ES */ + hb_fifo_t * fifo_raw; /* Decodec SPU */ +#endif +}; + +struct hb_title_s +{ + char dvd[1024]; + int index; + int vts; + int ttn; + int cell_start; + int cell_end; + int block_start; + int block_end; + int block_count; + + /* Visual-friendly duration */ + int hours; + int minutes; + int seconds; + + /* Exact duration (in 1/90000s) */ + uint64_t duration; + + int width; + int height; + int aspect; + int rate; + int rate_base; + int crop[4]; + + uint32_t palette[16]; + + hb_list_t * list_chapter; + hb_list_t * list_audio; + hb_list_t * list_subtitle; + + /* Job template for this title */ + hb_job_t * job; +}; + + +struct hb_state_s +{ +#define HB_STATE_IDLE 1 +#define HB_STATE_SCANNING 2 +#define HB_STATE_SCANDONE 4 +#define HB_STATE_WORKING 8 +#define HB_STATE_PAUSED 16 +#define HB_STATE_WORKDONE 32 + int state; + + union + { + struct + { + /* HB_STATE_SCANNING */ + int title_cur; + int title_count; + } scanning; + + struct + { + /* HB_STATE_WORKING */ + float progress; + int job_cur; + int job_count; + float rate_cur; + float rate_avg; + int hours; + int minutes; + int seconds; + } working; + + struct + { + /* HB_STATE_WORKDONE */ +#define HB_ERROR_NONE 0 +#define HB_ERROR_CANCELED 1 +#define HB_ERROR_UNKNOWN 2 + int error; + } workdone; + + } param; +}; + +#endif diff --git a/libhb/deca52.c b/libhb/deca52.c new file mode 100644 index 000000000..a4f7492b3 --- /dev/null +++ b/libhb/deca52.c @@ -0,0 +1,200 @@ +/* $Id: deca52.c,v 1.14 2005/03/03 17:21:57 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "a52dec/a52.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + hb_audio_t * audio; + + /* liba52 handle */ + a52_state_t * state; + + int flags_in; + int flags_out; + int rate; + int bitrate; + float level; + + int error; + int sync; + int size; + + uint8_t frame[3840]; + + hb_list_t * list; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); +static hb_buffer_t * Decode( hb_work_object_t * w ); + +/*********************************************************************** + * hb_work_deca52_init + *********************************************************************** + * Allocate the work object, initialize liba52 + **********************************************************************/ +hb_work_object_t * hb_work_deca52_init( hb_job_t * job, hb_audio_t * audio ) +{ + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "AC3 decoder" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->audio = audio; + + w->list = hb_list_init(); + w->state = a52_init( 0 ); + w->flags_out = A52_STEREO; + w->level = 32768.0; + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * Free memory + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + a52_free( w->state ); + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * Add the given buffer to the data we already have, and decode as much + * as we can + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * buf; + + hb_list_add( w->list, *buf_in ); + *buf_in = NULL; + + /* If we got more than a frame, chain raw buffers */ + *buf_out = buf = Decode( w ); + while( buf ) + { + buf->next = Decode( w ); + buf = buf->next; + } + + return HB_WORK_OK; +} + +/*********************************************************************** + * Decode + *********************************************************************** + * + **********************************************************************/ +static hb_buffer_t * Decode( hb_work_object_t * w ) +{ + hb_buffer_t * buf; + int i, j; + uint64_t pts; + int pos; + + /* Get a frame header if don't have one yet */ + if( !w->sync ) + { + while( hb_list_bytes( w->list ) >= 7 ) + { + /* We have 7 bytes, check if this is a correct header */ + hb_list_seebytes( w->list, w->frame, 7 ); + w->size = a52_syncinfo( w->frame, &w->flags_in, &w->rate, + &w->bitrate ); + if( w->size ) + { + /* It is. W00t. */ + if( w->error ) + { + hb_log( "a52_syncinfo ok" ); + } + w->error = 0; + w->sync = 1; + break; + } + + /* It is not */ + if( !w->error ) + { + hb_log( "a52_syncinfo failed" ); + w->error = 1; + } + + /* Try one byte later */ + hb_list_getbytes( w->list, w->frame, 1, NULL, NULL ); + } + } + + if( !w->sync || + hb_list_bytes( w->list ) < w->size ) + { + /* Need more data */ + return NULL; + } + + /* Get the whole frame */ + hb_list_getbytes( w->list, w->frame, w->size, &pts, &pos ); + + /* AC3 passthrough: don't decode the AC3 frame */ + if( w->job->acodec & HB_ACODEC_AC3 ) + { + buf = hb_buffer_init( w->size ); + memcpy( buf->data, w->frame, w->size ); + buf->start = pts + ( pos / w->size ) * 6 * 256 * 90000 / w->rate; + buf->stop = buf->start + 6 * 256 * 90000 / w->rate; + w->sync = 0; + return buf; + } + + /* Feed liba52 */ + a52_frame( w->state, w->frame, &w->flags_out, &w->level, 0 ); + + /* 6 blocks per frame, 256 samples per block, 2 channels */ + buf = hb_buffer_init( 3072 * sizeof( float ) ); + buf->start = pts + ( pos / w->size ) * 6 * 256 * 90000 / w->rate; + buf->stop = buf->start + 6 * 256 * 90000 / w->rate; + + for( i = 0; i < 6; i++ ) + { + sample_t * samples_in; + float * samples_out; + + a52_block( w->state ); + samples_in = a52_samples( w->state ); + samples_out = ((float *) buf->data) + 512 * i; + + /* Interleave */ + for( j = 0; j < 256; j++ ) + { + samples_out[2*j] = samples_in[j]; + samples_out[2*j+1] = samples_in[256+j]; + } + } + + w->sync = 0; + return buf; +} + diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c new file mode 100644 index 000000000..f18579f36 --- /dev/null +++ b/libhb/decavcodec.c @@ -0,0 +1,137 @@ +/* $Id: decavcodec.c,v 1.6 2005/03/06 04:08:54 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "ffmpeg/avcodec.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + hb_audio_t * audio; + + AVCodecContext * context; + int64_t pts_last; +}; + + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); +static void Close( hb_work_object_t ** _w ); + +/*********************************************************************** + * hb_work_decavcodec_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_decavcodec_init( hb_job_t * job, + hb_audio_t * audio ) +{ + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + AVCodec * codec; + w->name = strdup( "MPGA decoder (libavcodec)" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->audio = audio; + + codec = avcodec_find_decoder( CODEC_ID_MP2 ); + w->context = avcodec_alloc_context(); + avcodec_open( w->context, codec ); + w->pts_last = -1; + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + avcodec_close( w->context ); + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * in = *buf_in, * buf, * last = NULL; + int pos, len, out_size, i; + short buffer[AVCODEC_MAX_AUDIO_FRAME_SIZE]; + uint64_t cur; + + *buf_out = NULL; + + if( in->start < 0 || + ( w->pts_last > 0 && + in->start > w->pts_last && + in->start - w->pts_last < 5000 ) ) /* Hacky */ + { + cur = w->pts_last; + } + else + { + cur = in->start; + } + + pos = 0; + while( pos < in->size ) + { + len = avcodec_decode_audio( w->context, buffer, &out_size, + in->data + pos, in->size - pos ); + if( out_size ) + { + short * s16; + float * fl32; + + buf = hb_buffer_init( 2 * out_size ); + + buf->start = cur; + buf->stop = cur + 90000 * ( out_size / 4 ) / + w->context->sample_rate; + cur = buf->stop; + + s16 = buffer; + fl32 = (float *) buf->data; + for( i = 0; i < out_size / 2; i++ ) + { + fl32[i] = s16[i]; + } + + if( last ) + { + last = last->next = buf; + } + else + { + *buf_out = last = buf; + } + } + + pos += len; + } + + w->pts_last = cur; + + return HB_WORK_OK; +} + diff --git a/libhb/declpcm.c b/libhb/declpcm.c new file mode 100644 index 000000000..59163c366 --- /dev/null +++ b/libhb/declpcm.c @@ -0,0 +1,113 @@ +/* $Id: declpcm.c,v 1.8 2005/11/04 14:44:01 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + hb_audio_t * audio; + + int64_t pts_last; +}; + +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * in = *buf_in, * out; + int samplerate = 0; + int count; + uint8_t * samples_u8; + float * samples_fl32; + int i; + uint64_t duration; + + *buf_out = NULL; + + if( in->data[5] != 0x80 ) + { + hb_log( "no LPCM frame sync (%02x)", in->data[5] ); + return HB_WORK_OK; + } + + switch( ( in->data[4] >> 4 ) & 0x3 ) + { + case 0: + samplerate = 48000; + break; + case 1: + samplerate = 96000;//32000; /* FIXME vlc says it is 96000 */ + break; + case 2: + samplerate = 44100; + break; + case 3: + samplerate = 32000; + break; + } + + count = ( in->size - 6 ) / 2; + out = hb_buffer_init( count * sizeof( float ) ); + duration = count * 90000 / samplerate / 2; + if( w->pts_last > 0 && + in->start < w->pts_last + duration / 6 && + in->start > w->pts_last - duration / 6 ) + { + /* Workaround for DVDs where dates aren't exact */ + out->start = w->pts_last; + } + else + { + out->start = in->start; + } + out->stop = out->start + duration; + w->pts_last = out->stop; + + samples_u8 = in->data + 6; + samples_fl32 = (float *) out->data; + + /* Big endian int16 -> float conversion */ + for( i = 0; i < count; i++ ) + { +#ifdef WORDS_BIGENDIAN + samples_fl32[0] = *( (int16_t *) samples_u8 ); +#else + samples_fl32[0] = (int16_t) ( ( samples_u8[0] << 8 ) | samples_u8[1] ); +#endif + samples_u8 += 2; + samples_fl32 += 1; + } + + *buf_out = out; + + return HB_WORK_OK; +} + +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + free( w->name ); + free( w ); + *_w = NULL; +} + +hb_work_object_t * hb_work_declpcm_init( hb_job_t * job, hb_audio_t * audio ) +{ + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "LPCM decoder" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->audio = audio; + + w->pts_last = -1; + + return w; +} + diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c new file mode 100644 index 000000000..d914c03a6 --- /dev/null +++ b/libhb/decmpeg2.c @@ -0,0 +1,253 @@ +/* $Id: decmpeg2.c,v 1.12 2005/03/03 16:30:42 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "mpeg2dec/mpeg2.h" + +/********************************************************************** + * hb_libmpeg2_t + ********************************************************************** + * A convenient libmpeg wrapper, used both here and in scan.c + *********************************************************************/ +struct hb_libmpeg2_s +{ + mpeg2dec_t * libmpeg2; + const mpeg2_info_t * info; + int width; + int height; + int rate; + int got_iframe; + int64_t last_pts; +}; + +/********************************************************************** + * hb_libmpeg2_init + ********************************************************************** + * + *********************************************************************/ +hb_libmpeg2_t * hb_libmpeg2_init() +{ + hb_libmpeg2_t * m = calloc( sizeof( hb_libmpeg2_t ), 1 ); + + m->libmpeg2 = mpeg2_init(); + m->info = mpeg2_info( m->libmpeg2 ); + m->last_pts = -1; + + return m; +} + +/********************************************************************** + * hb_libmpeg2_decode + ********************************************************************** + * + *********************************************************************/ +int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, + hb_list_t * list_raw ) +{ + mpeg2_state_t state; + hb_buffer_t * buf; + uint8_t * data; + + /* Feed libmpeg2 */ + if( buf_es->start > -1 ) + { + mpeg2_tag_picture( m->libmpeg2, buf_es->start >> 32, + buf_es->start & 0xFFFFFFFF ); + } + mpeg2_buffer( m->libmpeg2, buf_es->data, + buf_es->data + buf_es->size ); + + for( ;; ) + { + state = mpeg2_parse( m->libmpeg2 ); + if( state == STATE_BUFFER ) + { + /* Require some more data */ + break; + } + else if( state == STATE_SEQUENCE ) + { + if( !( m->width && m->height && m->rate ) ) + { + m->width = m->info->sequence->width; + m->height = m->info->sequence->height; + m->rate = m->info->sequence->frame_period; + + if( m->rate == 900900 ) + { + /* 29.97 fps. 3:2 pulldown might, or might not be + used. I can't find a way to know, so we always + output 23.976 */ + m->rate = 1126125; + } + } + } + else if( ( state == STATE_SLICE || state == STATE_END ) && + m->info->display_fbuf ) + { + if( ( m->info->display_picture->flags & + PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I ) + { + m->got_iframe = 1; + } + + if( m->got_iframe ) + { + buf = hb_buffer_init( m->width * m->height * 3 / 2 ); + data = buf->data; + + memcpy( data, m->info->display_fbuf->buf[0], + m->width * m->height ); + data += m->width * m->height; + memcpy( data, m->info->display_fbuf->buf[1], + m->width * m->height / 4 ); + data += m->width * m->height / 4; + memcpy( data, m->info->display_fbuf->buf[2], + m->width * m->height / 4 ); + + if( m->info->display_picture->flags & PIC_FLAG_TAGS ) + { + buf->start = + ( (uint64_t) m->info->display_picture->tag << 32 ) | + ( (uint64_t) m->info->display_picture->tag2 ); + } + else if( m->last_pts > -1 ) + { + /* For some reason nb_fields is sometimes 1 while it + should be 2 */ + buf->start = m->last_pts + + MAX( 2, m->info->display_picture->nb_fields ) * + m->info->sequence->frame_period / 600; + } + else + { + buf->start = -1; + } + m->last_pts = buf->start; + + hb_list_add( list_raw, buf ); + } + } + else if( state == STATE_INVALID ) + { + mpeg2_reset( m->libmpeg2, 0 ); + } + } + return 1; +} + +/********************************************************************** + * hb_libmpeg2_info + ********************************************************************** + * + *********************************************************************/ +void hb_libmpeg2_info( hb_libmpeg2_t * m, int * width, int * height, + int * rate ) +{ + *width = m->width; + *height = m->height; + *rate = m->rate; +} + +/********************************************************************** + * hb_libmpeg2_close + ********************************************************************** + * + *********************************************************************/ +void hb_libmpeg2_close( hb_libmpeg2_t ** _m ) +{ + hb_libmpeg2_t * m = *_m; + + mpeg2_close( m->libmpeg2 ); + + free( m ); + *_m = NULL; +} + +/********************************************************************** + * The decmpeg2 work object + ********************************************************************** + * + *********************************************************************/ +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_libmpeg2_t * libmpeg2; + hb_list_t * list; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); +static void Close( hb_work_object_t ** _w ); + +/********************************************************************** + * hb_work_decmpeg2_init + ********************************************************************** + * + *********************************************************************/ +hb_work_object_t * hb_work_decmpeg2_init( hb_job_t * job ) +{ + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "MPEG-2 decoder (libmpeg2)" ); + w->work = Work; + w->close = Close; + + w->libmpeg2 = hb_libmpeg2_init(); + w->list = hb_list_init(); + return w; +} + +/********************************************************************** + * Work + ********************************************************************** + * + *********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * buf, * last = NULL; + + hb_libmpeg2_decode( w->libmpeg2, *buf_in, w->list ); + + *buf_out = NULL; + + while( ( buf = hb_list_item( w->list, 0 ) ) ) + { + hb_list_rem( w->list, buf ); + if( last ) + { + last->next = buf; + last = buf; + } + else + { + *buf_out = buf; + last = buf; + } + } + + return HB_WORK_OK; +} + +/********************************************************************** + * Close + ********************************************************************** + * + *********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + hb_list_close( &w->list ); + hb_libmpeg2_close( &w->libmpeg2 ); + free( w->name ); + free( w ); + *_w = NULL; +} diff --git a/libhb/decsub.c b/libhb/decsub.c new file mode 100644 index 000000000..72f742bd9 --- /dev/null +++ b/libhb/decsub.c @@ -0,0 +1,420 @@ +/* $Id: decsub.c,v 1.12 2005/04/14 17:37:54 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + + uint8_t buf[0xFFFF]; + int size_sub; + int size_got; + int size_rle; + int64_t pts; + int64_t pts_start; + int64_t pts_stop; + int x; + int y; + int width; + int height; + + int offsets[2]; + uint8_t lum[4]; + uint8_t alpha[4]; +}; + + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); +static hb_buffer_t * Decode( hb_work_object_t * w ); +static void ParseControls( hb_work_object_t * w ); +static hb_buffer_t * CropSubtitle( hb_work_object_t * w, + uint8_t * raw ); + +/*********************************************************************** + * hb_work_decsub_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_decsub_init( hb_job_t * job ) +{ + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "Subtitle decoder" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->pts = -1; + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * Free memory + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * in = *buf_in; + + int size_sub, size_rle; + + size_sub = ( in->data[0] << 8 ) | in->data[1]; + size_rle = ( in->data[2] << 8 ) | in->data[3]; + + if( !w->size_sub ) + { + /* We are looking for the start of a new subtitle */ + if( size_sub && size_rle && size_sub > size_rle && + in->size <= size_sub ) + { + /* Looks all right so far */ + w->size_sub = size_sub; + w->size_rle = size_rle; + + memcpy( w->buf, in->data, in->size ); + w->size_got = in->size; + w->pts = in->start; + } + } + else + { + /* We are waiting for the end of the current subtitle */ + if( in->size <= w->size_sub - w->size_got ) + { + memcpy( w->buf + w->size_got, in->data, in->size ); + w->size_got += in->size; + if( in->start >= 0 ) + { + w->pts = in->start; + } + } + } + + *buf_out = NULL; + + if( w->size_sub && w->size_sub == w->size_got ) + { + /* We got a complete subtitle, decode it */ + *buf_out = Decode( w ); + + /* Wait for the next one */ + w->size_sub = 0; + w->size_got = 0; + w->size_rle = 0; + w->pts = -1; + } + + return HB_WORK_OK; +} + +static hb_buffer_t * Decode( hb_work_object_t * w ) +{ + int code, line, col; + int offsets[2]; + int * offset; + hb_buffer_t * buf; + uint8_t * buf_raw = NULL; + + /* Get infos about the subtitle */ + ParseControls( w ); + + /* Do the actual decoding now */ + buf_raw = malloc( w->width * w->height * 2 ); + +#define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \ +( w->buf[((*offset)>>1)] & 0xF ) : ( w->buf[((*offset)>>1)] >> 4 ) ) ); \ +(*offset)++ + + offsets[0] = w->offsets[0] * 2; + offsets[1] = w->offsets[1] * 2; + + for( line = 0; line < w->height; line++ ) + { + /* Select even or odd field */ + offset = ( line & 1 ) ? &offsets[1] : &offsets[0]; + + for( col = 0; col < w->width; col += code >> 2 ) + { + uint8_t * lum, * alpha; + + code = 0; + GET_NEXT_NIBBLE; + if( code < 0x4 ) + { + GET_NEXT_NIBBLE; + if( code < 0x10 ) + { + GET_NEXT_NIBBLE; + if( code < 0x40 ) + { + GET_NEXT_NIBBLE; + if( code < 0x100 ) + { + /* End of line */ + code |= ( w->width - col ) << 2; + } + } + } + } + + lum = buf_raw; + alpha = lum + w->width * w->height; + memset( lum + line * w->width + col, + w->lum[code & 3], code >> 2 ); + memset( alpha + line * w->width + col, + w->alpha[code & 3], code >> 2 ); + } + + /* Byte-align */ + if( *offset & 1 ) + { + (*offset)++; + } + } + + /* Crop subtitle (remove transparent borders) */ + buf = CropSubtitle( w, buf_raw ); + + free( buf_raw ); + + return buf; +} + +/*********************************************************************** + * ParseControls + *********************************************************************** + * Get the start and end dates (relative to the PTS from the PES + * header), the width and height of the subpicture and the colors and + * alphas used in it + **********************************************************************/ +static void ParseControls( hb_work_object_t * w ) +{ + hb_job_t * job = w->job; + hb_title_t * title = job->title; + + int i; + int command; + int date, next; + + for( i = w->size_rle; ; ) + { + date = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; + next = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; + + for( ;; ) + { + command = w->buf[i++]; + + if( command == 0xFF ) + { + break; + } + + switch( command ) + { + case 0x00: + break; + + case 0x01: + w->pts_start = w->pts + date * 900; + break; + + case 0x02: + w->pts_stop = w->pts + date * 900; + break; + + case 0x03: + { + int colors[4]; + int j; + + colors[0] = (w->buf[i+0]>>4)&0x0f; + colors[1] = (w->buf[i+0])&0x0f; + colors[2] = (w->buf[i+1]>>4)&0x0f; + colors[3] = (w->buf[i+1])&0x0f; + + for( j = 0; j < 4; j++ ) + { + uint32_t color = title->palette[colors[j]]; + w->lum[3-j] = (color>>16) & 0xff; + } + i += 2; + break; + } + case 0x04: + { + w->alpha[3] = (w->buf[i+0]>>4)&0x0f; + w->alpha[2] = (w->buf[i+0])&0x0f; + w->alpha[1] = (w->buf[i+1]>>4)&0x0f; + w->alpha[0] = (w->buf[i+1])&0x0f; + i += 2; + break; + } + case 0x05: + { + w->x = (w->buf[i+0]<<4) | ((w->buf[i+1]>>4)&0x0f); + w->width = (((w->buf[i+1]&0x0f)<<8)| w->buf[i+2]) - w->x + 1; + w->y = (w->buf[i+3]<<4)| ((w->buf[i+4]>>4)&0x0f); + w->height = (((w->buf[i+4]&0x0f)<<8)| w->buf[i+5]) - w->y + 1; + i += 6; + break; + } + case 0x06: + { + w->offsets[0] = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; + w->offsets[1] = ( w->buf[i] << 8 ) | w->buf[i+1]; i += 2; + break; + } + } + } + + if( i > next ) + { + break; + } + i = next; + } +} + +/*********************************************************************** + * CropSubtitle + *********************************************************************** + * Given a raw decoded subtitle, detects transparent borders and + * returns a cropped subtitle in a hb_buffer_t ready to be used by + * the renderer, or NULL if the subtitle was completely transparent + **********************************************************************/ +static int LineIsTransparent( hb_work_object_t * w, uint8_t * p ) +{ + int i; + for( i = 0; i < w->width; i++ ) + { + if( p[i] ) + { + return 0; + } + } + return 1; +} +static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p ) +{ + int i; + for( i = 0; i < w->height; i++ ) + { + if( p[i*w->width] ) + { + return 0; + } + } + return 1; +} +static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) +{ + int i; + int crop[4] = { -1,-1,-1,-1 }; + uint8_t * alpha; + int realwidth, realheight; + hb_buffer_t * buf; + uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out; + + alpha = raw + w->width * w->height; + + /* Top */ + for( i = 0; i < w->height; i++ ) + { + if( !LineIsTransparent( w, &alpha[i*w->width] ) ) + { + crop[0] = i; + break; + } + } + + if( crop[0] < 0 ) + { + /* Empty subtitle */ + return NULL; + } + + /* Bottom */ + for( i = w->height - 1; i >= 0; i-- ) + { + if( !LineIsTransparent( w, &alpha[i*w->width] ) ) + { + crop[1] = i; + break; + } + } + + /* Left */ + for( i = 0; i < w->width; i++ ) + { + if( !ColumnIsTransparent( w, &alpha[i] ) ) + { + crop[2] = i; + break; + } + } + + /* Right */ + for( i = w->width - 1; i >= 0; i-- ) + { + if( !ColumnIsTransparent( w, &alpha[i] ) ) + { + crop[3] = i; + break; + } + } + + realwidth = crop[3] - crop[2] + 1; + realheight = crop[1] - crop[0] + 1; + + buf = hb_buffer_init( realwidth * realheight * 2 ); + buf->start = w->pts_start; + buf->stop = w->pts_stop; + buf->x = w->x + crop[2]; + buf->y = w->y + crop[0]; + buf->width = realwidth; + buf->height = realheight; + + lum_in = raw + crop[0] * w->width + crop[2]; + alpha_in = lum_in + w->width * w->height; + lum_out = buf->data; + alpha_out = lum_out + realwidth * realheight; + + for( i = 0; i < realheight; i++ ) + { + memcpy( lum_out, lum_in, realwidth ); + memcpy( alpha_out, alpha_in, realwidth ); + lum_in += w->width; + alpha_in += w->width; + lum_out += realwidth; + alpha_out += realwidth; + } + + return buf; +} diff --git a/libhb/demuxmpeg.c b/libhb/demuxmpeg.c new file mode 100644 index 000000000..721478e80 --- /dev/null +++ b/libhb/demuxmpeg.c @@ -0,0 +1,125 @@ +/* $Id: demuxmpeg.c,v 1.4 2004/10/19 23:11:36 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +/* Basic MPEG demuxer, only works with DVDs (2048 bytes packets) */ + +int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es ) +{ + hb_buffer_t * buf_es; + int pos; + + pos = 0; + +#define d (buf_ps->data) + + /* pack_header */ + if( d[pos] != 0 || d[pos+1] != 0 || + d[pos+2] != 0x1 || d[pos+3] != 0xBA ) + { + hb_log( "hb_demux_ps: not a PS packet (%02x%02x%02x%02x)", + d[pos], d[pos+1], d[pos+2], d[pos+3] ); + return 0; + } + pos += 4; /* pack_start_code */ + pos += 9; /* pack_header */ + pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */ + + /* system_header */ + if( d[pos] == 0 && d[pos+1] == 0 && + d[pos+2] == 0x1 && d[pos+3] == 0xBB ) + { + int header_length; + + pos += 4; /* system_header_start_code */ + header_length = ( d[pos] << 8 ) + d[pos+1]; + pos += 2 + header_length; + } + + /* pes */ + while( pos + 6 < buf_ps->size && + d[pos] == 0 && d[pos+1] == 0 && d[pos+2] == 0x1 ) + { + int id; + int pes_packet_length; + int pes_packet_end; + int pes_header_d_length; + int pes_header_end; + int has_pts; + int64_t pts = -1; + + pos += 3; /* packet_start_code_prefix */ + id = d[pos]; + pos += 1; + + pes_packet_length = ( d[pos] << 8 ) + d[pos+1]; + pos += 2; /* pes_packet_length */ + pes_packet_end = pos + pes_packet_length; + + if( id != 0xE0 && id != 0xBD && + ( id & 0xC0 ) != 0xC0 ) + { + /* Not interesting */ + pos = pes_packet_end; + continue; + } + + has_pts = ( ( d[pos+1] >> 6 ) & 0x2 ) ? 1 : 0; + pos += 2; /* Required headers */ + + pes_header_d_length = d[pos]; + pos += 1; + pes_header_end = pos + pes_header_d_length; + + if( has_pts ) + { + pts = ( ( ( (uint64_t) d[pos] >> 1 ) & 0x7 ) << 30 ) + + ( d[pos+1] << 22 ) + + ( ( d[pos+2] >> 1 ) << 15 ) + + ( d[pos+3] << 7 ) + + ( d[pos+4] >> 1 ); + } + + pos = pes_header_end; + + if( id == 0xBD ) + { + id |= ( d[pos] << 8 ); + if( ( id & 0xF0FF ) == 0x80BD ) /* A52 */ + { + pos += 4; + } + else if( ( id & 0xE0FF ) == 0x20BD || /* SPU */ + ( id & 0xF0FF ) == 0xA0BD ) /* LPCM */ + { + pos += 1; + } + } + + /* Sanity check */ + if( pos >= pes_packet_end ) + { + pos = pes_packet_end; + continue; + } + + /* Here we hit we ES payload */ + buf_es = hb_buffer_init( pes_packet_end - pos ); + + buf_es->id = id; + buf_es->start = pts; + memcpy( buf_es->data, d + pos, pes_packet_end - pos ); + + hb_list_add( list_es, buf_es ); + + pos = pes_packet_end; + } + +#undef d + + return 1; +} diff --git a/libhb/dvd.c b/libhb/dvd.c new file mode 100644 index 000000000..9b2aef13b --- /dev/null +++ b/libhb/dvd.c @@ -0,0 +1,735 @@ +/* $Id: dvd.c,v 1.11 2005/11/04 15:30:47 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" +#include "lang.h" + +#include "dvdread/ifo_read.h" +#include "dvdread/nav_read.h" + +struct hb_dvd_s +{ + char * path; + + dvd_reader_t * reader; + ifo_handle_t * vmg; + + int vts; + int ttn; + ifo_handle_t * ifo; + dvd_file_t * file; + + pgc_t * pgc; + int cell_start; + int cell_end; + int title_start; + int title_end; + int title_block_count; + int cell_cur; + int cell_next; + int block; + int pack_len; + int next_vobu; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void FindNextCell( hb_dvd_t * ); +static int dvdtime2msec( dvd_time_t * ); + +/*********************************************************************** + * hb_dvd_init + *********************************************************************** + * + **********************************************************************/ +hb_dvd_t * hb_dvd_init( char * path ) +{ + hb_dvd_t * d; + + d = calloc( sizeof( hb_dvd_t ), 1 ); + + /* Open device */ + if( !( d->reader = DVDOpen( path ) ) ) + { + hb_log( "dvd: DVDOpen failed (%s)", path ); + goto fail; + } + + /* Open main IFO */ + if( !( d->vmg = ifoOpen( d->reader, 0 ) ) ) + { + hb_log( "dvd: ifoOpen failed" ); + goto fail; + } + + d->path = strdup( path ); + + return d; + +fail: + if( d->vmg ) ifoClose( d->vmg ); + if( d->reader ) DVDClose( d->reader ); + free( d ); + return NULL; +} + +/*********************************************************************** + * hb_dvd_title_count + **********************************************************************/ +int hb_dvd_title_count( hb_dvd_t * d ) +{ + return d->vmg->tt_srpt->nr_of_srpts; +} + +/*********************************************************************** + * hb_dvd_title_scan + **********************************************************************/ +hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t ) +{ + + hb_title_t * title; + ifo_handle_t * vts = NULL; + int pgc_id, pgn, i; + hb_chapter_t * chapter, * chapter_old; + int c; + uint64_t duration; + float duration_correction; + + title = hb_title_init( d->path, t ); + + hb_log( "scan: scanning title %d", t ); + + /* VTS which our title is in */ + title->vts = d->vmg->tt_srpt->title[t-1].title_set_nr; + + hb_log( "scan: opening IFO for VTS %d", title->vts ); + if( !( vts = ifoOpen( d->reader, title->vts ) ) ) + { + hb_log( "scan: ifoOpen failed" ); + goto fail; + } + + /* Position of the title in the VTS */ + title->ttn = d->vmg->tt_srpt->title[t-1].vts_ttn; + + /* Get pgc */ + pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgcn; + pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgn; + d->pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc; + + /* Start cell */ + title->cell_start = d->pgc->program_map[pgn-1] - 1; + title->block_start = d->pgc->cell_playback[title->cell_start].first_sector; + + /* End cell */ + title->cell_end = d->pgc->nr_of_cells - 1; + title->block_end = d->pgc->cell_playback[title->cell_end].last_sector; + + /* Block count */ + title->block_count = 0; + d->cell_cur = title->cell_start; + while( d->cell_cur <= title->cell_end ) + { +#define cp d->pgc->cell_playback[d->cell_cur] + title->block_count += cp.last_sector + 1 - cp.first_sector; +#undef cp + FindNextCell( d ); + d->cell_cur = d->cell_next; + } + + hb_log( "scan: vts=%d, ttn=%d, cells=%d->%d, blocks=%d->%d, " + "%d blocks", title->vts, title->ttn, title->cell_start, + title->cell_end, title->block_start, title->block_end, + title->block_count ); + + if( title->block_count < 2048 ) + { + hb_log( "scan: title too short (%d blocks), ignoring", + title->block_count ); + goto fail; + } + + + /* Get duration */ + title->duration = 90LL * dvdtime2msec( &d->pgc->playback_time ); + title->hours = title->duration / 90000 / 3600; + title->minutes = ( ( title->duration / 90000 ) % 3600 ) / 60; + title->seconds = ( title->duration / 90000 ) % 60; + hb_log( "scan: duration is %02d:%02d:%02d (%lld ms)", + title->hours, title->minutes, title->seconds, + title->duration / 90 ); + + /* Discard titles under 10 seconds */ + if( !( title->hours | title->minutes ) && title->seconds < 10 ) + { + hb_log( "scan: ignoring title (too short)" ); + goto fail; + } + + /* Detect languages */ + for( i = 0; i < vts->vtsi_mat->nr_of_vts_audio_streams; i++ ) + { + hb_audio_t * audio, * audio_tmp; + int audio_format, lang_code, audio_control, + position, j; + + hb_log( "scan: checking audio %d", i + 1 ); + + audio = calloc( sizeof( hb_audio_t ), 1 ); + + audio_format = vts->vtsi_mat->vts_audio_attr[i].audio_format; + lang_code = vts->vtsi_mat->vts_audio_attr[i].lang_code; + audio_control = + vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i]; + + if( !( audio_control & 0x8000 ) ) + { + hb_log( "scan: audio channel is not active" ); + free( audio ); + continue; + } + + position = ( audio_control & 0x7F00 ) >> 8; + + switch( audio_format ) + { + case 0x00: + audio->id = ( ( 0x80 + position ) << 8 ) | 0xbd; + audio->codec = HB_ACODEC_AC3; + break; + + case 0x02: + case 0x03: + audio->id = 0xc0 + position; + audio->codec = HB_ACODEC_MPGA; + break; + + case 0x04: + audio->id = ( ( 0xa0 + position ) << 8 ) | 0xbd; + audio->codec = HB_ACODEC_LPCM; + break; + + default: + audio->id = 0; + audio->codec = 0; + hb_log( "scan: unknown audio codec (%x)", + audio_format ); + break; + } + if( !audio->id ) + { + continue; + } + + /* Check for duplicate tracks */ + audio_tmp = NULL; + for( j = 0; j < hb_list_count( title->list_audio ); j++ ) + { + audio_tmp = hb_list_item( title->list_audio, j ); + if( audio->id == audio_tmp->id ) + { + break; + } + audio_tmp = NULL; + } + if( audio_tmp ) + { + hb_log( "scan: duplicate audio track" ); + free( audio ); + continue; + } + + snprintf( audio->lang, sizeof( audio->lang ), "%s (%s)", + lang_for_code( vts->vtsi_mat->vts_audio_attr[i].lang_code ), + audio->codec == HB_ACODEC_AC3 ? "AC3" : ( audio->codec == + HB_ACODEC_MPGA ? "MPEG" : "LPCM" ) ); + + hb_log( "scan: id=%x, lang=%s", audio->id, + audio->lang ); + + hb_list_add( title->list_audio, audio ); + } + + if( !hb_list_count( title->list_audio ) ) + { + hb_log( "scan: ignoring title (no audio track)" ); + goto fail; + } + + memcpy( title->palette, + vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->palette, + 16 * sizeof( uint32_t ) ); + + /* Check for subtitles */ + for( i = 0; i < vts->vtsi_mat->nr_of_vts_subp_streams; i++ ) + { + hb_subtitle_t * subtitle; + int spu_control; + int position; + + hb_log( "scan: checking subtitle %d", i + 1 ); + + spu_control = + vts->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i]; + + if( !( spu_control & 0x80000000 ) ) + { + hb_log( "scan: subtitle channel is not active" ); + continue; + } + + if( vts->vtsi_mat->vts_video_attr.display_aspect_ratio ) + { + switch( vts->vtsi_mat->vts_video_attr.permitted_df ) + { + case 1: + position = spu_control & 0xFF; + break; + case 2: + position = ( spu_control >> 8 ) & 0xFF; + break; + default: + position = ( spu_control >> 16 ) & 0xFF; + } + } + else + { + position = ( spu_control >> 24 ) & 0x7F; + } + + subtitle = calloc( sizeof( hb_subtitle_t ), 1 ); + subtitle->id = ( ( 0x20 + position ) << 8 ) | 0xbd; + snprintf( subtitle->lang, sizeof( subtitle->lang ), "%s", + lang_for_code( vts->vtsi_mat->vts_subp_attr[i].lang_code ) ); + + hb_log( "scan: id=%x, lang=%s", subtitle->id, + subtitle->lang ); + + hb_list_add( title->list_subtitle, subtitle ); + } + + /* Chapters */ + hb_log( "scan: title %d has %d chapters", t, + vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts ); + for( i = 0, c = 1; + i < vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts; i++ ) + { + int pgc_id_next, pgn_next; + pgc_t * pgc_next; + + chapter = calloc( sizeof( hb_chapter_t ), 1 ); + chapter->index = c; + + pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgcn; + pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgn; + d->pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc; + + /* Start cell */ + chapter->cell_start = d->pgc->program_map[pgn-1] - 1; + chapter->block_start = + d->pgc->cell_playback[chapter->cell_start].first_sector; + + /* End cell */ + if( i != vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts - 1 ) + { + /* The cell before the starting cell of the next chapter, + or... */ + pgc_id_next = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i+1].pgcn; + pgn_next = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i+1].pgn; + pgc_next = vts->vts_pgcit->pgci_srp[pgc_id_next-1].pgc; + chapter->cell_end = pgc_next->program_map[pgn_next-1] - 2; + if( chapter->cell_end < 0 ) + { + /* Huh? */ + free( chapter ); + continue; + } + } + else + { + /* ... the last cell of the title */ + chapter->cell_end = title->cell_end; + } + chapter->block_end = + d->pgc->cell_playback[chapter->cell_end].last_sector; + + /* Block count, duration */ + pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgcn; + pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[0].pgn; + d->pgc = vts->vts_pgcit->pgci_srp[pgc_id-1].pgc; + chapter->block_count = 0; + chapter->duration = 0; + + d->cell_cur = chapter->cell_start; + while( d->cell_cur <= chapter->cell_end ) + { +#define cp d->pgc->cell_playback[d->cell_cur] + chapter->block_count += cp.last_sector + 1 - cp.first_sector; + chapter->duration += 90LL * dvdtime2msec( &cp.playback_time ); +#undef cp + FindNextCell( d ); + d->cell_cur = d->cell_next; + } + + if( chapter->block_count < 2048 && chapter->index > 1 ) + { + hb_log( "scan: chapter %d too short (%d blocks, " + "cells=%d->%d), merging", chapter->index, + chapter->block_count, chapter->cell_start, + chapter->cell_end ); + chapter_old = hb_list_item( title->list_chapter, + chapter->index - 2 ); + chapter_old->cell_end = chapter->cell_end; + chapter_old->block_end = chapter->block_end; + chapter_old->block_count += chapter->block_count; + free( chapter ); + chapter = chapter_old; + } + else + { + hb_list_add( title->list_chapter, chapter ); + c++; + } + } + + /* The durations we get for chapters aren't precise. Scale them so + the total matches the title duration */ + duration = 0; + for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) + { + chapter = hb_list_item( title->list_chapter, i ); + duration += chapter->duration; + } + duration_correction = (float) title->duration / (float) duration; + for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) + { + int seconds; + chapter = hb_list_item( title->list_chapter, i ); + chapter->duration = duration_correction * chapter->duration; + seconds = ( chapter->duration + 45000 ) / 90000; + chapter->hours = seconds / 3600; + chapter->minutes = ( seconds % 3600 ) / 60; + chapter->seconds = seconds % 60; + + hb_log( "scan: chap %d c=%d->%d, b=%d->%d (%d), %lld ms", + chapter->index, chapter->cell_start, chapter->cell_end, + chapter->block_start, chapter->block_end, + chapter->block_count, chapter->duration / 90 ); + } + + /* Get aspect. We don't get width/height/rate infos here as + they tend to be wrong */ + switch( vts->vtsi_mat->vts_video_attr.display_aspect_ratio ) + { + case 0: + title->aspect = HB_ASPECT_BASE * 4 / 3; + break; + case 3: + title->aspect = HB_ASPECT_BASE * 16 / 9; + break; + default: + hb_log( "scan: unknown aspect" ); + goto fail; + } + + hb_log( "scan: aspect = %d", title->aspect ); + + /* This title is ok so far */ + goto cleanup; + +fail: + hb_list_close( &title->list_audio ); + free( title ); + title = NULL; + +cleanup: + if( vts ) ifoClose( vts ); + + return title; +} + +/*********************************************************************** + * hb_dvd_start + *********************************************************************** + * Title and chapter start at 1 + **********************************************************************/ +int hb_dvd_start( hb_dvd_t * d, int title, int chapter ) +{ + int pgc_id, pgn; + int i; + + /* Open the IFO and the VOBs for this title */ + d->vts = d->vmg->tt_srpt->title[title-1].title_set_nr; + d->ttn = d->vmg->tt_srpt->title[title-1].vts_ttn; + if( !( d->ifo = ifoOpen( d->reader, d->vts ) ) ) + { + hb_log( "dvd: ifoOpen failed for VTS %d", d->vts ); + return 0; + } + if( !( d->file = DVDOpenFile( d->reader, d->vts, + DVD_READ_TITLE_VOBS ) ) ) + { + hb_log( "dvd: DVDOpenFile failed for VTS %d", d->vts ); + return 0; + } + + /* Get title first and last blocks */ + pgc_id = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[0].pgcn; + pgn = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[0].pgn; + d->pgc = d->ifo->vts_pgcit->pgci_srp[pgc_id-1].pgc; + d->cell_start = d->pgc->program_map[pgn - 1] - 1; + d->cell_end = d->pgc->nr_of_cells - 1; + d->title_start = d->pgc->cell_playback[d->cell_start].first_sector; + d->title_end = d->pgc->cell_playback[d->cell_end].last_sector; + + /* Block count */ + d->title_block_count = 0; + for( i = d->cell_start; i <= d->cell_end; i++ ) + { + d->title_block_count += d->pgc->cell_playback[i].last_sector + 1 - + d->pgc->cell_playback[i].first_sector; + } + + /* Get pgc for the current chapter */ + pgc_id = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[chapter-1].pgcn; + pgn = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[chapter-1].pgn; + d->pgc = d->ifo->vts_pgcit->pgci_srp[pgc_id-1].pgc; + + /* Get the two first cells */ + d->cell_cur = d->pgc->program_map[pgn-1] - 1; + FindNextCell( d ); + + d->block = d->pgc->cell_playback[d->cell_cur].first_sector; + d->next_vobu = d->block; + d->pack_len = 0; + + return 1; +} + +/*********************************************************************** + * hb_dvd_seek + *********************************************************************** + * + **********************************************************************/ +int hb_dvd_seek( hb_dvd_t * d, float f ) +{ + int target; + + target = d->title_start + (int) ( f * d->title_block_count ); + + /* Find the cell we shall start in */ + d->cell_cur = d->cell_start; + FindNextCell( d ); + for( ;; ) + { + if( target < d->pgc->cell_playback[d->cell_cur].last_sector ) + { + break; + } + d->cell_cur = d->cell_next; + FindNextCell( d ); + } + + /* Now let hb_dvd_read find the next VOBU */ + d->next_vobu = target; + d->pack_len = 0; + + return 1; +} + +/*********************************************************************** + * hb_dvd_read + *********************************************************************** + * + **********************************************************************/ +int hb_dvd_read( hb_dvd_t * d, hb_buffer_t * b ) +{ + if( !d->pack_len ) + { + /* New pack */ + dsi_t dsi_pack; + int error; + + error = 0; + + for( ;; ) + { + int block, pack_len, next_vobu; + + if( DVDReadBlocks( d->file, d->next_vobu, 1, b->data ) != 1 ) + { + hb_log( "dvd: DVDReadBlocks failed (%d)", d->next_vobu ); + return 0; + } + + navRead_DSI( &dsi_pack, &b->data[DSI_START_BYTE] ); + + block = dsi_pack.dsi_gi.nv_pck_lbn; + pack_len = dsi_pack.dsi_gi.vobu_ea; + next_vobu = block + ( dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); + + if( pack_len > 0 && + pack_len < 1024 && + block >= d->next_vobu && + ( block <= d->title_start + d->title_block_count || + block <= d->title_end ) ) + { + /* XXX + This looks like a valid VOBU, but actually we are + just hoping */ + if( error ) + { +#if 0 + hb_log( "dvd: found VOBU at %d (b %d, l %d, n %d)", + d->next_vobu, block, pack_len, next_vobu ); +#endif + } + d->block = block; + d->pack_len = pack_len; + d->next_vobu = next_vobu; + break; + } + + /* Wasn't a valid VOBU, try next block */ + if( !error ) + { +#if 0 + hb_log( "dvd: looking for a VOBU (%d)", d->next_vobu ); +#endif + } + + if( ++error > 1024 ) + { + hb_log( "dvd: couldn't find a VOBU after 1024 blocks" ); + return 0; + } + + (d->next_vobu)++; + } + + if( dsi_pack.vobu_sri.next_vobu == SRI_END_OF_CELL ) + { + d->cell_cur = d->cell_next; + d->next_vobu = d->pgc->cell_playback[d->cell_cur].first_sector; + FindNextCell( d ); + } + } + else + { + if( DVDReadBlocks( d->file, d->block, 1, b->data ) != 1 ) + { + hb_log( "reader: DVDReadBlocks failed (%d)", d->block ); + return 0; + } + d->pack_len--; + } + + d->block++; + + return 1; +} + +/*********************************************************************** + * hb_dvd_chapter + *********************************************************************** + * Returns in which chapter the next block to be read is. + * Chapter numbers start at 1. + **********************************************************************/ +int hb_dvd_chapter( hb_dvd_t * d ) +{ + int i; + int pgc_id, pgn; + pgc_t * pgc; + + for( i = 0; + i < d->ifo->vts_ptt_srpt->title[d->ttn-1].nr_of_ptts; + i++ ) + { + /* Get pgc for chapter (i+1) */ + pgc_id = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[i].pgcn; + pgn = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[i].pgn; + pgc = d->ifo->vts_pgcit->pgci_srp[pgc_id-1].pgc; + + if( d->cell_cur >= pgc->program_map[pgn-1] - 1 && + d->cell_cur <= pgc->nr_of_cells - 1 ) + { + /* We are in this chapter */ + return i + 1; + } + } + + /* End of title */ + return -1; +} + +/*********************************************************************** + * hb_dvd_close + *********************************************************************** + * Closes and frees everything + **********************************************************************/ +void hb_dvd_close( hb_dvd_t ** _d ) +{ + hb_dvd_t * d = *_d; + + if( d->ifo ) ifoClose( d->ifo ); + if( d->vmg ) ifoClose( d->vmg ); + if( d->file ) DVDCloseFile( d->file ); + if( d->reader ) DVDClose( d->reader ); + + free( d ); + *_d = NULL; +} + +/*********************************************************************** + * FindNextCell + *********************************************************************** + * Assumes pgc and cell_cur are correctly set, and sets cell_next to the + * cell to be read when we will be done with cell_cur. + **********************************************************************/ +static void FindNextCell( hb_dvd_t * d ) +{ + int i = 0; + + if( d->pgc->cell_playback[d->cell_cur].block_type == + BLOCK_TYPE_ANGLE_BLOCK ) + { + + while( d->pgc->cell_playback[d->cell_cur+i].block_mode != + BLOCK_MODE_LAST_CELL ) + { + i++; + } + d->cell_next = d->cell_cur + i + 1; + } + else + { + d->cell_next = d->cell_cur + 1; + } +} + +/*********************************************************************** + * dvdtime2msec + *********************************************************************** + * From lsdvd + **********************************************************************/ +static int dvdtime2msec(dvd_time_t * dt) +{ + double frames_per_s[4] = {-1.0, 25.00, -1.0, 29.97}; + double fps = frames_per_s[(dt->frame_u & 0xc0) >> 6]; + long ms; + ms = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000; + ms += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000; + ms += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000; + + if( fps > 0 ) + { + ms += ((dt->frame_u & 0x30) >> 3) * 5 + + (dt->frame_u & 0x0f) * 1000.0 / fps; + } + + return ms; +} diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c new file mode 100644 index 000000000..deff7c527 --- /dev/null +++ b/libhb/encavcodec.c @@ -0,0 +1,201 @@ +/* $Id: encavcodec.c,v 1.23 2005/10/13 23:47:06 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "ffmpeg/avcodec.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + AVCodecContext * context; + FILE * file; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +/*********************************************************************** + * hb_work_encavcodec_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_encavcodec_init( hb_job_t * job ) +{ + AVCodec * codec; + AVCodecContext * context; + + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "MPEG-4 encoder (libavcodec)" ); + w->work = Work; + w->close = Close; + + w->job = job; + + codec = avcodec_find_encoder( CODEC_ID_MPEG4 ); + if( !codec ) + { + hb_log( "hb_work_encavcodec_init: avcodec_find_encoder " + "failed" ); + } + context = avcodec_alloc_context(); + if( job->vquality < 0.0 || job->vquality > 1.0 ) + { + /* Rate control */ + context->bit_rate = 1000 * job->vbitrate; + context->bit_rate_tolerance = 10 * context->bit_rate; + } + else + { + /* Constant quantizer */ + context->qmin = 31 - job->vquality * 30; + context->qmax = context->qmin; + hb_log( "encavcodec: encoding at constant quantizer %d", + context->qmin ); + } + context->width = job->width; + context->height = job->height; + context->time_base = (AVRational) { job->vrate_base, job->vrate }; + context->gop_size = 10 * job->vrate / job->vrate_base; + context->pix_fmt = PIX_FMT_YUV420P; + + if( job->mux & HB_MUX_MP4 ) + { + context->flags |= CODEC_FLAG_GLOBAL_HEADER; + } + if( job->grayscale ) + { + context->flags |= CODEC_FLAG_GRAY; + } + + if( job->pass ) + { + char filename[1024]; memset( filename, 0, 1024 ); + hb_get_tempory_filename( job->h, filename, "ffmpeg.log" ); + + if( job->pass == 1 ) + { + w->file = fopen( filename, "wb" ); + context->flags |= CODEC_FLAG_PASS1; + } + else + { + int size; + char * log; + + w->file = fopen( filename, "rb" ); + fseek( w->file, 0, SEEK_END ); + size = ftell( w->file ); + fseek( w->file, 0, SEEK_SET ); + log = malloc( size + 1 ); + log[size] = '\0'; + fread( log, size, 1, w->file ); + fclose( w->file ); + w->file = NULL; + + context->flags |= CODEC_FLAG_PASS2; + context->stats_in = log; + } + } + + if( avcodec_open( context, codec ) ) + { + hb_log( "hb_work_encavcodec_init: avcodec_open failed" ); + } + w->context = context; + + if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 ) + { +#define c job->config.mpeg4 + /* Hem hem */ + c.config = malloc( 15 ); + c.config_length = 15; + memcpy( c.config, context->extradata + 15, 15 ); +#undef c + } + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + hb_job_t * job = w->job; + + if( w->context ) + { + hb_log( "encavcodec: closing libavcodec" ); + avcodec_close( w->context ); + } + if( w->file ) + { + fclose( w->file ); + } + if( job->es_config ) + { + free( job->es_config ); + job->es_config = NULL; + job->es_config_length = 0; + } + + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_job_t * job = w->job; + AVFrame * frame; + hb_buffer_t * in = *buf_in, * buf; + + frame = avcodec_alloc_frame(); + frame->data[0] = in->data; + frame->data[1] = frame->data[0] + job->width * job->height; + frame->data[2] = frame->data[1] + job->width * job->height / 4; + frame->linesize[0] = job->width; + frame->linesize[1] = job->width / 2; + frame->linesize[2] = job->width / 2; + + /* Should be way too large */ + buf = hb_buffer_init( 3 * job->width * job->height / 2 ); + buf->size = avcodec_encode_video( w->context, buf->data, buf->alloc, + frame ); + buf->start = in->start; + buf->stop = in->stop; + buf->key = w->context->coded_frame->key_frame; + + av_free( frame ); + + if( job->pass == 1 ) + { + /* Write stats */ + fprintf( w->file, "%s", w->context->stats_out ); + } + + *buf_out = buf; + + return HB_WORK_OK; +} + + diff --git a/libhb/encfaac.c b/libhb/encfaac.c new file mode 100644 index 000000000..a5b704f4c --- /dev/null +++ b/libhb/encfaac.c @@ -0,0 +1,166 @@ +/* $Id: encfaac.c,v 1.13 2005/03/03 17:21:57 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "faac.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + hb_audio_t * audio; + + faacEncHandle * faac; + unsigned long input_samples; + unsigned long output_bytes; + uint8_t * buf; + + hb_list_t * list; + int64_t pts; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +/*********************************************************************** + * hb_work_encfaac_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_encfaac_init( hb_job_t * job, hb_audio_t * audio ) +{ + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + faacEncConfigurationPtr cfg; + w->name = strdup( "AAC encoder (libfaac)" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->audio = audio; + + w->faac = faacEncOpen( job->arate, 2, &w->input_samples, + &w->output_bytes ); + w->buf = malloc( w->input_samples * sizeof( float ) ); + + cfg = faacEncGetCurrentConfiguration( w->faac ); + cfg->mpegVersion = MPEG4; + cfg->aacObjectType = LOW; + cfg->allowMidside = 1; + cfg->useLfe = 0; + cfg->useTns = 0; + cfg->bitRate = job->abitrate * 500; /* Per channel */ + cfg->bandWidth = 0; + cfg->outputFormat = 0; + cfg->inputFormat = FAAC_INPUT_FLOAT; + if( !faacEncSetConfiguration( w->faac, cfg ) ) + { + hb_log( "faacEncSetConfiguration failed" ); + } + if( faacEncGetDecoderSpecificInfo( w->faac, &audio->config.faac.decinfo, + &audio->config.faac.size ) < 0 ) + { + hb_log( "faacEncGetDecoderSpecificInfo failed" ); + } + + w->list = hb_list_init(); + w->pts = -1; + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + + faacEncClose( w->faac ); + free( w->buf ); + hb_list_empty( &w->list ); + free( w->audio->config.faac.decinfo ); + + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Encode + *********************************************************************** + * + **********************************************************************/ +static hb_buffer_t * Encode( hb_work_object_t * w ) +{ + hb_buffer_t * buf; + uint64_t pts; + int pos; + + if( hb_list_bytes( w->list ) < w->input_samples * sizeof( float ) ) + { + /* Need more data */ + return NULL; + } + + hb_list_getbytes( w->list, w->buf, w->input_samples * sizeof( float ), + &pts, &pos ); + + buf = hb_buffer_init( w->output_bytes ); + buf->start = pts + 90000 * pos / 2 / sizeof( float ) / w->job->arate; + buf->stop = buf->start + 90000 * w->input_samples / w->job->arate / 2; + buf->size = faacEncEncode( w->faac, (int32_t *) w->buf, + w->input_samples, buf->data, w->output_bytes ); + buf->key = 1; + + if( !buf->size ) + { + /* Encoding was successful but we got no data. Try to encode + more */ + hb_buffer_close( &buf ); + return Encode( w ); + } + else if( buf->size < 0 ) + { + hb_log( "faacEncEncode failed" ); + hb_buffer_close( &buf ); + return NULL; + } + + return buf; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * buf; + + hb_list_add( w->list, *buf_in ); + *buf_in = NULL; + + *buf_out = buf = Encode( w ); + + while( buf ) + { + buf->next = Encode( w ); + buf = buf->next; + } + + return HB_WORK_OK; +} + diff --git a/libhb/enclame.c b/libhb/enclame.c new file mode 100644 index 000000000..19014ac26 --- /dev/null +++ b/libhb/enclame.c @@ -0,0 +1,154 @@ +/* $Id: enclame.c,v 1.9 2005/03/05 14:27:05 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "lame/lame.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + hb_audio_t * audio; + + /* LAME handle */ + lame_global_flags * lame; + + unsigned long input_samples; + unsigned long output_bytes; + uint8_t * buf; + + hb_list_t * list; + int64_t pts; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +/*********************************************************************** + * hb_work_enclame_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_enclame_init( hb_job_t * job, hb_audio_t * audio ) +{ + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "MP3 encoder (libmp3lame)" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->audio = audio; + + hb_log( "enclame: opening libmp3lame" ); + + w->lame = lame_init(); + lame_set_brate( w->lame, job->abitrate ); + lame_set_in_samplerate( w->lame, job->arate ); + lame_set_out_samplerate( w->lame, job->arate ); + lame_init_params( w->lame ); + + w->input_samples = 1152 * 2; + w->output_bytes = LAME_MAXMP3BUFFER; + w->buf = malloc( w->input_samples * sizeof( float ) ); + + w->list = hb_list_init(); + w->pts = -1; + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Encode + *********************************************************************** + * + **********************************************************************/ +static hb_buffer_t * Encode( hb_work_object_t * w ) +{ + hb_buffer_t * buf; + int16_t samples_s16[1152 * 2]; + uint64_t pts; + int pos, i; + + if( hb_list_bytes( w->list ) < w->input_samples * sizeof( float ) ) + { + return NULL; + } + + hb_list_getbytes( w->list, w->buf, w->input_samples * sizeof( float ), + &pts, &pos); + + for( i = 0; i < 1152 * 2; i++ ) + { + samples_s16[i] = ((float*) w->buf)[i]; + } + + buf = hb_buffer_init( w->output_bytes ); + buf->start = pts + 90000 * pos / 2 / sizeof( float ) / w->job->arate; + buf->stop = buf->start + 90000 * 1152 / w->job->arate; + buf->size = lame_encode_buffer_interleaved( w->lame, samples_s16, + 1152, buf->data, LAME_MAXMP3BUFFER ); + buf->key = 1; + + if( !buf->size ) + { + /* Encoding was successful but we got no data. Try to encode + more */ + hb_buffer_close( &buf ); + return Encode( w ); + } + else if( buf->size < 0 ) + { + hb_log( "enclame: lame_encode_buffer failed" ); + hb_buffer_close( &buf ); + return NULL; + } + + return buf; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * buf; + + hb_list_add( w->list, *buf_in ); + *buf_in = NULL; + + *buf_out = buf = Encode( w ); + + while( buf ) + { + buf->next = Encode( w ); + buf = buf->next; + } + + return HB_WORK_OK; +} + diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c new file mode 100644 index 000000000..86b824372 --- /dev/null +++ b/libhb/encvorbis.c @@ -0,0 +1,205 @@ +/* $Id: encvorbis.c,v 1.6 2005/03/05 15:08:32 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "vorbis/vorbisenc.h" + +#define OGGVORBIS_FRAME_SIZE 1024 + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + hb_audio_t * audio; + + vorbis_info vi; + vorbis_comment vc; + vorbis_dsp_state vd; + vorbis_block vb; + + unsigned long input_samples; + uint8_t * buf; + uint64_t pts; + + hb_list_t * list; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +/*********************************************************************** + * hb_work_encvorbis_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_encvorbis_init( hb_job_t * job, hb_audio_t * audio ) +{ + int i; + ogg_packet header[3]; + + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "Vorbis encoder (libvorbis)" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->audio = audio; + + hb_log( "encvorbis: opening libvorbis" ); + + /* init */ + vorbis_info_init( &w->vi ); + if( vorbis_encode_setup_managed( &w->vi, 2, + job->arate, -1, 1000 * job->abitrate, -1 ) || + vorbis_encode_ctl( &w->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) || + vorbis_encode_setup_init( &w->vi ) ) + { + hb_log( "encvorbis: vorbis_encode_setup_managed failed" ); + } + + /* add a comment */ + vorbis_comment_init( &w->vc ); + vorbis_comment_add_tag( &w->vc, "Encoder", "HandBrake"); + + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init( &w->vd, &w->vi); + vorbis_block_init( &w->vd, &w->vb); + + /* get the 3 headers */ + vorbis_analysis_headerout( &w->vd, &w->vc, + &header[0], &header[1], &header[2] ); + for( i = 0; i < 3; i++ ) + { + audio->config.vorbis.headers[i] = + malloc( sizeof( ogg_packet ) + header[i].bytes ); + memcpy( audio->config.vorbis.headers[i], &header[i], + sizeof( ogg_packet ) ); + memcpy( audio->config.vorbis.headers[i] + sizeof( ogg_packet ), + header[i].packet, header[i].bytes ); + } + + w->input_samples = 2 * OGGVORBIS_FRAME_SIZE; + w->buf = malloc( w->input_samples * sizeof( float ) ); + + w->list = hb_list_init(); + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Flush + *********************************************************************** + * + **********************************************************************/ +static hb_buffer_t * Flush( hb_work_object_t * w ) +{ + hb_buffer_t * buf; + + if( vorbis_analysis_blockout( &w->vd, &w->vb ) == 1 ) + { + ogg_packet op; + + vorbis_analysis( &w->vb, NULL ); + vorbis_bitrate_addblock( &w->vb ); + + if( vorbis_bitrate_flushpacket( &w->vd, &op ) ) + { + buf = hb_buffer_init( sizeof( ogg_packet ) + op.bytes ); + memcpy( buf->data, &op, sizeof( ogg_packet ) ); + memcpy( buf->data + sizeof( ogg_packet ), op.packet, + op.bytes ); + buf->key = 1; + buf->start = w->pts; /* No exact, but who cares - the OGM + muxer doesn't use it */ + buf->stop = buf->start + + 90000 * OGGVORBIS_FRAME_SIZE + w->job->arate; + + return buf; + } + } + + return NULL; +} + +/*********************************************************************** + * Encode + *********************************************************************** + * + **********************************************************************/ +static hb_buffer_t * Encode( hb_work_object_t * w ) +{ + hb_buffer_t * buf; + float ** buffer; + int i; + + /* Try to extract more data */ + if( ( buf = Flush( w ) ) ) + { + return buf; + } + + if( hb_list_bytes( w->list ) < w->input_samples * sizeof( float ) ) + { + return NULL; + } + + /* Process more samples */ + hb_list_getbytes( w->list, w->buf, w->input_samples * sizeof( float ), + &w->pts, NULL ); + buffer = vorbis_analysis_buffer( &w->vd, OGGVORBIS_FRAME_SIZE ); + for( i = 0; i < OGGVORBIS_FRAME_SIZE; i++ ) + { + buffer[0][i] = ((float *) w->buf)[2*i] / 32768.f; + buffer[1][i] = ((float *) w->buf)[2*i+1] / 32768.f; + } + vorbis_analysis_wrote( &w->vd, OGGVORBIS_FRAME_SIZE ); + + /* Try to extract again */ + return Flush( w ); +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_buffer_t * buf; + + hb_list_add( w->list, *buf_in ); + *buf_in = NULL; + + *buf_out = buf = Encode( w ); + + while( buf ) + { + buf->next = Encode( w ); + buf = buf->next; + } + + return HB_WORK_OK; +} diff --git a/libhb/encx264.c b/libhb/encx264.c new file mode 100644 index 000000000..cf58452e7 --- /dev/null +++ b/libhb/encx264.c @@ -0,0 +1,221 @@ +/* $Id: encx264.c,v 1.21 2005/11/04 13:09:41 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include <stdarg.h> + +#include "hb.h" + +#include "x264.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + x264_t * x264; + x264_picture_t pic_in; + x264_picture_t pic_out; + + char filename[1024]; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); +static void Close( hb_work_object_t ** _w ); + +/*********************************************************************** + * hb_work_encx264_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_encx264_init( hb_job_t * job ) +{ + hb_work_object_t * w; + x264_param_t param; + x264_nal_t * nal; + int nal_count; + + w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "AVC encoder (libx264)" ); + w->work = Work; + w->close = Close; + + w->job = job; + + memset( w->filename, 0, 1024 ); + hb_get_tempory_filename( job->h, w->filename, "x264.log" ); + + x264_param_default( ¶m ); + + param.i_threads = hb_get_cpu_count(); + param.i_width = job->width; + param.i_height = job->height; + param.i_fps_num = job->vrate; + param.i_fps_den = job->vrate_base; + param.i_keyint_max = 20 * job->vrate / job->vrate_base; + param.i_log_level = X264_LOG_NONE; + if( job->h264_13 ) + { + param.b_cabac = 0; + param.i_level_idc = 13; + } + + /* Slightly faster with minimal quality lost */ + param.analyse.i_subpel_refine = 4; + + if( job->vquality >= 0.0 && job->vquality <= 1.0 ) + { + /* Constant QP */ + param.rc.i_qp_constant = 51 - job->vquality * 51; + hb_log( "encx264: encoding at constant QP %d", + param.rc.i_qp_constant ); + } + else + { + /* Rate control */ + param.rc.b_cbr = 1; + param.rc.i_bitrate = job->vbitrate; + switch( job->pass ) + { + case 1: + param.rc.b_stat_write = 1; + param.rc.psz_stat_out = w->filename; + break; + case 2: + param.rc.b_stat_read = 1; + param.rc.psz_stat_in = w->filename; + break; + } + } + + hb_log( "encx264: opening libx264 (pass %d)", job->pass ); + w->x264 = x264_encoder_open( ¶m ); + +#define c job->config.h264 + x264_encoder_headers( w->x264, &nal, &nal_count ); + + /* Sequence Parameter Set */ + c.sps_length = 1 + nal[1].i_payload; + c.sps = malloc( c.sps_length); + c.sps[0] = 0x67; + memcpy( &c.sps[1], nal[1].p_payload, nal[1].i_payload ); + + /* Picture Parameter Set */ + c.pps_length = 1 + nal[2].i_payload; + c.pps = malloc( c.pps_length ); + c.pps[0] = 0x68; + memcpy( &c.pps[1], nal[2].p_payload, nal[2].i_payload ); +#undef c + + x264_picture_alloc( &w->pic_in, X264_CSP_I420, + job->width, job->height ); + + return w; +} + +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + + x264_encoder_close( w->x264 ); + + /* TODO */ + + free( w->name ); + free( w ); + *_w = NULL; +} + +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_job_t * job = w->job; + hb_buffer_t * in = *buf_in, * buf; + int i_nal; + x264_nal_t * nal; + int i; + + /* XXX avoid this memcpy ? */ + memcpy( w->pic_in.img.plane[0], in->data, job->width * job->height ); + if( job->grayscale ) + { + /* XXX x264 has currently no option for grayscale encoding */ + memset( w->pic_in.img.plane[1], 0x80, job->width * job->height / 4 ); + memset( w->pic_in.img.plane[2], 0x80, job->width * job->height / 4 ); + } + else + { + memcpy( w->pic_in.img.plane[1], in->data + job->width * job->height, + job->width * job->height / 4 ); + memcpy( w->pic_in.img.plane[2], in->data + 5 * job->width * + job->height / 4, job->width * job->height / 4 ); + } + + w->pic_in.i_type = X264_TYPE_AUTO; + w->pic_in.i_qpplus1 = 0; + + x264_encoder_encode( w->x264, &nal, &i_nal, + &w->pic_in, &w->pic_out ); + + /* Should be way too large */ + buf = hb_buffer_init( 3 * job->width * job->height / 2 ); + buf->size = 0; + buf->start = in->start; + buf->stop = in->stop; + buf->key = 0; + + for( i = 0; i < i_nal; i++ ) + { + int size, data; + + data = buf->alloc - buf->size; + if( ( size = x264_nal_encode( buf->data + buf->size, &data, + 1, &nal[i] ) ) < 1 ) + { + continue; + } + + if( job->mux & HB_MUX_AVI ) + { + if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) + { + buf->key = 1; + } + buf->size += size; + continue; + } + + /* H.264 in .mp4 */ + switch( buf->data[buf->size+4] & 0x1f ) + { + case 0x7: + case 0x8: + /* SPS, PPS */ + break; + + default: + /* H.264 in mp4 (stolen from mp4creator) */ + buf->data[buf->size+0] = ( ( size - 4 ) >> 24 ) & 0xFF; + buf->data[buf->size+1] = ( ( size - 4 ) >> 16 ) & 0xFF; + buf->data[buf->size+2] = ( ( size - 4 ) >> 8 ) & 0xFF; + buf->data[buf->size+3] = ( ( size - 4 ) >> 0 ) & 0xFF; + if( nal[i].i_ref_idc == NAL_PRIORITY_HIGHEST ) + { + buf->key = 1; + } + buf->size += size; + } + } + + *buf_out = buf; + + return HB_WORK_OK; +} + + diff --git a/libhb/encxvid.c b/libhb/encxvid.c new file mode 100644 index 000000000..a874d9f00 --- /dev/null +++ b/libhb/encxvid.c @@ -0,0 +1,222 @@ +/* $Id: encxvid.c,v 1.10 2005/03/09 23:28:39 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "xvid.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + void * xvid; + char filename[1024]; + int quant; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +/*********************************************************************** + * hb_work_encxvid_init + *********************************************************************** + * + **********************************************************************/ +hb_work_object_t * hb_work_encxvid_init( hb_job_t * job ) +{ + xvid_gbl_init_t xvid_gbl_init; + xvid_enc_create_t create; + xvid_plugin_single_t single; + xvid_plugin_2pass1_t rc2pass1; + xvid_plugin_2pass2_t rc2pass2; + xvid_enc_plugin_t plugins[1]; + + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "MPEG-4 encoder (libxvidcore)" ); + w->work = Work; + w->close = Close; + + w->job = job; + + memset( w->filename, 0, 1024 ); + hb_get_tempory_filename( job->h, w->filename, "xvid.log" ); + + memset( &xvid_gbl_init, 0, sizeof( xvid_gbl_init ) ); + xvid_gbl_init.version = XVID_VERSION; + xvid_global( NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL ); + + memset( &create, 0, sizeof( create ) ); + create.version = XVID_VERSION; + create.width = job->width; + create.height = job->height; + create.zones = NULL; + create.num_zones = 0; + + switch( job->pass ) + { + case 0: + memset( &single, 0, sizeof( single ) ); + single.version = XVID_VERSION; + if( job->vquality < 0.0 || job->vquality > 1.0 ) + { + /* Rate control */ + single.bitrate = 1000 * job->vbitrate; + w->quant = 0; + } + else + { + /* Constant quantizer */ + w->quant = 31 - job->vquality * 30; + hb_log( "encxvid: encoding at constant quantizer %d", + w->quant ); + } + plugins[0].func = xvid_plugin_single; + plugins[0].param = &single; + break; + + case 1: + memset( &rc2pass1, 0, sizeof( rc2pass1 ) ); + rc2pass1.version = XVID_VERSION; + rc2pass1.filename = w->filename; + plugins[0].func = xvid_plugin_2pass1; + plugins[0].param = &rc2pass1; + break; + + case 2: + memset( &rc2pass2, 0, sizeof( rc2pass2 ) ); + rc2pass2.version = XVID_VERSION; + rc2pass2.filename = w->filename; + rc2pass2.bitrate = 1000 * job->vbitrate; + plugins[0].func = xvid_plugin_2pass2; + plugins[0].param = &rc2pass2; + break; + } + + create.plugins = plugins; + create.num_plugins = 1; + + create.num_threads = 0; + create.fincr = job->vrate_base; + create.fbase = job->vrate; + create.max_key_interval = 10 * job->vrate / job->vrate_base; + create.max_bframes = 0; + create.bquant_ratio = 150; + create.bquant_offset = 100; + create.frame_drop_ratio = 0; + create.global = 0; + + xvid_encore( NULL, XVID_ENC_CREATE, &create, NULL ); + w->xvid = create.handle; + + return w; +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + + if( w->xvid ) + { + hb_log( "encxvid: closing libxvidcore" ); + xvid_encore( w->xvid, XVID_ENC_DESTROY, NULL, NULL); + } + + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_job_t * job = w->job; + xvid_enc_frame_t frame; + hb_buffer_t * in = *buf_in, * buf; + + /* Should be way too large */ + buf = hb_buffer_init( 3 * job->width * job->height / 2 ); + buf->start = in->start; + buf->stop = in->stop; + + memset( &frame, 0, sizeof( frame ) ); + + frame.version = XVID_VERSION; + frame.bitstream = buf->data; + frame.length = -1; + frame.input.plane[0] = in->data; + frame.input.csp = XVID_CSP_I420; + frame.input.stride[0] = job->width; + frame.vol_flags = 0; + frame.vop_flags = XVID_VOP_HALFPEL | XVID_VOP_INTER4V | + XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED; + if( job->grayscale ) + { + frame.vop_flags |= XVID_VOP_GREYSCALE; + } + frame.type = XVID_TYPE_AUTO; + frame.quant = w->quant; + frame.motion = XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | + XVID_ME_EXTSEARCH16 | XVID_ME_ADVANCEDDIAMOND8 | + XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 | + XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP; + frame.quant_intra_matrix = NULL; + frame.quant_inter_matrix = NULL; + + buf->size = xvid_encore( w->xvid, XVID_ENC_ENCODE, &frame, NULL ); + buf->key = ( frame.out_flags & XVID_KEYFRAME ); + +#define c job->config.mpeg4 + if( !c.config ) + { + int vol_start, vop_start; + for( vol_start = 0; ; vol_start++ ) + { + if( buf->data[vol_start] == 0x0 && + buf->data[vol_start+1] == 0x0 && + buf->data[vol_start+2] == 0x1 && + buf->data[vol_start+3] == 0x20 ) + { + break; + } + } + for( vop_start = vol_start + 4; ; vop_start++ ) + { + if( buf->data[vop_start] == 0x0 && + buf->data[vop_start+1] == 0x0 && + buf->data[vop_start+2] == 0x1 && + buf->data[vop_start+3] == 0xB6 ) + { + break; + } + } + + hb_log( "encxvid: VOL size is %d bytes", vop_start - vol_start ); + c.config = malloc( vop_start - vol_start ); + c.config_length = vop_start - vol_start; + memcpy( c.config, &buf->data[vol_start], c.config_length ); + } +#undef c + + *buf_out = buf; + + return HB_WORK_OK; +} + diff --git a/libhb/fifo.c b/libhb/fifo.c new file mode 100644 index 000000000..81ca2a184 --- /dev/null +++ b/libhb/fifo.c @@ -0,0 +1,180 @@ +/* $Id: fifo.c,v 1.17 2005/10/15 18:05:03 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#ifndef SYS_DARWIN +#include <malloc.h> +#endif + +hb_buffer_t * hb_buffer_init( int size ) +{ + hb_buffer_t * b; + + if( !( b = calloc( sizeof( hb_buffer_t ), 1 ) ) ) + { + hb_log( "out of memory" ); + return NULL; + } + + b->alloc = size; + b->size = size; +#if defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) + b->data = malloc( size ); +#elif defined( SYS_CYGWIN ) + /* FIXME */ + b->data = malloc( size + 17 ); +#else + b->data = memalign( 16, size ); +#endif + + if( !b->data ) + { + hb_log( "out of memory" ); + free( b ); + return NULL; + } + return b; +} + +void hb_buffer_realloc( hb_buffer_t * b, int size ) +{ + /* No more alignment, but we don't care */ + b->data = realloc( b->data, size ); + b->alloc = size; +} + +void hb_buffer_close( hb_buffer_t ** _b ) +{ + hb_buffer_t * b = *_b; + + if( b->data ) + { + free( b->data ); + } + free( b ); + + *_b = NULL; +} + +/* Fifo */ +struct hb_fifo_s +{ + hb_lock_t * lock; + int capacity; + int size; + hb_buffer_t * first; + hb_buffer_t * last; +}; + +hb_fifo_t * hb_fifo_init( int capacity ) +{ + hb_fifo_t * f; + f = calloc( sizeof( hb_fifo_t ), 1 ); + f->lock = hb_lock_init(); + f->capacity = capacity; + return f; +} + +int hb_fifo_size( hb_fifo_t * f ) +{ + int ret; + + hb_lock( f->lock ); + ret = f->size; + hb_unlock( f->lock ); + + return ret; +} + +int hb_fifo_is_full( hb_fifo_t * f ) +{ + int ret; + + hb_lock( f->lock ); + ret = ( f->size >= f->capacity ); + hb_unlock( f->lock ); + + return ret; +} + +hb_buffer_t * hb_fifo_get( hb_fifo_t * f ) +{ + hb_buffer_t * b; + + hb_lock( f->lock ); + if( f->size < 1 ) + { + hb_unlock( f->lock ); + return NULL; + } + b = f->first; + f->first = b->next; + b->next = NULL; + f->size -= 1; + hb_unlock( f->lock ); + + return b; +} + +hb_buffer_t * hb_fifo_see( hb_fifo_t * f ) +{ + hb_buffer_t * b; + + hb_lock( f->lock ); + if( f->size < 1 ) + { + hb_unlock( f->lock ); + return NULL; + } + b = f->first; + hb_unlock( f->lock ); + + return b; +} + +void hb_fifo_push( hb_fifo_t * f, hb_buffer_t * b ) +{ + if( !b ) + { + return; + } + + hb_lock( f->lock ); + if( f->size > 0 ) + { + f->last->next = b; + } + else + { + f->first = b; + } + f->last = b; + f->size += 1; + while( f->last->next ) + { + f->size += 1; + f->last = f->last->next; + } + hb_unlock( f->lock ); +} + +void hb_fifo_close( hb_fifo_t ** _f ) +{ + hb_fifo_t * f = *_f; + hb_buffer_t * b; + + hb_log( "fifo_close: trashing %d buffer(s)", hb_fifo_size( f ) ); + while( ( b = hb_fifo_get( f ) ) ) + { + hb_buffer_close( &b ); + } + + hb_lock_close( &f->lock ); + free( f ); + + *_f = NULL; +} diff --git a/libhb/hb.c b/libhb/hb.c new file mode 100644 index 000000000..f27a353bc --- /dev/null +++ b/libhb/hb.c @@ -0,0 +1,514 @@ +/* $Id: hb.c,v 1.43 2005/04/27 21:05:24 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "ffmpeg/avcodec.h" + +struct hb_handle_s +{ + /* The "Check for update" thread */ + int build; + char version[16]; + hb_thread_t * update_thread; + + /* This thread's only purpose is to check other threads' + states */ + volatile int die; + hb_thread_t * main_thread; + int pid; + + /* DVD/file scan thread */ + hb_list_t * list_title; + hb_thread_t * scan_thread; + + /* The thread which processes the jobs. Others threads are launched + from this one (see work.c) */ + hb_list_t * jobs; + int job_count; + volatile int work_die; + int work_error; + hb_thread_t * work_thread; + + int cpu_count; + + hb_lock_t * state_lock; + hb_state_t state; + + int paused; + hb_lock_t * pause_lock; +}; + +static void thread_func( void * ); + +hb_handle_t * hb_init( int verbose, int update_check ) +{ + hb_handle_t * h = calloc( sizeof( hb_handle_t ), 1 ); + uint64_t date; + + /* See hb_log() in common.c */ + if( verbose > HB_DEBUG_NONE ) + { + putenv( "HB_DEBUG=1" ); + } + + /* Check for an update on the website if asked to */ + h->build = -1; + + if( update_check ) + { + hb_log( "hb_init: checking for updates" ); + date = hb_get_date(); + h->update_thread = hb_update_init( &h->build, h->version ); + + for( ;; ) + { + if( hb_thread_has_exited( h->update_thread ) ) + { + /* Immediate success or failure */ + hb_thread_close( &h->update_thread ); + break; + } + if( hb_get_date() > date + 1000 ) + { + /* Still nothing after one second. Connection problem, + let the thread die */ + hb_log( "hb_init: connection problem, not waiting for " + "update_thread" ); + break; + } + hb_snooze( 50 ); + } + } + + /* CPU count detection */ + hb_log( "hb_init: checking cpu count" ); + h->cpu_count = hb_get_cpu_count(); + + h->list_title = hb_list_init(); + h->jobs = hb_list_init(); + + h->state_lock = hb_lock_init(); + h->state.state = HB_STATE_IDLE; + + h->pause_lock = hb_lock_init(); + + /* libavcodec */ + avcodec_init(); + register_avcodec( &mpeg4_encoder ); + register_avcodec( &mp2_decoder ); + register_avcodec( &ac3_encoder ); + + /* Start library thread */ + hb_log( "hb_init: starting libhb thread" ); + h->die = 0; + h->main_thread = hb_thread_init( "libhb", thread_func, h, + HB_NORMAL_PRIORITY ); + + return h; +} + +char * hb_get_version( hb_handle_t * h ) +{ + return HB_VERSION; +} + +int hb_get_build( hb_handle_t * h ) +{ + return HB_BUILD; +} + +int hb_check_update( hb_handle_t * h, char ** version ) +{ + *version = ( h->build < 0 ) ? NULL : h->version; + return h->build; +} + +void hb_set_cpu_count( hb_handle_t * h, int cpu_count ) +{ + cpu_count = MAX( 1, cpu_count ); + cpu_count = MIN( cpu_count, 8 ); + h->cpu_count = cpu_count; +} + +void hb_scan( hb_handle_t * h, const char * path, int title_index ) +{ + hb_title_t * title; + + /* Clean up from previous scan */ + while( ( title = hb_list_item( h->list_title, 0 ) ) ) + { + hb_list_rem( h->list_title, title ); + hb_title_close( &title ); + } + + hb_log( "hb_scan: path=%s, title_index=%d", path, title_index ); + h->scan_thread = hb_scan_init( h, path, title_index, h->list_title ); +} + +hb_list_t * hb_get_titles( hb_handle_t * h ) +{ + return h->list_title; +} + +void hb_get_preview( hb_handle_t * h, hb_title_t * title, int picture, + uint8_t * buffer ) +{ + hb_job_t * job = title->job; + char filename[1024]; + FILE * file; + uint8_t * buf1, * buf2, * buf3, * buf4, * pen; + uint32_t * p32; + AVPicture pic1, pic2, pic3, pic4; + ImgReSampleContext * context; + int i; + + buf1 = malloc( title->width * title->height * 3 / 2 ); + buf2 = malloc( title->width * title->height * 3 / 2 ); + buf3 = malloc( title->width * title->height * 3 / 2 ); + buf4 = malloc( title->width * title->height * 4 ); + avpicture_fill( &pic1, buf1, PIX_FMT_YUV420P, + title->width, title->height ); + avpicture_fill( &pic2, buf2, PIX_FMT_YUV420P, + title->width, title->height ); + avpicture_fill( &pic3, buf3, PIX_FMT_YUV420P, + job->width, job->height ); + avpicture_fill( &pic4, buf4, PIX_FMT_RGBA32, + job->width, job->height ); + + memset( filename, 0, 1024 ); + + hb_get_tempory_filename( h, filename, "%x%d", + (int) title, picture ); + + file = fopen( filename, "r" ); + if( !file ) + { + hb_log( "hb_get_preview: fopen failed" ); + return; + } + + fread( buf1, title->width * title->height * 3 / 2, 1, file ); + fclose( file ); + + context = img_resample_full_init( + job->width, job->height, title->width, title->height, + job->crop[0], job->crop[1], job->crop[2], job->crop[3], + 0, 0, 0, 0 ); + + if( job->deinterlace ) + { + avpicture_deinterlace( &pic2, &pic1, PIX_FMT_YUV420P, + title->width, title->height ); + img_resample( context, &pic3, &pic2 ); + } + else + { + img_resample( context, &pic3, &pic1 ); + } + img_convert( &pic4, PIX_FMT_RGBA32, &pic3, PIX_FMT_YUV420P, + job->width, job->height ); + + /* Gray background */ + p32 = (uint32_t *) buffer; + for( i = 0; i < ( title->width + 2 ) * ( title->height + 2 ); i++ ) + { + p32[i] = 0xFF808080; + } + + /* Draw the picture, centered, and draw the cropping zone */ + pen = buffer + ( title->height - job->height ) * + ( title->width + 2 ) * 2 + ( title->width - job->width ) * 2; + memset( pen, 0xFF, 4 * ( job->width + 2 ) ); + pen += 4 * ( title->width + 2 ); + for( i = 0; i < job->height; i++ ) + { + uint8_t * nextLine; + nextLine = pen + 4 * ( title->width + 2 ); + memset( pen, 0xFF, 4 ); + pen += 4; + memcpy( pen, buf4 + 4 * job->width * i, 4 * job->width ); + pen += 4 * job->width; + memset( pen, 0xFF, 4 ); + pen = nextLine; + } + memset( pen, 0xFF, 4 * ( job->width + 2 ) ); + + free( buf1 ); + free( buf2 ); + free( buf3 ); + free( buf4 ); +} + +int hb_count( hb_handle_t * h ) +{ + return hb_list_count( h->jobs ); +} + +hb_job_t * hb_job( hb_handle_t * h, int i ) +{ + return hb_list_item( h->jobs, i ); +} + +/* hb_add: memcpy() party. That's ugly, for if someone has a better + idea... */ +void hb_add( hb_handle_t * h, hb_job_t * job ) +{ + hb_job_t * job_copy; + hb_title_t * title, * title_copy; + hb_chapter_t * chapter, * chapter_copy; + hb_audio_t * audio, * audio_copy; + hb_subtitle_t * subtitle, * subtitle_copy; + int i; + + /* Copy the title */ + title = job->title; + title_copy = malloc( sizeof( hb_title_t ) ); + memcpy( title_copy, title, sizeof( hb_title_t ) ); + + title_copy->list_chapter = hb_list_init(); + for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) + { + chapter = hb_list_item( title->list_chapter, i ); + chapter_copy = malloc( sizeof( hb_chapter_t ) ); + memcpy( chapter_copy, chapter, sizeof( hb_chapter_t ) ); + hb_list_add( title_copy->list_chapter, chapter_copy ); + } + + /* Copy the audio track(s) we want */ + title_copy->list_audio = hb_list_init(); + + /* Do nothing about audio during first pass */ + if( job->pass != 1 ) + { + for( i = 0; i < 8; i++ ) + { + if( job->audios[i] < 0 ) + { + break; + } + if( ( audio = hb_list_item( title->list_audio, job->audios[i] ) ) ) + { + audio_copy = malloc( sizeof( hb_audio_t ) ); + memcpy( audio_copy, audio, sizeof( hb_audio_t ) ); + hb_list_add( title_copy->list_audio, audio_copy ); + } + } + } + + /* Copy the subtitle we want (or not) */ + title_copy->list_subtitle = hb_list_init(); + if( ( subtitle = hb_list_item( title->list_subtitle, job->subtitle ) ) ) + { + subtitle_copy = malloc( sizeof( hb_subtitle_t ) ); + memcpy( subtitle_copy, subtitle, sizeof( hb_subtitle_t ) ); + hb_list_add( title_copy->list_subtitle, subtitle_copy ); + } + + /* Copy the job */ + job_copy = calloc( sizeof( hb_job_t ), 1 ); + memcpy( job_copy, job, sizeof( hb_job_t ) ); + job_copy->title = title_copy; + job_copy->file = strdup( job->file ); + job_copy->h = h; + job_copy->pause = h->pause_lock; + + /* Add the job to the list */ + hb_list_add( h->jobs, job_copy ); +} + +void hb_rem( hb_handle_t * h, hb_job_t * job ) +{ + hb_list_rem( h->jobs, job ); + + /* XXX free everything XXX */ +} + +void hb_start( hb_handle_t * h ) +{ + /* XXX Hack */ + h->job_count = hb_list_count( h->jobs ); + + hb_lock( h->state_lock ); + h->state.state = HB_STATE_WORKING; +#define p h->state.param.working + p.progress = 0.0; + p.job_cur = 1; + p.job_count = h->job_count; + p.rate_cur = 0.0; + p.rate_avg = 0.0; + p.hours = -1; + p.minutes = -1; + p.seconds = -1; +#undef p + hb_unlock( h->state_lock ); + + h->paused = 0; + + h->work_die = 0; + h->work_thread = hb_work_init( h->jobs, h->cpu_count, + &h->work_die, &h->work_error ); +} + +void hb_pause( hb_handle_t * h ) +{ + if( !h->paused ) + { + hb_lock( h->pause_lock ); + h->paused = 1; + + hb_lock( h->state_lock ); + h->state.state = HB_STATE_PAUSED; + hb_unlock( h->state_lock ); + } +} + +void hb_resume( hb_handle_t * h ) +{ + if( h->paused ) + { + hb_unlock( h->pause_lock ); + h->paused = 0; + } +} + +void hb_stop( hb_handle_t * h ) +{ + h->work_die = 1; + + hb_resume( h ); +} + +void hb_get_state( hb_handle_t * h, hb_state_t * s ) +{ + hb_lock( h->state_lock ); + + memcpy( s, &h->state, sizeof( hb_state_t ) ); + h->state.state = HB_STATE_IDLE; + + hb_unlock( h->state_lock ); +} + +void hb_close( hb_handle_t ** _h ) +{ + hb_handle_t * h = *_h; + hb_title_t * title; + + h->die = 1; + hb_thread_close( &h->main_thread ); + + while( ( title = hb_list_item( h->list_title, 0 ) ) ) + { + hb_list_rem( h->list_title, title ); + hb_title_close( &title ); + } + hb_list_close( &h->list_title ); + + hb_list_close( &h->jobs ); + hb_lock_close( &h->state_lock ); + hb_lock_close( &h->pause_lock ); + free( h ); + *_h = NULL; +} + +static void thread_func( void * _h ) +{ + hb_handle_t * h = (hb_handle_t *) _h; + char dirname[1024]; + DIR * dir; + struct dirent * entry; + + h->pid = getpid(); + + /* Create folder for temporary files */ + memset( dirname, 0, 1024 ); + hb_get_tempory_directory( h, dirname ); + + hb_mkdir( dirname ); + + while( !h->die ) + { + /* In case the check_update thread hangs, it'll die sooner or + later. Then, we join it here */ + if( h->update_thread && + hb_thread_has_exited( h->update_thread ) ) + { + hb_thread_close( &h->update_thread ); + } + + /* Check if the scan thread is done */ + if( h->scan_thread && + hb_thread_has_exited( h->scan_thread ) ) + { + hb_thread_close( &h->scan_thread ); + + hb_log( "libhb: scan thread found %d valid title(s)", + hb_list_count( h->list_title ) ); + hb_lock( h->state_lock ); + h->state.state = HB_STATE_SCANDONE; + hb_unlock( h->state_lock ); + } + + /* Check if the work thread is done */ + if( h->work_thread && + hb_thread_has_exited( h->work_thread ) ) + { + hb_thread_close( &h->work_thread ); + + hb_log( "libhb: work result = %d", + h->work_error ); + hb_lock( h->state_lock ); + h->state.state = HB_STATE_WORKDONE; + h->state.param.workdone.error = h->work_error; + hb_unlock( h->state_lock ); + } + + hb_snooze( 50 ); + } + + if( h->work_thread ) + { + hb_stop( h ); + hb_thread_close( &h->work_thread ); + } + + /* Remove temp folder */ + dir = opendir( dirname ); + while( ( entry = readdir( dir ) ) ) + { + char filename[1024]; + if( entry->d_name[0] == '.' ) + { + continue; + } + memset( filename, 0, 1024 ); + snprintf( filename, 1023, "%s/%s", dirname, entry->d_name ); + unlink( filename ); + } + closedir( dir ); + rmdir( dirname ); +} + +int hb_get_pid( hb_handle_t * h ) +{ + return h->pid; +} + +void hb_set_state( hb_handle_t * h, hb_state_t * s ) +{ + hb_lock( h->pause_lock ); + hb_lock( h->state_lock ); + memcpy( &h->state, s, sizeof( hb_state_t ) ); + if( h->state.state == HB_STATE_WORKING ) + { + /* XXX Hack */ + h->state.param.working.job_cur = + h->job_count - hb_list_count( h->jobs ); + h->state.param.working.job_count = h->job_count; + } + hb_unlock( h->state_lock ); + hb_unlock( h->pause_lock ); +} diff --git a/libhb/hb.h b/libhb/hb.h new file mode 100644 index 000000000..4a64c9047 --- /dev/null +++ b/libhb/hb.h @@ -0,0 +1,76 @@ +/* $Id: hb.h,v 1.12 2005/03/29 09:40:28 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#ifndef HB_HB_H +#define HB_HB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common.h" + +/* hb_init() + Initializes a libhb session (launches his own thread, detects CPUs, + etc) */ +#define HB_DEBUG_NONE 0 +#define HB_DEBUG_ALL 1 +hb_handle_t * hb_init( int verbose, int update_check ); + +/* hb_get_version() */ +char * hb_get_version( hb_handle_t * ); +int hb_get_build( hb_handle_t * ); + +/* hb_check_update() + Checks for an update on the website. If there is, returns the build + number and points 'version' to a version description. Returns a + negative value otherwise. */ +int hb_check_update( hb_handle_t * h, char ** version ); + +/* hb_set_cpu_count() + Force libhb to act as if you had X CPU(s). + Default is to use the detected count (see also hb_get_cpu_count() in + ports.h) */ +void hb_set_cpu_count( hb_handle_t *, int ); + +/* hb_scan() + Scan the specified path. Can be a DVD device, a VIDEO_TS folder or + a VOB file. If title_index is 0, scan all titles. */ +void hb_scan( hb_handle_t *, const char * path, + int title_index ); + +/* hb_get_titles() + Returns the list of valid titles detected by the latest scan. */ +hb_list_t * hb_get_titles( hb_handle_t * ); + +void hb_get_preview( hb_handle_t *, hb_title_t *, int, + uint8_t * ); + +/* Handling jobs */ +int hb_count( hb_handle_t * ); +hb_job_t * hb_job( hb_handle_t *, int ); +void hb_add( hb_handle_t *, hb_job_t * ); +void hb_rem( hb_handle_t *, hb_job_t * ); + +void hb_start( hb_handle_t * ); +void hb_pause( hb_handle_t * ); +void hb_resume( hb_handle_t * ); +void hb_stop( hb_handle_t * ); + +/* hb_get_state() + Should be regularly called by the UI (like 5 or 10 times a second). + Look at test/test.c to see how to use it. */ +void hb_get_state( hb_handle_t *, hb_state_t * ); + +/* hb_close() + Aborts all current jobs if any, frees memory. */ +void hb_close( hb_handle_t ** ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libhb/internal.h b/libhb/internal.h new file mode 100644 index 000000000..e22da82ee --- /dev/null +++ b/libhb/internal.h @@ -0,0 +1,172 @@ +/* $Id: internal.h,v 1.40 2005/04/27 10:14:02 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +/*********************************************************************** + * common.c + **********************************************************************/ +void hb_log( char * log, ... ); + +int hb_list_bytes( hb_list_t * ); +void hb_list_seebytes( hb_list_t * l, uint8_t * dst, int size ); +void hb_list_getbytes( hb_list_t * l, uint8_t * dst, int size, + uint64_t * pts, int * pos ); +void hb_list_empty( hb_list_t ** ); + +hb_title_t * hb_title_init( char * dvd, int index ); +void hb_title_close( hb_title_t ** ); + +/*********************************************************************** + * hb.c + **********************************************************************/ +int hb_get_pid( hb_handle_t * ); +void hb_set_state( hb_handle_t *, hb_state_t * ); + +/*********************************************************************** + * fifo.c + **********************************************************************/ +typedef struct hb_buffer_s hb_buffer_t; +struct hb_buffer_s +{ + int size; + int alloc; + uint8_t * data; + int cur; + + int id; + int64_t start; + int64_t stop; + int key; + + int x; + int y; + int width; + int height; + + hb_buffer_t * sub; + + hb_buffer_t * next; +}; + +hb_buffer_t * hb_buffer_init( int size ); +void hb_buffer_realloc( hb_buffer_t *, int size ); +void hb_buffer_close( hb_buffer_t ** ); + +typedef struct hb_fifo_s hb_fifo_t; + +hb_fifo_t * hb_fifo_init(); +int hb_fifo_size( hb_fifo_t * ); +int hb_fifo_is_full( hb_fifo_t * ); +hb_buffer_t * hb_fifo_get( hb_fifo_t * ); +hb_buffer_t * hb_fifo_see( hb_fifo_t * ); +void hb_fifo_push( hb_fifo_t *, hb_buffer_t * ); +void hb_fifo_close( hb_fifo_t ** ); + +/*********************************************************************** + * Threads: update.c, scan.c, work.c, reader.c, muxcommon.c + **********************************************************************/ +hb_thread_t * hb_update_init( int * build, char * version ); +hb_thread_t * hb_scan_init( hb_handle_t *, const char * path, + int title_index, hb_list_t * list_title ); +hb_thread_t * hb_work_init( hb_list_t * jobs, int cpu_count, + volatile int * die, int * error ); +hb_thread_t * hb_reader_init( hb_job_t * ); +hb_thread_t * hb_muxer_init( hb_job_t * ); + +/*********************************************************************** + * libmpeg2 wrapper + *********************************************************************** + * It is exported here because it is used at several places + **********************************************************************/ +typedef struct hb_libmpeg2_s hb_libmpeg2_t; + +hb_libmpeg2_t * hb_libmpeg2_init(); +int hb_libmpeg2_decode( hb_libmpeg2_t *, + hb_buffer_t * es_buf, + hb_list_t * raw_list ); +void hb_libmpeg2_info( hb_libmpeg2_t * m, int * width, + int * height, int * rate ); +void hb_libmpeg2_close( hb_libmpeg2_t ** ); + +/*********************************************************************** + * mpegdemux.c + **********************************************************************/ +int hb_demux_ps( hb_buffer_t * ps_buf, hb_list_t * es_list ); + +/*********************************************************************** + * dvd.c + **********************************************************************/ +typedef struct hb_dvd_s hb_dvd_t; + +hb_dvd_t * hb_dvd_init( char * path ); +int hb_dvd_title_count( hb_dvd_t * ); +hb_title_t * hb_dvd_title_scan( hb_dvd_t *, int title ); +int hb_dvd_start( hb_dvd_t *, int title, int chapter ); +int hb_dvd_seek( hb_dvd_t *, float ); +int hb_dvd_read( hb_dvd_t *, hb_buffer_t * ); +int hb_dvd_chapter( hb_dvd_t * ); +void hb_dvd_close( hb_dvd_t ** ); + +/*********************************************************************** + * Work objects + **********************************************************************/ +typedef struct hb_work_object_s hb_work_object_t; + +#define HB_WORK_COMMON \ + hb_lock_t * lock; \ + int used; \ + uint64_t time; \ + char * name; \ + hb_fifo_t * fifo_in; \ + hb_fifo_t * fifo_out; \ + int (* work) ( hb_work_object_t *, hb_buffer_t **, \ + hb_buffer_t ** ); \ + void (* close) ( hb_work_object_t ** ) + +#define HB_WORK_IDLE 0 +#define HB_WORK_OK 1 +#define HB_WORK_ERROR 2 +#define HB_WORK_DONE 3 + + +#define DECLARE_WORK_NORMAL( a ) \ + hb_work_object_t * hb_work_##a##_init( hb_job_t * ); + +#define DECLARE_WORK_AUDIO( a ) \ + hb_work_object_t * hb_work_##a##_init( hb_job_t *, hb_audio_t * ); + +DECLARE_WORK_NORMAL( sync ); +DECLARE_WORK_NORMAL( decmpeg2 ); +DECLARE_WORK_NORMAL( decsub ); +DECLARE_WORK_NORMAL( render ); +DECLARE_WORK_NORMAL( encavcodec ); +DECLARE_WORK_NORMAL( encxvid ); +DECLARE_WORK_NORMAL( encx264 ); +DECLARE_WORK_AUDIO( deca52 ); +DECLARE_WORK_AUDIO( decavcodec ); +DECLARE_WORK_AUDIO( declpcm ); +DECLARE_WORK_AUDIO( encfaac ); +DECLARE_WORK_AUDIO( enclame ); +DECLARE_WORK_AUDIO( encvorbis ); + +/*********************************************************************** + * Muxers + **********************************************************************/ +typedef struct hb_mux_object_s hb_mux_object_t; +typedef struct hb_mux_data_s hb_mux_data_t; + +#define HB_MUX_COMMON \ + int (*init) ( hb_mux_object_t * ); \ + int (*mux) ( hb_mux_object_t *, hb_mux_data_t *, \ + hb_buffer_t * ); \ + int (*end) ( hb_mux_object_t * ); + +#define DECLARE_MUX( a ) \ + hb_mux_object_t * hb_mux_##a##_init( hb_job_t * ); + +DECLARE_MUX( mp4 ); +DECLARE_MUX( avi ); +DECLARE_MUX( ogm ); + diff --git a/core/Languages.h b/libhb/lang.h index 7949688c9..f88f539ff 100644 --- a/core/Languages.h +++ b/libhb/lang.h @@ -1,20 +1,21 @@ -/* $Id: Languages.h,v 1.1 2003/11/03 12:08:01 titer Exp $ +/* $Id: lang.h,v 1.1 2004/08/02 07:19:05 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#ifndef HB_LANGUAGES_H -#define HB_LANGUAGES_H +#ifndef HB_LANG_H +#define HB_LANG_H typedef struct iso639_lang_t { - char * engName; /* Description in English */ - char * nativeName; /* Description in native language */ + char * eng_name; /* Description in English */ + char * native_name; /* Description in native language */ char * iso639_1; /* ISO-639-1 (2 characters) code */ + } iso639_lang_t; -static iso639_lang_t languages[] = +static const iso639_lang_t languages[] = { { "Afar", "", "aa" }, { "Abkhazian", "", "ab" }, { "Afrikaans", "", "af" }, @@ -181,4 +182,28 @@ static iso639_lang_t languages[] = { "Zulu", "", "zu" }, { NULL, NULL, NULL } }; +static char * lang_for_code( int code ) +{ + char code_string[2]; + iso639_lang_t * lang; + + code_string[0] = ( code >> 8 ) & 0xFF; + code_string[1] = code & 0xFF; + + for( lang = (iso639_lang_t*) languages; lang->eng_name; lang++ ) + { + if( !strncmp( lang->iso639_1, code_string, 2 ) ) + { + if( *lang->native_name ) + { + return lang->native_name; + } + + return lang->eng_name; + } + } + + return "Unknown"; +} + #endif diff --git a/libhb/muxavi.c b/libhb/muxavi.c new file mode 100644 index 000000000..8746a3cdd --- /dev/null +++ b/libhb/muxavi.c @@ -0,0 +1,551 @@ +/* $Id: muxavi.c,v 1.10 2005/03/30 18:17:29 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#define AVIF_HASINDEX 0x10 +#define AVIIF_KEYFRAME 0x10 +#define FOURCC(a) ((a[3]<<24)|(a[2]<<16)|(a[1]<<8)|a[0]) + +/* Structures definitions */ +typedef struct __attribute__((__packed__)) +{ + uint32_t FourCC; + uint32_t BytesCount; + uint32_t MicroSecPerFrame; + uint32_t MaxBytesPerSec; + uint32_t PaddingGranularity; + uint32_t Flags; + uint32_t TotalFrames; + uint32_t InitialFrames; + uint32_t Streams; + uint32_t SuggestedBufferSize; + uint32_t Width; + uint32_t Height; + uint32_t Reserved[4]; + +} hb_avi_main_header_t; + +typedef struct __attribute__((__packed__)) +{ + uint32_t FourCC; + uint32_t BytesCount; + uint32_t Type; + uint32_t Handler; + uint32_t Flags; + uint16_t Priority; + uint16_t Language; + uint32_t InitialFrames; + uint32_t Scale; + uint32_t Rate; + uint32_t Start; + uint32_t Length; + uint32_t SuggestedBufferSize; + uint32_t Quality; + uint32_t SampleSize; + int16_t Left; + int16_t Top; + int16_t Right; + int16_t Bottom; + +} hb_avi_stream_header_t; + +typedef struct __attribute__((__packed__)) +{ + uint32_t FourCC; + uint32_t BytesCount; + uint32_t Size; + uint32_t Width; + uint32_t Height; + uint16_t Planes; + uint16_t BitCount; + uint32_t Compression; + uint32_t SizeImage; + uint32_t XPelsPerMeter; + uint32_t YPelsPerMeter; + uint32_t ClrUsed; + uint32_t ClrImportant; + +} hb_bitmap_info_t; + +typedef struct __attribute__((__packed__)) +{ + uint32_t FourCC; + uint32_t BytesCount; + uint16_t FormatTag; + uint16_t Channels; + uint32_t SamplesPerSec; + uint32_t AvgBytesPerSec; + uint16_t BlockAlign; + uint16_t BitsPerSample; + uint16_t Size; + +} hb_wave_formatex_t; + +typedef struct __attribute__((__packed__)) +{ + uint16_t Id; + uint32_t Flags; + uint16_t BlockSize; + uint16_t FramesPerBlock; + uint16_t CodecDelay; + +} hb_wave_mp3_t; + +static void WriteBuffer( FILE * file, hb_buffer_t * buf ) +{ + fwrite( buf->data, buf->size, 1, file ); +} + +/* Little-endian write routines */ + +static void WriteInt8( FILE * file, uint8_t val ) +{ + fputc( val, file ); +} + +static void WriteInt16( FILE * file, uint16_t val ) +{ + fputc( val & 0xFF, file ); + fputc( val >> 8, file ); +} + +static void WriteInt32( FILE * file, uint32_t val ) +{ + fputc( val & 0xFF, file ); + fputc( ( val >> 8 ) & 0xFF, file ); + fputc( ( val >> 16 ) & 0xFF, file ); + fputc( val >> 24, file ); +} + +static void WriteBitmapInfo( FILE * file, hb_bitmap_info_t * info ) +{ + WriteInt32( file, info->FourCC ); + WriteInt32( file, info->BytesCount ); + WriteInt32( file, info->Size ); + WriteInt32( file, info->Width ); + WriteInt32( file, info->Height ); + WriteInt16( file, info->Planes ); + WriteInt16( file, info->BitCount ); + WriteInt32( file, info->Compression ); + WriteInt32( file, info->SizeImage ); + WriteInt32( file, info->XPelsPerMeter ); + WriteInt32( file, info->YPelsPerMeter ); + WriteInt32( file, info->ClrUsed ); + WriteInt32( file, info->ClrImportant ); +} + +static void WriteWaveFormatEx( FILE * file, hb_wave_formatex_t * format ) +{ + WriteInt32( file, format->FourCC ); + WriteInt32( file, format->BytesCount ); + WriteInt16( file, format->FormatTag ); + WriteInt16( file, format->Channels ); + WriteInt32( file, format->SamplesPerSec ); + WriteInt32( file, format->AvgBytesPerSec ); + WriteInt16( file, format->BlockAlign ); + WriteInt16( file, format->BitsPerSample ); + WriteInt16( file, format->Size ); +} + +static void WriteWaveMp3( FILE * file, hb_wave_mp3_t * mp3 ) +{ + WriteInt16( file, mp3->Id ); + WriteInt32( file, mp3->Flags ); + WriteInt16( file, mp3->BlockSize ); + WriteInt16( file, mp3->FramesPerBlock ); + WriteInt16( file, mp3->CodecDelay ); +} + +static void WriteMainHeader( FILE * file, hb_avi_main_header_t * header ) +{ + WriteInt32( file, header->FourCC ); + WriteInt32( file, header->BytesCount ); + WriteInt32( file, header->MicroSecPerFrame ); + WriteInt32( file, header->MaxBytesPerSec ); + WriteInt32( file, header->PaddingGranularity ); + WriteInt32( file, header->Flags ); + WriteInt32( file, header->TotalFrames ); + WriteInt32( file, header->InitialFrames ); + WriteInt32( file, header->Streams ); + WriteInt32( file, header->SuggestedBufferSize ); + WriteInt32( file, header->Width ); + WriteInt32( file, header->Height ); + WriteInt32( file, header->Reserved[0] ); + WriteInt32( file, header->Reserved[1] ); + WriteInt32( file, header->Reserved[2] ); + WriteInt32( file, header->Reserved[3] ); +} + +static void WriteStreamHeader( FILE * file, hb_avi_stream_header_t * header ) +{ + WriteInt32( file, header->FourCC ); + WriteInt32( file, header->BytesCount ); + WriteInt32( file, header->Type ); + WriteInt32( file, header->Handler ); + WriteInt32( file, header->Flags ); + WriteInt16( file, header->Priority ); + WriteInt16( file, header->Language ); + WriteInt32( file, header->InitialFrames ); + WriteInt32( file, header->Scale ); + WriteInt32( file, header->Rate ); + WriteInt32( file, header->Start ); + WriteInt32( file, header->Length ); + WriteInt32( file, header->SuggestedBufferSize ); + WriteInt32( file, header->Quality ); + WriteInt32( file, header->SampleSize ); + WriteInt16( file, header->Left ); + WriteInt16( file, header->Top ); + WriteInt16( file, header->Right ); + WriteInt16( file, header->Bottom ); +} + +static void IndexAddInt32( hb_buffer_t * b, uint32_t val ) +{ + if( b->size + 16 > b->alloc ) + { + hb_log( "muxavi: reallocing index (%d MB)", + 1 + b->alloc / 1024 / 1024 ); + hb_buffer_realloc( b, b->alloc + 1024 * 1024 ); + } + + b->data[b->size++] = val & 0xFF; + b->data[b->size++] = ( val >> 8 ) & 0xFF; + b->data[b->size++] = ( val >> 16 ) & 0xFF; + b->data[b->size++] = val >> 24; +} + +struct hb_mux_object_s +{ + HB_MUX_COMMON; + + hb_job_t * job; + + /* Data size in bytes, not including headers */ + unsigned size; + FILE * file; + hb_buffer_t * index; + hb_avi_main_header_t main_header; +}; + +struct hb_mux_data_s +{ + uint32_t fourcc; + hb_avi_stream_header_t header; + union + { + hb_bitmap_info_t v; + struct + { + hb_wave_formatex_t f; + hb_wave_mp3_t m; + } a; + } format; +}; + +static void AddIndex( hb_mux_object_t * m ) +{ + fseek( m->file, 0, SEEK_END ); + + /* Write the index at the end of the file */ + WriteInt32( m->file, FOURCC( "idx1" ) ); + WriteInt32( m->file, m->index->size ); + WriteBuffer( m->file, m->index ); + + /* Update file size */ + m->size += 8 + m->index->size; + fseek( m->file, 4, SEEK_SET ); + WriteInt32( m->file, 2040 + m->size ); + + /* Update HASINDEX flag */ + m->main_header.Flags |= AVIF_HASINDEX; + fseek( m->file, 24, SEEK_SET ); + WriteMainHeader( m->file, &m->main_header ); +} + + +/********************************************************************** + * AVIInit + ********************************************************************** + * Allocates things, create file, initialize and write headers + *********************************************************************/ +static int AVIInit( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + hb_title_t * title = job->title; + + hb_audio_t * audio; + hb_mux_data_t * mux_data; + + int audio_count = hb_list_count( title->list_audio ); + int is_ac3 = ( job->acodec & HB_ACODEC_AC3 ); + int hdrl_bytes; + int i; + + /* Allocate index */ + m->index = hb_buffer_init( 1024 * 1024 ); + m->index->size = 0; + + /* Open destination file */ + hb_log( "muxavi: opening %s", job->file ); + m->file = fopen( job->file, "wb" ); + +#define m m->main_header + /* AVI main header */ + m.FourCC = FOURCC( "avih" ); + m.BytesCount = sizeof( hb_avi_main_header_t ) - 8; + m.MicroSecPerFrame = (uint64_t) 1000000 * job->vrate_base / job->vrate; + m.Streams = 1 + audio_count; + m.Width = job->width; + m.Height = job->height; +#undef m + + /* Video track */ + mux_data = calloc( sizeof( hb_mux_data_t ), 1 ); + job->mux_data = mux_data; + +#define h mux_data->header + /* Video stream header */ + h.FourCC = FOURCC( "strh" ); + h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8; + h.Type = FOURCC( "vids" ); + + if( job->vcodec == HB_VCODEC_FFMPEG ) + h.Handler = FOURCC( "divx" ); + else if( job->vcodec == HB_VCODEC_XVID ) + h.Handler = FOURCC( "xvid" ); + else if( job->vcodec == HB_VCODEC_X264 ) + h.Handler = FOURCC( "h264" ); + + h.Scale = job->vrate_base; + h.Rate = job->vrate; +#undef h + +#define f mux_data->format.v + /* Video stream format */ + f.FourCC = FOURCC( "strf" ); + f.BytesCount = sizeof( hb_bitmap_info_t ) - 8; + f.Size = f.BytesCount; + f.Width = job->width; + f.Height = job->height; + f.Planes = 1; + f.BitCount = 24; + if( job->vcodec == HB_VCODEC_FFMPEG ) + f.Compression = FOURCC( "DX50" ); + else if( job->vcodec == HB_VCODEC_XVID ) + f.Compression = FOURCC( "XVID" ); + else if( job->vcodec == HB_VCODEC_X264 ) + f.Compression = FOURCC( "H264" ); +#undef f + + /* Audio tracks */ + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + + mux_data = calloc( sizeof( hb_mux_data_t ), 1 ); + audio->mux_data = mux_data; + +#define h mux_data->header +#define f mux_data->format.a.f +#define m mux_data->format.a.m + /* Audio stream header */ + h.FourCC = FOURCC( "strh" ); + h.BytesCount = sizeof( hb_avi_stream_header_t ) - 8; + h.Type = FOURCC( "auds" ); + h.InitialFrames = 1; + h.Scale = 1; + h.Rate = is_ac3 ? ( audio->bitrate / 8 ) : + ( job->abitrate * 1000 / 8 ); + h.Quality = 0xFFFFFFFF; + h.SampleSize = 1; + + /* Audio stream format */ + f.FourCC = FOURCC( "strf" ); + if( is_ac3 ) + { + f.BytesCount = sizeof( hb_wave_formatex_t ) - 8; + f.FormatTag = 0x2000; + f.Channels = audio->channels; + f.SamplesPerSec = audio->rate; + } + else + { + f.BytesCount = sizeof( hb_wave_formatex_t ) + + sizeof( hb_wave_mp3_t ) - 8; + f.FormatTag = 0x55; + f.Channels = 2; + f.SamplesPerSec = job->arate; + } + f.AvgBytesPerSec = h.Rate; + f.BlockAlign = 1; + if( is_ac3 ) + { + f.Size = 0; + } + else + { + f.Size = sizeof( hb_wave_mp3_t ); + m.Id = 1; + m.Flags = 2; + m.BlockSize = 1152 * f.AvgBytesPerSec / job->arate; + m.FramesPerBlock = 1; + m.CodecDelay = 1393; + } +#undef h +#undef f +#undef m + } + + hdrl_bytes = + /* Main header */ + 4 + sizeof( hb_avi_main_header_t ) + + /* strh for video + audios */ + ( 1 + audio_count ) * ( 12 + sizeof( hb_avi_stream_header_t ) ) + + /* video strf */ + sizeof( hb_bitmap_info_t ) + + /* audios strf */ + audio_count * ( sizeof( hb_wave_formatex_t ) + + ( is_ac3 ? 0 : sizeof( hb_wave_mp3_t ) ) ); + + /* Here we really start to write into the file */ + + /* Main headers */ + WriteInt32( m->file, FOURCC( "RIFF" ) ); + WriteInt32( m->file, 2040 ); + WriteInt32( m->file, FOURCC( "AVI " ) ); + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, hdrl_bytes ); + WriteInt32( m->file, FOURCC( "hdrl" ) ); + WriteMainHeader( m->file, &m->main_header ); + + /* Video track */ + mux_data = job->mux_data; + mux_data->fourcc = FOURCC( "00dc" ); + + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) + + sizeof( hb_bitmap_info_t ) ); + WriteInt32( m->file, FOURCC( "strl" ) ); + WriteStreamHeader( m->file, &mux_data->header ); + WriteBitmapInfo( m->file, &mux_data->format.v ); + + /* Audio tracks */ + for( i = 0; i < audio_count; i++ ) + { + char fourcc[4] = "00wb"; + + audio = hb_list_item( title->list_audio, i ); + mux_data = audio->mux_data; + + fourcc[1] = '1' + i; /* This is fine as we don't allow more + than 8 tracks */ + mux_data->fourcc = FOURCC( fourcc ); + + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) + + sizeof( hb_wave_formatex_t ) + + ( is_ac3 ? 0 : sizeof( hb_wave_mp3_t ) ) ); + WriteInt32( m->file, FOURCC( "strl" ) ); + WriteStreamHeader( m->file, &mux_data->header ); + WriteWaveFormatEx( m->file, &mux_data->format.a.f ); + if( !is_ac3 ) + { + WriteWaveMp3( m->file, &mux_data->format.a.m ); + } + } + + WriteInt32( m->file, FOURCC( "JUNK" ) ); + WriteInt32( m->file, 2020 - hdrl_bytes ); + for( i = 0; i < 2020 - hdrl_bytes; i++ ) + { + WriteInt8( m->file, 0 ); + } + WriteInt32( m->file, FOURCC( "LIST" ) ); + WriteInt32( m->file, 4 ); + WriteInt32( m->file, FOURCC( "movi" ) ); + + return 0; +} + +static int AVIMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, + hb_buffer_t * buf ) +{ + hb_job_t * job = m->job; + hb_title_t * title = job->title; + + hb_audio_t * audio; + int i; + + /* Update index */ + IndexAddInt32( m->index, mux_data->fourcc ); + IndexAddInt32( m->index, buf->key ? AVIIF_KEYFRAME : 0 ); + IndexAddInt32( m->index, 4 + m->size ); + IndexAddInt32( m->index, buf->size ); + + /* Write the chunk to the file */ + fseek( m->file, 0, SEEK_END ); + WriteInt32( m->file, mux_data->fourcc ); + WriteInt32( m->file, buf->size ); + WriteBuffer( m->file, buf ); + + /* Chunks must be 2-bytes aligned */ + if( buf->size & 1 ) + { + WriteInt8( m->file, 0 ); + } + + /* Update headers */ + m->size += 8 + EVEN( buf->size ); + mux_data->header.Length++; + + /* RIFF size */ + fseek( m->file, 4, SEEK_SET ); + WriteInt32( m->file, 2052 + m->size ); + + /* Mmmmh that's not nice */ + fseek( m->file, 140, SEEK_SET ); + WriteInt32( m->file, job->mux_data->header.Length ); + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + fseek( m->file, 264 + i * + ( 102 + ( ( job->acodec & HB_ACODEC_AC3 ) ? 0 : + sizeof( hb_wave_mp3_t ) ) ), SEEK_SET ); + WriteInt32( m->file, audio->mux_data->header.Length ); + } + + /* movi size */ + fseek( m->file, 2052, SEEK_SET ); + WriteInt32( m->file, 4 + m->size ); + return 0; +} + +static int AVIEnd( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + + hb_log( "muxavi: writing index" ); + AddIndex( m ); + + hb_log( "muxavi: closing %s", job->file ); + fclose( m->file ); + + hb_buffer_close( &m->index ); + + return 0; +} + +hb_mux_object_t * hb_mux_avi_init( hb_job_t * job ) +{ + hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 ); + m->init = AVIInit; + m->mux = AVIMux; + m->end = AVIEnd; + m->job = job; + return m; +} + diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c new file mode 100644 index 000000000..090f332b2 --- /dev/null +++ b/libhb/muxcommon.c @@ -0,0 +1,215 @@ +/* $Id: muxcommon.c,v 1.23 2005/03/30 17:27:19 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +struct hb_mux_object_s +{ + HB_MUX_COMMON; +}; + +typedef struct +{ + hb_job_t * job; + uint64_t pts; + +} hb_mux_t; + +typedef struct +{ + hb_fifo_t * fifo; + hb_mux_data_t * mux_data; + uint64_t frames; + uint64_t bytes; + +} hb_track_t; + +static hb_track_t * GetTrack( hb_list_t * list ) +{ + hb_buffer_t * buf; + hb_track_t * track = NULL, * track2; + int64_t pts = 0; + int i; + + for( i = 0; i < hb_list_count( list ); i++ ) + { + track2 = hb_list_item( list, i ); + buf = hb_fifo_see( track2->fifo ); + if( !buf ) + { + return NULL; + } + if( !track || buf->start < pts ) + { + track = track2; + pts = buf->start; + } + } + return track; +} + +static void MuxerFunc( void * _mux ) +{ + hb_mux_t * mux = _mux; + hb_job_t * job = mux->job; + hb_title_t * title = job->title; + hb_audio_t * audio; + hb_list_t * list; + hb_buffer_t * buf; + hb_track_t * track; + int i; + + hb_mux_object_t * m = NULL; + + /* Get a real muxer */ + if( job->pass != 1 ) + { + switch( job->mux ) + { + case HB_MUX_MP4: + m = hb_mux_mp4_init( job ); + break; + case HB_MUX_AVI: + m = hb_mux_avi_init( job ); + break; + case HB_MUX_OGM: + m = hb_mux_ogm_init( job ); + break; + } + } + + /* Wait for one buffer for each track */ + while( !*job->die && !job->done ) + { + int ready; + + ready = 1; + if( !hb_fifo_size( job->fifo_mpeg4 ) ) + { + ready = 0; + } + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( !hb_fifo_size( audio->fifo_out ) ) + { + ready = 0; + break; + } + } + + if( ready ) + { + break; + } + + hb_snooze( 50 ); + } + + /* Create file, write headers */ + if( job->pass != 1 ) + { + m->init( m ); + } + + /* Build list of fifos we're interested in */ + list = hb_list_init(); + + track = calloc( sizeof( hb_track_t ), 1 ); + track->fifo = job->fifo_mpeg4; + track->mux_data = job->mux_data; + hb_list_add( list, track ); + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + track = calloc( sizeof( hb_track_t ), 1 ); + track->fifo = audio->fifo_out; + track->mux_data = audio->mux_data; + hb_list_add( list, track ); + } + + while( !*job->die && !job->done ) + { + if( !( track = GetTrack( list ) ) ) + { + hb_snooze( 50 ); + continue; + } + + buf = hb_fifo_get( track->fifo ); + if( job->pass != 1 ) + { + m->mux( m, track->mux_data, buf ); + track->frames += 1; + track->bytes += buf->size; + mux->pts = buf->stop; + } + hb_buffer_close( &buf ); + } + + if( job->pass != 1 ) + { + struct stat sb; + uint64_t bytes_total, frames_total; + + m->end( m ); + + if( !stat( job->file, &sb ) ) + { + hb_log( "mux: file size, %lld bytes", (uint64_t) sb.st_size ); + + bytes_total = 0; + frames_total = 0; + for( i = 0; i < hb_list_count( list ); i++ ) + { + track = hb_list_item( list, i ); + hb_log( "mux: track %d, %lld bytes, %.2f kbps", + i, track->bytes, + 90000.0 * track->bytes / mux->pts / 125 ); + if( !i && ( job->vquality < 0.0 || job->vquality > 1.0 ) ) + { + /* Video */ + hb_log( "mux: video bitrate error, %+lld bytes", + track->bytes - mux->pts * job->vbitrate * + 125 / 90000 ); + } + bytes_total += track->bytes; + frames_total += track->frames; + } + + if( bytes_total && frames_total ) + { + hb_log( "mux: overhead, %.2f bytes per frame", + (float) ( sb.st_size - bytes_total ) / + frames_total ); + } + } + } + + free( m ); + + for( i = 0; i < hb_list_count( list ); i++ ) + { + track = hb_list_item( list, i ); + if( track->mux_data ) + { + free( track->mux_data ); + } + free( track ); + } + hb_list_close( &list ); + + free( mux ); +} + +hb_thread_t * hb_muxer_init( hb_job_t * job ) +{ + hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 ); + mux->job = job; + return hb_thread_init( "muxer", MuxerFunc, mux, + HB_NORMAL_PRIORITY ); +} diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c new file mode 100644 index 000000000..a02a05232 --- /dev/null +++ b/libhb/muxmp4.c @@ -0,0 +1,160 @@ +/* $Id: muxmp4.c,v 1.24 2005/11/04 13:09:41 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +/* libmp4v2 header */ +#include "mp4.h" + +#include "hb.h" + +struct hb_mux_object_s +{ + HB_MUX_COMMON; + + hb_job_t * job; + + /* libmp4v2 handle */ + MP4FileHandle file; + + /* Cumulated durations so far, in timescale units (see MP4Mux) */ + uint64_t sum_dur; +}; + +struct hb_mux_data_s +{ + MP4TrackId track; +}; + +/********************************************************************** + * MP4Init + ********************************************************************** + * Allocates hb_mux_data_t structures, create file and write headers + *********************************************************************/ +static int MP4Init( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + hb_title_t * title = job->title; + + hb_audio_t * audio; + hb_mux_data_t * mux_data; + int i; + + /* Create an empty mp4 file */ + m->file = MP4Create( job->file, MP4_DETAILS_ERROR, 0 ); + + /* Video track */ + mux_data = malloc( sizeof( hb_mux_data_t ) ); + job->mux_data = mux_data; + + /* When using the standard 90000 timescale, QuickTime tends to have + synchronization issues (audio not playing at the correct speed). + To workaround this, we use the audio samplerate as the + timescale */ + MP4SetTimeScale( m->file, job->arate ); + + if( job->vcodec == HB_VCODEC_X264 ) + { +#define c job->config.h264 + /* Stolen from mp4creator */ + MP4SetVideoProfileLevel( m->file, 0x7F ); + + mux_data->track = MP4AddH264VideoTrack( m->file, job->arate, + MP4_INVALID_DURATION, job->width, job->height, + c.sps[1], /* AVCProfileIndication */ + c.sps[2], /* profile_compat */ + c.sps[3], /* AVCLevelIndication */ + 3 ); /* 4 bytes length before each NAL unit */ + + MP4AddH264SequenceParameterSet( m->file, mux_data->track, + c.sps, c.sps_length ); + MP4AddH264PictureParameterSet( m->file, mux_data->track, + c.pps, c.pps_length ); +#undef c + } + else /* FFmpeg or XviD */ + { +#define c job->config.mpeg4 + MP4SetVideoProfileLevel( m->file, MPEG4_SP_L3 ); + mux_data->track = MP4AddVideoTrack( m->file, job->arate, + MP4_INVALID_DURATION, job->width, job->height, + MP4_MPEG4_VIDEO_TYPE ); + + /* VOL from FFmpeg or XviD */ + MP4SetTrackESConfiguration( m->file, mux_data->track, + c.config, c.config_length ); +#undef c + } + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + mux_data = malloc( sizeof( hb_mux_data_t ) ); + audio->mux_data = mux_data; + + mux_data->track = MP4AddAudioTrack( m->file, + job->arate, 1024, MP4_MPEG4_AUDIO_TYPE ); + MP4SetAudioProfileLevel( m->file, 0x0F ); + MP4SetTrackESConfiguration( m->file, mux_data->track, + audio->config.faac.decinfo, audio->config.faac.size ); + } + + return 0; +} + +static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, + hb_buffer_t * buf ) +{ + hb_job_t * job = m->job; + + uint64_t duration; + + if( mux_data == job->mux_data ) + { + /* Video */ + /* Because we use the audio samplerate as the timescale, + we have to use potentially variable durations so the video + doesn't go out of sync */ + duration = ( buf->stop * job->arate / 90000 ) - m->sum_dur; + m->sum_dur += duration; + } + else + { + /* Audio */ + duration = MP4_INVALID_DURATION; + } + + MP4WriteSample( m->file, mux_data->track, buf->data, buf->size, + duration, 0, buf->key ); + return 0; +} + +static int MP4End( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + char filename[1024]; memset( filename, 0, 1024 ); + + MP4Close( m->file ); + +#if 0 + hb_log( "muxmp4: optimizing file" ); + snprintf( filename, 1024, "%s.tmp", job->file ); + MP4Optimize( job->file, filename, MP4_DETAILS_ERROR ); + remove( job->file ); + rename( filename, job->file ); +#endif + + return 0; +} + +hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job ) +{ + hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 ); + m->init = MP4Init; + m->mux = MP4Mux; + m->end = MP4End; + m->job = job; + return m; +} + diff --git a/libhb/muxogm.c b/libhb/muxogm.c new file mode 100644 index 000000000..d326c9828 --- /dev/null +++ b/libhb/muxogm.c @@ -0,0 +1,364 @@ +/* $Id: muxogm.c,v 1.4 2005/02/20 00:41:56 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include <ogg/ogg.h> + +struct hb_mux_object_s +{ + HB_MUX_COMMON; + + hb_job_t * job; + + FILE * file; +}; + +struct hb_mux_data_s +{ + int codec; + ogg_stream_state os; + int i_packet_no; +}; + +typedef struct __attribute__((__packed__)) +{ + uint8_t i_packet_type; + + char stream_type[8]; + char sub_type[4]; + + int32_t i_size; + + int64_t i_time_unit; + int64_t i_samples_per_unit; + int32_t i_default_len; + + int32_t i_buffer_size; + int16_t i_bits_per_sample; + int16_t i_padding_0; // hum hum + union + { + struct + { + int32_t i_width; + int32_t i_height; + + } video; + struct + { + int16_t i_channels; + int16_t i_block_align; + int32_t i_avgbytespersec; + } audio; + } header; + +} ogg_stream_header_t; + +#define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v) +static void _SetWLE( uint8_t *p, uint16_t i_dw ) +{ + p[1] = ( i_dw >> 8 )&0xff; + p[0] = ( i_dw )&0xff; +} + +#define SetDWLE( p, v ) _SetDWLE( (uint8_t*)p, v) +static void _SetDWLE( uint8_t *p, uint32_t i_dw ) +{ + p[3] = ( i_dw >> 24 )&0xff; + p[2] = ( i_dw >> 16 )&0xff; + p[1] = ( i_dw >> 8 )&0xff; + p[0] = ( i_dw )&0xff; +} +#define SetQWLE( p, v ) _SetQWLE( (uint8_t*)p, v) +static void _SetQWLE( uint8_t *p, uint64_t i_qw ) +{ + SetDWLE( p, i_qw&0xffffffff ); + SetDWLE( p+4, ( i_qw >> 32)&0xffffffff ); +} + +static int OGMFlush( hb_mux_object_t * m, hb_mux_data_t * mux_data ) +{ + for( ;; ) + { + ogg_page og; + if( ogg_stream_flush( &mux_data->os, &og ) == 0 ) + { + break; + } + if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || + fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) + { + return -1; + } + } + return 0; +} + +/********************************************************************** + * OGMInit + ********************************************************************** + * Allocates hb_mux_data_t structures, create file and write headers + *********************************************************************/ +static int OGMInit( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + hb_title_t * title = job->title; + + hb_audio_t * audio; + hb_mux_data_t * mux_data; + int i; + + ogg_packet op; + ogg_stream_header_t h; + + /* Open output file */ + if( ( m->file = fopen( job->file, "wb" ) ) == NULL ) + { + hb_log( "muxogm: failed to open `%s'", job->file ); + return -1; + } + hb_log( "muxogm: `%s' opened", job->file ); + + /* Video track */ + mux_data = malloc( sizeof( hb_mux_data_t ) ); + mux_data->codec = job->vcodec; + mux_data->i_packet_no = 0; + job->mux_data = mux_data; + ogg_stream_init( &mux_data->os, 0 ); + + /* Audio */ + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + mux_data = malloc( sizeof( hb_mux_data_t ) ); + mux_data->codec = job->acodec; + mux_data->i_packet_no = 0; + audio->mux_data = mux_data; + ogg_stream_init( &mux_data->os, i + 1 ); + } + + + /* First pass: all b_o_s packets */ + + /* Video */ + mux_data = job->mux_data; + memset( &h, 0, sizeof( ogg_stream_header_t ) ); + h.i_packet_type = 0x01; + memcpy( h.stream_type, "video ", 8 ); + if( mux_data->codec == HB_VCODEC_X264 ) + { + memcpy( h.sub_type, "H264", 4 ); + } + else if( mux_data->codec == HB_VCODEC_XVID ) + { + memcpy( h.sub_type, "XVID", 4 ); + } + else + { + memcpy( h.sub_type, "DX50", 4 ); + } + SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); + SetQWLE( &h.i_time_unit, (int64_t) 10 * 1000 * 1000 * + (int64_t) job->vrate_base / (int64_t) job->vrate ); + SetQWLE( &h.i_samples_per_unit, 1 ); + SetDWLE( &h.i_default_len, 0 ); + SetDWLE( &h.i_buffer_size, 1024*1024 ); + SetWLE ( &h.i_bits_per_sample, 0 ); + SetDWLE( &h.header.video.i_width, job->width ); + SetDWLE( &h.header.video.i_height, job->height ); + op.packet = (char*)&h; + op.bytes = sizeof( ogg_stream_header_t ); + op.b_o_s = 1; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = mux_data->i_packet_no++; + ogg_stream_packetin( &mux_data->os, &op ); + OGMFlush( m, mux_data ); + + /* Audio */ + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + mux_data = audio->mux_data; + memset( &h, 0, sizeof( ogg_stream_header_t ) ); + switch( job->acodec ) + { + case HB_ACODEC_LAME: + { + h.i_packet_type = 0x01; + memcpy( h.stream_type, "audio ", 8 ); + memcpy( h.sub_type, "55 ", 4 ); + + SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); + SetQWLE( &h.i_time_unit, 0 ); + SetQWLE( &h.i_samples_per_unit, job->arate ); + SetDWLE( &h.i_default_len, 1 ); + SetDWLE( &h.i_buffer_size, 30 * 1024 ); + SetWLE ( &h.i_bits_per_sample, 0 ); + + SetDWLE( &h.header.audio.i_channels, 2 ); + SetDWLE( &h.header.audio.i_block_align, 0 ); + SetDWLE( &h.header.audio.i_avgbytespersec, + job->abitrate / 8 ); + + op.packet = (char*) &h; + op.bytes = sizeof( ogg_stream_header_t ); + op.b_o_s = 1; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = mux_data->i_packet_no++; + ogg_stream_packetin( &mux_data->os, &op ); + break; + } + case HB_ACODEC_VORBIS: + { + memcpy( &op, audio->config.vorbis.headers[0], + sizeof( ogg_packet ) ); + op.packet = audio->config.vorbis.headers[0] + + sizeof( ogg_packet ); + ogg_stream_packetin( &mux_data->os, &op ); + break; + } + default: + hb_log( "muxogm: unhandled codec" ); + break; + } + OGMFlush( m, mux_data ); + } + + /* second pass: all non b_o_s packets */ + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( job->acodec == HB_ACODEC_VORBIS ) + { + int j; + mux_data = audio->mux_data; + + for( j = 1; j < 3; j++ ) + { + memcpy( &op, audio->config.vorbis.headers[j], + sizeof( ogg_packet ) ); + op.packet = audio->config.vorbis.headers[j] + + sizeof( ogg_packet ); + ogg_stream_packetin( &mux_data->os, &op ); + + OGMFlush( m, mux_data ); + } + } + } + hb_log( "muxogm: headers written" ); + + return 0; +} + +static int OGMMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, + hb_buffer_t * buf ) +{ + ogg_packet op; + + switch( mux_data->codec ) + { + case HB_VCODEC_FFMPEG: + case HB_VCODEC_XVID: + case HB_VCODEC_X264: + op.bytes = buf->size + 1; + op.packet = malloc( op.bytes ); + op.packet[0] = buf->key ? 0x08 : 0x00; + memcpy( &op.packet[1], buf->data, buf->size ); + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = mux_data->i_packet_no; + op.packetno = mux_data->i_packet_no++; + break; + case HB_ACODEC_LAME: + op.bytes = buf->size + 1; + op.packet = malloc( op.bytes ); + op.packet[0] = 0x08; + memcpy( &op.packet[1], buf->data, buf->size ); + op.b_o_s = 0; + op.e_o_s = 0; + op.granulepos = mux_data->i_packet_no * 1152; + op.packetno = mux_data->i_packet_no++; + break; + case HB_ACODEC_VORBIS: + memcpy( &op, buf->data, sizeof( ogg_packet ) ); + op.packet = malloc( op.bytes ); + memcpy( op.packet, buf->data + sizeof( ogg_packet ), op.bytes ); + break; + + default: + hb_log( "muxogm: unhandled codec" ); + op.bytes = 0; + op.packet = NULL; + break; + } + + if( op.packet ) + { + ogg_stream_packetin( &mux_data->os, &op ); + + for( ;; ) + { + ogg_page og; + if( ogg_stream_pageout( &mux_data->os, &og ) == 0 ) + { + break; + } + + if( fwrite( og.header, og.header_len, 1, m->file ) <= 0 || + fwrite( og.body, og.body_len, 1, m->file ) <= 0 ) + { + hb_log( "muxogm: write failed" ); + break; + } + } + free( op.packet ); + } + return 0; +} + +static int OGMEnd( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + + hb_title_t * title = job->title; + hb_audio_t * audio; + hb_mux_data_t * mux_data; + int i; + + mux_data = job->mux_data; + if( OGMFlush( m, mux_data ) < 0 ) + { + return -1; + } + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + mux_data = audio->mux_data; + if( OGMFlush( m, mux_data ) < 0 ) + { + return -1; + } + } + + fclose( m->file ); + hb_log( "muxogm: `%s' closed", job->file ); + + return 0; +} + +hb_mux_object_t * hb_mux_ogm_init( hb_job_t * job ) +{ + hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 ); + m->init = OGMInit; + m->mux = OGMMux; + m->end = OGMEnd; + m->job = job; + return m; +} + diff --git a/libhb/ports.c b/libhb/ports.c new file mode 100644 index 000000000..20c2cae94 --- /dev/null +++ b/libhb/ports.c @@ -0,0 +1,593 @@ +/* $Id: ports.c,v 1.15 2005/10/15 18:05:03 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include <time.h> +#include <sys/time.h> + +#if defined( SYS_BEOS ) +#include <OS.h> +#include <signal.h> +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) +#include <pthread.h> +#elif defined( SYS_CYGWIN ) +#include <windows.h> +#endif + +#ifdef SYS_CYGWIN +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#endif + +#include "hb.h" + +/************************************************************************ + * hb_get_date() + ************************************************************************ + * Returns the current date in milliseconds. + * On Win32, we implement a gettimeofday emulation here because + * libdvdread and libmp4v2 use it without checking. + ************************************************************************/ +#ifdef SYS_CYGWIN +struct timezone +{ +}; + +int gettimeofday( struct timeval * tv, struct timezone * tz ) +{ + int tick; + tick = GetTickCount(); + tv->tv_sec = tick / 1000; + tv->tv_usec = ( tick % 1000 ) * 1000; + return 0; +} +#endif + +uint64_t hb_get_date() +{ + struct timeval tv; + gettimeofday( &tv, NULL ); + return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 ); +} + +/************************************************************************ + * hb_snooze() + ************************************************************************ + * Waits <delay> milliseconds. + ************************************************************************/ +void hb_snooze( int delay ) +{ + if( delay < 1 ) + { + return; + } +#if defined( SYS_BEOS ) + snooze( 1000 * delay ); +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + usleep( 1000 * delay ); +#elif defined( SYS_CYGWIN ) + Sleep( delay ); +#endif +} + +/************************************************************************ + * hb_get_cpu_count() + ************************************************************************ + * Whenever possible, returns the number of CPUs on the current + * computer. Returns 1 otherwise. + * The detection is actually only performed on the first call. + ************************************************************************/ +int hb_get_cpu_count() +{ + static int cpu_count = 0; + + if( cpu_count ) + { + return cpu_count; + } + cpu_count = 1; + +#if defined( SYS_BEOS ) + { + system_info info; + get_system_info( &info ); + cpu_count = info.cpu_count; + } + +#elif defined( SYS_DARWIN ) || defined( SYS_FREEBSD ) + FILE * info; + char buffer[16]; + + if( ( info = popen( "/usr/sbin/sysctl hw.ncpu", "r" ) ) ) + { + memset( buffer, 0, 16 ); + if( fgets( buffer, 15, info ) ) + { + if( sscanf( buffer, "hw.ncpu: %d", &cpu_count ) != 1 ) + { + cpu_count = 1; + } + } + fclose( info ); + } + +#elif defined( SYS_LINUX ) + { + FILE * info; + char buffer[8]; + + if( ( info = popen( "grep -c '^processor' /proc/cpuinfo", + "r" ) ) ) + { + memset( buffer, 0, 8 ); + if( fgets( buffer, 7, info ) ) + { + if( sscanf( buffer, "%d", &cpu_count ) != 1 ) + { + cpu_count = 1; + } + } + fclose( info ); + } + } + +#elif defined( SYS_CYGWIN ) + SYSTEM_INFO cpuinfo; + GetSystemInfo( &cpuinfo ); + cpu_count = cpuinfo.dwNumberOfProcessors; +#endif + + cpu_count = MAX( 1, cpu_count ); + cpu_count = MIN( cpu_count, 8 ); + + return cpu_count; +} + +/************************************************************************ + * Get a tempory directory for HB + ***********************************************************************/ +void hb_get_tempory_directory( hb_handle_t * h, char path[512] ) +{ + char base[512]; + + /* Create the base */ +#ifdef SYS_CYGWIN + char *p; + int i_size = GetTempPath( 512, base ); + if( i_size <= 0 || i_size >= 512 ) + { + if( getcwd( base, 512 ) == NULL ) + strcpy( base, "c:" ); /* Bad fallback but ... */ + } + + /* c:/path/ works like a charm under cygwin(win32?) so use it */ + while( ( p = strchr( base, '\\' ) ) ) + *p = '/'; +#else + strcpy( base, "/tmp" ); +#endif + /* I prefer to remove evntual last '/' (for cygwin) */ + if( base[strlen(base)-1] == '/' ) + base[strlen(base)-1] = '\0'; + + snprintf( path, 512, "%s/hb.%d", base, hb_get_pid( h ) ); +} + +/************************************************************************ + * Get a tempory filename for HB + ***********************************************************************/ +void hb_get_tempory_filename( hb_handle_t * h, char name[1024], + char *fmt, ... ) +{ + va_list args; + + hb_get_tempory_directory( h, name ); + strcat( name, "/" ); + + va_start( args, fmt ); + vsnprintf( &name[strlen(name)], 1024 - strlen(name), fmt, args ); + va_end( args ); +} + +/************************************************************************ + * hb_mkdir + ************************************************************************ + * Wrapper to the real mkdir, needed only because it doesn't take a + * second argument on Win32. Grrr. + ***********************************************************************/ +void hb_mkdir( char * name ) +{ +#ifdef SYS_CYGWIN + mkdir( name ); +#else + mkdir( name, 0755 ); +#endif +} + +/************************************************************************ + * Portable thread implementation + ***********************************************************************/ +struct hb_thread_s +{ + char * name; + int priority; + void (* function) ( void * ); + void * arg; + + hb_lock_t * lock; + int exited; + +#if defined( SYS_BEOS ) + thread_id thread; +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_t thread; +#elif defined( SYS_CYGWIN ) + HANDLE thread; +#endif +}; + +/************************************************************************ + * hb_thread_func() + ************************************************************************ + * We use it as the root routine for any thread, for two reasons: + * + To set the thread priority on OS X (pthread_setschedparam() could + * be called from hb_thread_init(), but it's nicer to do it as we + * are sure it is done before the real routine starts) + * + Get informed when the thread exits, so we know whether + * hb_thread_close() will block or not. + ***********************************************************************/ +static void hb_thread_func( void * _t ) +{ + hb_thread_t * t = (hb_thread_t *) _t; + +#if defined( SYS_DARWIN ) + /* Set the thread priority */ + struct sched_param param; + memset( ¶m, 0, sizeof( struct sched_param ) ); + param.sched_priority = t->priority; + pthread_setschedparam( pthread_self(), SCHED_OTHER, ¶m ); +#endif + +#if defined( SYS_BEOS ) + signal( SIGINT, SIG_IGN ); +#endif + + /* Start the actual routine */ + t->function( t->arg ); + + /* Inform that the thread can be joined now */ + hb_log( "thread %d exited (\"%s\")", t->thread, t->name ); + hb_lock( t->lock ); + t->exited = 1; + hb_unlock( t->lock ); +} + +/************************************************************************ + * hb_thread_init() + ************************************************************************ + * name: user-friendly name + * function: the thread routine + * arg: argument of the routine + * priority: HB_LOW_PRIORITY or HB_NORMAL_PRIORITY + ***********************************************************************/ +hb_thread_t * hb_thread_init( char * name, void (* function)(void *), + void * arg, int priority ) +{ + hb_thread_t * t = calloc( sizeof( hb_thread_t ), 1 ); + + t->name = strdup( name ); + t->function = function; + t->arg = arg; + t->priority = priority; + + t->lock = hb_lock_init(); + + /* Create and start the thread */ +#if defined( SYS_BEOS ) + t->thread = spawn_thread( (thread_func) hb_thread_func, + name, priority, t ); + resume_thread( t->thread ); + +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_create( &t->thread, NULL, + (void * (*)( void * )) hb_thread_func, t ); + +#elif defined( SYS_CYGWIN ) + t->thread = CreateThread( NULL, 0, + (LPTHREAD_START_ROUTINE) hb_thread_func, t, 0, NULL ); + + /* Maybe use THREAD_PRIORITY_LOWEST instead */ + if( priority == HB_LOW_PRIORITY ) + SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL ); +#endif + + hb_log( "thread %d started (\"%s\")", t->thread, t->name ); + return t; +} + +/************************************************************************ + * hb_thread_close() + ************************************************************************ + * Joins the thread and frees memory. + ***********************************************************************/ +void hb_thread_close( hb_thread_t ** _t ) +{ + hb_thread_t * t = *_t; + + /* Join the thread */ +#if defined( SYS_BEOS ) + long exit_value; + wait_for_thread( t->thread, &exit_value ); + +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_join( t->thread, NULL ); + +#elif defined( SYS_CYGWIN ) + WaitForSingleObject( t->thread, INFINITE ); +#endif + + hb_log( "thread %d joined (\"%s\")", + t->thread, t->name ); + + hb_lock_close( &t->lock ); + free( t->name ); + free( t ); + *_t = NULL; +} + +/************************************************************************ + * hb_thread_has_exited() + ************************************************************************ + * Returns 1 if the thread can be joined right away, 0 otherwise. + ***********************************************************************/ +int hb_thread_has_exited( hb_thread_t * t ) +{ + int exited; + + hb_lock( t->lock ); + exited = t->exited; + hb_unlock( t->lock ); + + return exited; +} + +/************************************************************************ + * Portable mutex implementation + ***********************************************************************/ +struct hb_lock_s +{ +#if defined( SYS_BEOS ) + sem_id sem; +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_mutex_t mutex; +#elif defined( SYS_CYGWIN ) + HANDLE mutex; +#endif +}; + +/************************************************************************ + * hb_lock_init() + * hb_lock_close() + * hb_lock() + * hb_unlock() + ************************************************************************ + * Basic wrappers to OS-specific semaphore or mutex functions. + ***********************************************************************/ +hb_lock_t * hb_lock_init() +{ + hb_lock_t * l = calloc( sizeof( hb_lock_t ), 1 ); + +#if defined( SYS_BEOS ) + l->sem = create_sem( 1, "sem" ); +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_mutex_init( &l->mutex, NULL ); +#elif defined( SYS_CYGWIN ) + l->mutex = CreateMutex( 0, FALSE, 0 ); +#endif + + return l; +} + +void hb_lock_close( hb_lock_t ** _l ) +{ + hb_lock_t * l = *_l; + +#if defined( SYS_BEOS ) + delete_sem( l->sem ); +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_mutex_destroy( &l->mutex ); +#elif defined( SYS_CYGWIN ) + CloseHandle( l->mutex ); +#endif + free( l ); + + *_l = NULL; +} + +void hb_lock( hb_lock_t * l ) +{ +#if defined( SYS_BEOS ) + acquire_sem( l->sem ); +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_mutex_lock( &l->mutex ); +#elif defined( SYS_CYGWIN ) + WaitForSingleObject( l->mutex, INFINITE ); +#endif +} + +void hb_unlock( hb_lock_t * l ) +{ +#if defined( SYS_BEOS ) + release_sem( l->sem ); +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_mutex_unlock( &l->mutex ); +#elif defined( SYS_CYGWIN ) + ReleaseMutex( l->mutex ); +#endif +} + +/************************************************************************ + * Portable condition variable implementation + ***********************************************************************/ +struct hb_cond_s +{ +#if defined( SYS_BEOS ) + int thread; +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_cond_t cond; +#elif defined( SYS_CYGWIN ) + HANDLE event; +#endif +}; + +/************************************************************************ + * hb_cond_init() + * hb_cond_close() + * hb_cond_wait() + * hb_cond_signal() + ************************************************************************ + * Win9x is not supported by this implementation (SignalObjectAndWait() + * only available on Windows 2000/XP). + ***********************************************************************/ +hb_cond_t * hb_cond_init() +{ + hb_cond_t * c = calloc( sizeof( hb_cond_t ), 1 ); + +#if defined( SYS_BEOS ) + c->thread = -1; +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_cond_init( &c->cond, NULL ); +#elif defined( SYS_CYGWIN ) + c->event = CreateEvent( NULL, FALSE, FALSE, NULL ); +#endif + + return c; +} + +void hb_cond_close( hb_cond_t ** _c ) +{ + hb_cond_t * c = *_c; + +#if defined( SYS_BEOS ) +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_cond_destroy( &c->cond ); +#elif defined( SYS_CYGWIN ) + CloseHandle( c->event ); +#endif + free( c ); + + *_c = NULL; +} + +void hb_cond_wait( hb_cond_t * c, hb_lock_t * lock ) +{ +#if defined( SYS_BEOS ) + c->thread = find_thread( NULL ); + release_sem( lock->sem ); + suspend_thread( c->thread ); + acquire_sem( lock->sem ); + c->thread = -1; +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_cond_wait( &c->cond, &lock->mutex ); +#elif defined( SYS_CYGWIN ) + SignalObjectAndWait( lock->mutex, c->event, INFINITE, FALSE ); + WaitForSingleObject( lock->mutex, INFINITE ); +#endif +} + +void hb_cond_signal( hb_cond_t * c ) +{ +#if defined( SYS_BEOS ) + while( c->thread != -1 ) + { + thread_info info; + get_thread_info( c->thread, &info ); + if( info.state == B_THREAD_SUSPENDED ) + { + resume_thread( c->thread ); + break; + } + /* Looks like we have been called between hb_cond_wait's + release_sem() and suspend_thread() lines. Wait until the + thread is actually suspended before we resume it */ + snooze( 5000 ); + } +#elif defined( SYS_DARWIN ) || defined( SYS_LINUX ) || defined( SYS_FREEBSD ) + pthread_cond_signal( &c->cond ); +#elif defined( SYS_CYGWIN ) + PulseEvent( c->event ); +#endif +} + +/************************************************************************ + * Network + ***********************************************************************/ + +struct hb_net_s +{ + int socket; +}; + +hb_net_t * hb_net_open( char * address, int port ) +{ + hb_net_t * n = calloc( sizeof( hb_net_t ), 1 ); + + struct sockaddr_in sock; + struct hostent * host; + + /* TODO: find out why this doesn't work on Win32 */ + if( !( host = gethostbyname( address ) ) ) + { + hb_log( "gethostbyname failed (%s)", address ); + free( n ); + return NULL; + } + + memset( &sock, 0, sizeof( struct sockaddr_in ) ); + sock.sin_family = host->h_addrtype; + sock.sin_port = htons( port ); + memcpy( &sock.sin_addr, host->h_addr, host->h_length ); + + if( ( n->socket = socket( host->h_addrtype, SOCK_STREAM, 0 ) ) < 0 ) + { + hb_log( "socket failed" ); + free( n ); + return NULL; + } + + if( connect( n->socket, (struct sockaddr *) &sock, + sizeof( struct sockaddr_in ) ) < 0 ) + { + hb_log( "connect failed" ); + free( n ); + return NULL; + } + + return n; +} + +int hb_net_send( hb_net_t * n, char * buffer ) +{ + return send( n->socket, buffer, strlen( buffer ), 0 ); +} + +int hb_net_recv( hb_net_t * n, char * buffer, int size ) +{ + return recv( n->socket, buffer, size - 1, 0 ); +} + +void hb_net_close( hb_net_t ** _n ) +{ + hb_net_t * n = (hb_net_t *) *_n; + close( n->socket ); + free( n ); + *_n = NULL; +} + diff --git a/libhb/ports.h b/libhb/ports.h new file mode 100644 index 000000000..4639c6b93 --- /dev/null +++ b/libhb/ports.h @@ -0,0 +1,86 @@ +/* $Id: ports.h,v 1.7 2005/10/15 18:05:03 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#ifndef HB_PORTS_H +#define HB_PORTS_H + +/************************************************************************ + * Utils + ***********************************************************************/ +uint64_t hb_get_date(); +void hb_snooze( int delay ); +int hb_get_cpu_count(); + +#ifdef __LIBHB__ + +/* Everything from now is only used internally and hidden to the UI */ + +/************************************************************************ + * Files utils + ***********************************************************************/ +void hb_get_tempory_directory( hb_handle_t * h, char path[512] ); +void hb_get_tempory_filename( hb_handle_t *, char name[1024], + char * fmt, ... ); +void hb_mkdir( char * name ); + +/************************************************************************ + * Threads + ***********************************************************************/ +typedef struct hb_thread_s hb_thread_t; + +#if defined( SYS_BEOS ) +# define HB_LOW_PRIORITY 5 +# define HB_NORMAL_PRIORITY 10 +#elif defined( SYS_DARWIN ) +# define HB_LOW_PRIORITY 0 +# define HB_NORMAL_PRIORITY 31 +#elif defined( SYS_LINUX ) || defined( SYS_FREEBSD ) +# define HB_LOW_PRIORITY 0 +# define HB_NORMAL_PRIORITY 0 +#elif defined( SYS_CYGWIN ) +# define HB_LOW_PRIORITY 0 +# define HB_NORMAL_PRIORITY 1 +#endif + +hb_thread_t * hb_thread_init( char * name, void (* function)(void *), + void * arg, int priority ); +void hb_thread_close( hb_thread_t ** ); +int hb_thread_has_exited( hb_thread_t * ); + +/************************************************************************ + * Mutexes + ***********************************************************************/ +typedef struct hb_lock_s hb_lock_t; + +hb_lock_t * hb_lock_init(); +void hb_lock_close( hb_lock_t ** ); +void hb_lock( hb_lock_t * ); +void hb_unlock( hb_lock_t * ); + +/************************************************************************ + * Condition variables + ***********************************************************************/ +typedef struct hb_cond_s hb_cond_t; + +hb_cond_t * hb_cond_init(); +void hb_cond_wait( hb_cond_t *, hb_lock_t * ); +void hb_cond_signal( hb_cond_t * ); +void hb_cond_close( hb_cond_t ** ); + +/************************************************************************ + * Network + ***********************************************************************/ +typedef struct hb_net_s hb_net_t; + +hb_net_t * hb_net_open( char * address, int port ); +int hb_net_send( hb_net_t *, char * ); +int hb_net_recv( hb_net_t *, char *, int ); +void hb_net_close( hb_net_t ** ); + +#endif /* __LIBHB__ */ + +#endif + diff --git a/libhb/reader.c b/libhb/reader.c new file mode 100644 index 000000000..e57467d8d --- /dev/null +++ b/libhb/reader.c @@ -0,0 +1,155 @@ +/* $Id: reader.c,v 1.20 2005/04/29 19:55:54 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +typedef struct +{ + hb_job_t * job; + hb_title_t * title; + volatile int * die; + + hb_dvd_t * dvd; + hb_buffer_t * ps; + +} hb_reader_t; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void ReaderFunc( void * ); +static hb_fifo_t * GetFifoForId( hb_job_t * job, int id ); + +/*********************************************************************** + * hb_reader_init + *********************************************************************** + * + **********************************************************************/ +hb_thread_t * hb_reader_init( hb_job_t * job ) +{ + hb_reader_t * r; + + r = calloc( sizeof( hb_reader_t ), 1 ); + + r->job = job; + r->title = job->title; + r->die = job->die; + + return hb_thread_init( "reader", ReaderFunc, r, + HB_NORMAL_PRIORITY ); +} + +/*********************************************************************** + * ReaderFunc + *********************************************************************** + * + **********************************************************************/ +static void ReaderFunc( void * _r ) +{ + hb_reader_t * r = _r; + hb_fifo_t * fifo; + hb_buffer_t * buf; + hb_list_t * list; + int chapter; + + if( !( r->dvd = hb_dvd_init( r->title->dvd ) ) ) + { + return; + } + + if( !hb_dvd_start( r->dvd, r->title->index, r->job->chapter_start ) ) + { + hb_dvd_close( &r->dvd ); + return; + } + + list = hb_list_init(); + r->ps = hb_buffer_init( 2048 ); + + while( !*r->die && !r->job->done ) + { + chapter = hb_dvd_chapter( r->dvd ); + if( chapter < 0 ) + { + hb_log( "reader: end of the title reached" ); + break; + } + if( chapter > r->job->chapter_end ) + { + hb_log( "reader: end of chapter %d reached (%d)", + r->job->chapter_end, chapter ); + break; + } + + if( !hb_dvd_read( r->dvd, r->ps ) ) + { + break; + } + + hb_demux_ps( r->ps, list ); + + while( ( buf = hb_list_item( list, 0 ) ) ) + { + hb_list_rem( list, buf ); + fifo = GetFifoForId( r->job, buf->id ); + if( fifo ) + { + while( !*r->die && !r->job->done && + hb_fifo_is_full( fifo ) ) + { + hb_snooze( 50 ); + } + hb_fifo_push( fifo, buf ); + } + else + { + hb_buffer_close( &buf ); + } + } + } + + hb_list_empty( &list ); + hb_buffer_close( &r->ps ); + hb_dvd_close( &r->dvd ); + + hb_log( "reader: done" ); +} + +/*********************************************************************** + * GetFifoForId + *********************************************************************** + * + **********************************************************************/ +static hb_fifo_t * GetFifoForId( hb_job_t * job, int id ) +{ + hb_title_t * title = job->title; + hb_audio_t * audio; + hb_subtitle_t * subtitle; + int i; + + if( id == 0xE0 ) + { + return job->fifo_mpeg2; + } + + if( ( subtitle = hb_list_item( title->list_subtitle, 0 ) ) && + id == subtitle->id ) + { + return subtitle->fifo_in; + } + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( id == audio->id ) + { + return audio->fifo_in; + } + } + + return NULL; +} + diff --git a/libhb/render.c b/libhb/render.c new file mode 100644 index 000000000..914fa3995 --- /dev/null +++ b/libhb/render.c @@ -0,0 +1,167 @@ +/* $Id: render.c,v 1.17 2005/04/14 17:37:54 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "ffmpeg/avcodec.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + + ImgReSampleContext * context; + AVPicture pic_raw; + AVPicture pic_deint; + AVPicture pic_render; + hb_buffer_t * buf_deint; +}; + +static void ApplySub( hb_job_t * job, hb_buffer_t * buf, + hb_buffer_t ** _sub ) +{ + hb_buffer_t * sub = *_sub; + hb_title_t * title = job->title; + int i, j, offset_top, offset_left; + uint8_t * lum, * alpha, * out; + + if( !sub ) + { + return; + } + + if( sub->width > title->width - job->crop[0] - job->crop[1] - 40 || + sub->height > title->height - job->crop[2] - job->crop[3] - 40 ) + { + /* The subtitle won't fit */ + hb_buffer_close( _sub ); + return; + } + + /* If necessary, move the subtitle so it is 20 pixels far from each + border of the cropped picture */ + offset_top = sub->y; + offset_top = MAX( offset_top, job->crop[0] + 20 ); + offset_top = MIN( offset_top, + title->height - job->crop[1] - 20 - sub->height ); + offset_left = sub->x; + offset_left = MAX( offset_left, job->crop[2] + 20 ); + offset_left = MIN( offset_left, + title->width - job->crop[3] - 20 - sub->width ); + + lum = sub->data; + alpha = lum + sub->width * sub->height; + out = buf->data + offset_top * title->width + offset_left; + + for( i = 0; i < sub->height; i++ ) + { + for( j = 0; j < sub->width; j++ ) + { + out[j] = ( (uint16_t) out[j] * ( 16 - (uint16_t) alpha[j] ) + + (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4; + } + lum += sub->width; + alpha += sub->width; + out += title->width; + } + + hb_buffer_close( _sub ); +} + +static int Work( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_job_t * job = w->job; + hb_title_t * title = job->title; + hb_buffer_t * in = *buf_in, * buf; + + avpicture_fill( &w->pic_raw, in->data, PIX_FMT_YUV420P, + title->width, title->height ); + + buf = hb_buffer_init( 3 * job->width * job->height / 2 ); + buf->start = in->start; + buf->stop = in->stop; + + if( job->deinterlace && w->context ) + { + avpicture_fill( &w->pic_render, buf->data, PIX_FMT_YUV420P, + job->width, job->height ); + avpicture_deinterlace( &w->pic_deint, &w->pic_raw, + PIX_FMT_YUV420P, title->width, + title->height ); + ApplySub( job, w->buf_deint, &in->sub ); + img_resample( w->context, &w->pic_render, &w->pic_deint ); + } + else if( job->deinterlace ) + { + avpicture_fill( &w->pic_deint, buf->data, PIX_FMT_YUV420P, + job->width, job->height ); + avpicture_deinterlace( &w->pic_deint, &w->pic_raw, + PIX_FMT_YUV420P, title->width, + title->height ); + ApplySub( job, buf, &in->sub ); + } + else if( w->context ) + { + ApplySub( job, in, &in->sub ); + avpicture_fill( &w->pic_render, buf->data, PIX_FMT_YUV420P, + job->width, job->height ); + img_resample( w->context, &w->pic_render, &w->pic_raw ); + } + else + { + hb_buffer_close( &buf ); + ApplySub( job, in, &in->sub ); + buf = in; + *buf_in = NULL; + } + + (*buf_out) = buf; + + return HB_WORK_OK; +} + +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + free( w->name ); + free( w ); + *_w = NULL; +} + +hb_work_object_t * hb_work_render_init( hb_job_t * job ) +{ + hb_title_t * title; + + hb_work_object_t * w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "Renderer" ); + w->work = Work; + w->close = Close; + + title = job->title; + + w->job = job; + + if( job->crop[0] || job->crop[1] || job->crop[2] || job->crop[3] || + job->width != title->width || job->height != title->height ) + { + w->context = img_resample_full_init( + job->width, job->height, title->width, title->height, + job->crop[0], job->crop[1], job->crop[2], job->crop[3], + 0, 0, 0, 0 ); + } + + if( job->deinterlace ) + { + /* Allocate a constant buffer used for deinterlacing */ + w->buf_deint = hb_buffer_init( 3 * title->width * + title->height / 2 ); + avpicture_fill( &w->pic_deint, w->buf_deint->data, + PIX_FMT_YUV420P, title->width, title->height ); + } + return w; +} diff --git a/libhb/scan.c b/libhb/scan.c new file mode 100644 index 000000000..812e84026 --- /dev/null +++ b/libhb/scan.c @@ -0,0 +1,491 @@ +/* $Id: scan.c,v 1.51 2005/04/27 21:05:24 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" +#include "a52dec/a52.h" + +typedef struct +{ + hb_handle_t * h; + + char * path; + int title_index; + hb_list_t * list_title; + + hb_dvd_t * dvd; + +} hb_scan_t; + +static void ScanFunc( void * ); +static int DecodePreviews( hb_scan_t *, hb_title_t * title ); +static void LookForAC3( hb_title_t * title, hb_buffer_t * b ); +static int AllAC3OK( hb_title_t * title ); + +hb_thread_t * hb_scan_init( hb_handle_t * handle, const char * path, + int title_index, hb_list_t * list_title ) +{ + hb_scan_t * data = calloc( sizeof( hb_scan_t ), 1 ); + + data->h = handle; + data->path = strdup( path ); + data->title_index = title_index; + data->list_title = list_title; + + return hb_thread_init( "scan", ScanFunc, data, HB_NORMAL_PRIORITY ); +} + +static void ScanFunc( void * _data ) +{ + hb_scan_t * data = (hb_scan_t *) _data; + hb_title_t * title; + int i; + + /* Try to open the path as a DVD. If it fails, try as a file */ + hb_log( "scan: trying to open with libdvdread" ); + if( ( data->dvd = hb_dvd_init( data->path ) ) ) + { + hb_log( "scan: DVD has %d title(s)", + hb_dvd_title_count( data->dvd ) ); + if( data->title_index ) + { + /* Scan this title only */ + hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd, + data->title_index ) ); + } + else + { + /* Scan all titles */ + for( i = 0; i < hb_dvd_title_count( data->dvd ); i++ ) + { + hb_list_add( data->list_title, + hb_dvd_title_scan( data->dvd, i + 1 ) ); + } + } + } + else + { + /* Open as a VOB file */ + FILE * file; + hb_log( "scan: trying to open as VOB file" ); + file = fopen( data->path, "rb" ); + if( file ) + { + /* XXX */ + fclose( file ); + } + else + { + hb_log( "scan: fopen failed" ); + return; + } + } + + for( i = 0; i < hb_list_count( data->list_title ); ) + { + int j; + hb_state_t state; + hb_audio_t * audio; + hb_title_t * title_tmp = NULL; + + title = hb_list_item( data->list_title, i ); + + /* I've seen a DVD with strictly identical titles. Check this + here and ignore it if redundant */ + for( j = 0; j < i; j++ ) + { + title_tmp = hb_list_item( data->list_title, j ); + if( title->vts == title_tmp->vts && + title->block_start == title_tmp->block_start && + title->block_end == title_tmp->block_end && + title->block_count == title_tmp->block_count ) + { + break; + } + else + { + title_tmp = NULL; + } + } + if( title_tmp ) + { + hb_log( "scan: title %d is duplicate with title %d", + title->index, title_tmp->index ); + hb_list_rem( data->list_title, title ); + free( title ); + continue; + } + +#define p state.param.scanning + /* Update the UI */ + state.state = HB_STATE_SCANNING; + p.title_cur = title->index; + p.title_count = hb_dvd_title_count( data->dvd ); + hb_set_state( data->h, &state ); +#undef p + + /* Decode previews */ + if( !DecodePreviews( data, title ) ) + { + /* TODO: free things */ + hb_list_rem( data->list_title, title ); + continue; + } + + /* Make sure we found AC3 rates and bitrates */ + for( j = 0; j < hb_list_count( title->list_audio ); ) + { + audio = hb_list_item( title->list_audio, j ); + if( audio->codec == HB_ACODEC_AC3 && + !audio->bitrate ) + { + hb_list_rem( title->list_audio, audio ); + free( audio ); + continue; + } + j++; + } + + /* Do we still have audio */ + if( !hb_list_count( title->list_audio ) ) + { + hb_list_rem( data->list_title, title ); + free( title ); + continue; + } + + i++; + } + + /* Init jobs templates */ + for( i = 0; i < hb_list_count( data->list_title ); i++ ) + { + hb_job_t * job; + + title = hb_list_item( data->list_title, i ); + job = calloc( sizeof( hb_job_t ), 1 ); + title->job = job; + + job->title = title; + + /* Set defaults settings */ + job->chapter_start = 1; + job->chapter_end = hb_list_count( title->list_chapter ); + + /* Autocrop by default. Gnark gnark */ + memcpy( job->crop, title->crop, 4 * sizeof( int ) ); + + job->width = title->width - job->crop[2] - job->crop[3]; + hb_fix_aspect( job, HB_KEEP_WIDTH ); + if( job->height > title->height - job->crop[0] - job->crop[1] ) + { + job->height = title->height - job->crop[0] - job->crop[1]; + hb_fix_aspect( job, HB_KEEP_HEIGHT ); + } + job->keep_ratio = 1; + + job->vcodec = HB_VCODEC_FFMPEG; + job->vquality = -1.0; + job->vbitrate = 1000; + job->pass = 0; + job->vrate = title->rate; + job->vrate_base = title->rate_base; + + job->audios[0] = 0; + job->audios[1] = -1; + + job->acodec = HB_ACODEC_FAAC; + job->abitrate = 128; + job->arate = 44100; + + job->subtitle = -1; + + job->mux = HB_MUX_MP4; + } + + if( data->dvd ) + { + hb_dvd_close( &data->dvd ); + } +} + +/*********************************************************************** + * DecodePreviews + *********************************************************************** + * Decode 10 pictures for the given title. + * It assumes that data->reader and data->vts have successfully been + * DVDOpen()ed and ifoOpen()ed. + **********************************************************************/ +static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) +{ + int i, ret; + hb_buffer_t * buf_ps, * buf_es, * buf_raw; + hb_list_t * list_es, * list_raw; + hb_libmpeg2_t * mpeg2; + + buf_ps = hb_buffer_init( 2048 ); + list_es = hb_list_init(); + list_raw = hb_list_init(); + + hb_log( "scan: decoding previews for title %d", title->index ); + + hb_dvd_start( data->dvd, title->index, 1 ); + + for( i = 0; i < 10; i++ ) + { + int j, k; + FILE * file_preview; + char filename[1024]; + + hb_dvd_seek( data->dvd, (float) ( i + 1 ) / 11.0 ); + + hb_log( "scan: preview %d", i + 1 ); + + mpeg2 = hb_libmpeg2_init(); + + for( j = 0; j < 10240; j++ ) + { + if( !hb_dvd_read( data->dvd, buf_ps ) ) + { + goto error; + } + hb_demux_ps( buf_ps, list_es ); + + while( ( buf_es = hb_list_item( list_es, 0 ) ) ) + { + hb_list_rem( list_es, buf_es ); + if( buf_es->id == 0xE0 && !hb_list_count( list_raw ) ) + { + hb_libmpeg2_decode( mpeg2, buf_es, list_raw ); + } + else if( !i ) + { + LookForAC3( title, buf_es ); + } + hb_buffer_close( &buf_es ); + + if( hb_list_count( list_raw ) && + ( i || AllAC3OK( title ) ) ) + { + /* We got a picture */ + break; + } + } + + if( hb_list_count( list_raw ) && + ( i || AllAC3OK( title ) ) ) + { + break; + } + } + + if( !hb_list_count( list_raw ) ) + { + hb_log( "scan: could not get a decoded picture" ); + goto error; + } + + if( !i ) + { + /* Get size and rate infos */ + title->rate = 27000000; + hb_libmpeg2_info( mpeg2, &title->width, &title->height, + &title->rate_base ); + title->crop[0] = title->crop[1] = title->height / 2; + title->crop[2] = title->crop[3] = title->width / 2; + } + + hb_libmpeg2_close( &mpeg2 ); + + while( ( buf_es = hb_list_item( list_es, 0 ) ) ) + { + hb_list_rem( list_es, buf_es ); + hb_buffer_close( &buf_es ); + } + + buf_raw = hb_list_item( list_raw, 0 ); + + hb_get_tempory_filename( data->h, filename, "%x%d", + (int) title, i ); + + file_preview = fopen( filename, "w" ); + if( file_preview ) + { + fwrite( buf_raw->data, title->width * title->height * 3 / 2, + 1, file_preview ); + fclose( file_preview ); + } + else + { + hb_log( "scan: fopen failed (%s)", filename ); + } + +#define Y buf_raw->data +#define DARK 64 + + /* Detect black borders */ + + for( j = 0; j < title->width; j++ ) + { + for( k = 0; k < title->crop[0]; k++ ) + if( Y[ k * title->width + j ] > DARK ) + { + title->crop[0] = k; + break; + } + for( k = 0; k < title->crop[1]; k++ ) + if( Y[ ( title->height - k - 1 ) * + title->width + j ] > DARK ) + { + title->crop[1] = k; + break; + } + } + for( j = 0; j < title->height; j++ ) + { + for( k = 0; k < title->crop[2]; k++ ) + if( Y[ j * title->width + k ] > DARK ) + { + title->crop[2] = k; + break; + } + for( k = 0; k < title->crop[3]; k++ ) + if( Y[ j * title->width + + title->width - k - 1 ] > DARK ) + { + title->crop[3] = k; + break; + } + } + + while( ( buf_raw = hb_list_item( list_raw, 0 ) ) ) + { + hb_list_rem( list_raw, buf_raw ); + hb_buffer_close( &buf_raw ); + } + } + + title->crop[0] = EVEN( title->crop[0] ); + title->crop[1] = EVEN( title->crop[1] ); + title->crop[2] = EVEN( title->crop[2] ); + title->crop[3] = EVEN( title->crop[3] ); + + hb_log( "scan: %dx%d, %.3f fps, autocrop = %d/%d/%d/%d", + title->width, title->height, (float) title->rate / + (float) title->rate_base, title->crop[0], title->crop[1], + title->crop[2], title->crop[3] ); + + ret = 1; + goto cleanup; + +error: + ret = 0; + +cleanup: + hb_buffer_close( &buf_ps ); + while( ( buf_es = hb_list_item( list_es, 0 ) ) ) + { + hb_list_rem( list_es, buf_es ); + hb_buffer_close( &buf_es ); + } + hb_list_close( &list_es ); + while( ( buf_raw = hb_list_item( list_raw, 0 ) ) ) + { + hb_list_rem( list_raw, buf_raw ); + hb_buffer_close( &buf_raw ); + } + hb_list_close( &list_raw ); + return ret; +} + +static void LookForAC3( hb_title_t * title, hb_buffer_t * b ) +{ + int i; + int flags; + int rate; + int bitrate; + + /* Figure out if this is a AC3 buffer for a known track */ + hb_audio_t * audio = NULL; + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( audio->codec == HB_ACODEC_AC3 && + audio->id == b->id ) + { + break; + } + else + { + audio = NULL; + } + } + if( !audio ) + { + return; + } + + if( audio->bitrate ) + { + /* Already done for this track */ + return; + } + + for( i = 0; i < b->size - 7; i++ ) + { + if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) ) + { + hb_log( "scan: rate=%dHz, bitrate=%d", rate, bitrate ); + audio->rate = rate; + audio->bitrate = bitrate; + switch( flags & A52_CHANNEL_MASK ) + { + case A52_MONO: + case A52_CHANNEL1: + case A52_CHANNEL2: + audio->channels = 1; + break; + case A52_STEREO: + case A52_DOLBY: + case A52_CHANNEL: + audio->channels = 2; + break; + case A52_3F: + case A52_2F1R: + audio->channels = 3; + break; + case A52_3F1R: + case A52_2F2R: + audio->channels = 4; + break; + case A52_3F2R: + audio->channels = 5; + break; + } + /* XXX */ + sprintf( audio->lang + strlen( audio->lang ), + " (%d ch)", audio->channels ); + break; + } + } +} + +static int AllAC3OK( hb_title_t * title ) +{ + int i; + hb_audio_t * audio; + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( audio->codec == HB_ACODEC_AC3 && + !audio->bitrate ) + { + return 0; + } + } + + return 1; +} diff --git a/libhb/sync.c b/libhb/sync.c new file mode 100644 index 000000000..e0530a03a --- /dev/null +++ b/libhb/sync.c @@ -0,0 +1,664 @@ +/* $Id: sync.c,v 1.38 2005/04/14 21:57:58 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#include "samplerate.h" +#include "ffmpeg/avcodec.h" + +#ifdef INT64_MIN +#undef INT64_MIN /* Because it isn't defined correctly in Zeta */ +#endif +#define INT64_MIN (-9223372036854775807LL-1) + +#define AC3_SAMPLES_PER_FRAME 1536 + +typedef struct +{ + hb_audio_t * audio; + int64_t count_frames; + + /* Raw */ + SRC_STATE * state; + SRC_DATA data; + + /* AC-3 */ + int ac3_size; + uint8_t * ac3_buf; + +} hb_sync_audio_t; + +struct hb_work_object_s +{ + HB_WORK_COMMON; + + hb_job_t * job; + int done; + + /* Video */ + hb_subtitle_t * subtitle; + int64_t pts_offset; + int64_t pts_offset_old; + int64_t count_frames; + int64_t count_frames_max; + hb_buffer_t * cur; /* The next picture to process */ + + /* Audio */ + hb_sync_audio_t sync_audio[8]; + + /* Statistics */ + uint64_t st_counts[4]; + uint64_t st_dates[4]; + uint64_t st_first; +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static void InitAudio( hb_work_object_t * w, int i ); +static void Close( hb_work_object_t ** _w ); +static int Work( hb_work_object_t * w, hb_buffer_t ** unused1, + hb_buffer_t ** unused2 ); +static int SyncVideo( hb_work_object_t * w ); +static void SyncAudio( hb_work_object_t * w, int i ); +static int NeedSilence( hb_work_object_t * w, hb_audio_t * ); +static void InsertSilence( hb_work_object_t * w, int i ); +static void UpdateState( hb_work_object_t * w ); + +/*********************************************************************** + * hb_work_sync_init + *********************************************************************** + * Initialize the work object + **********************************************************************/ +hb_work_object_t * hb_work_sync_init( hb_job_t * job ) +{ + hb_work_object_t * w; + hb_title_t * title = job->title; + hb_chapter_t * chapter; + int i; + uint64_t duration; + + w = calloc( sizeof( hb_work_object_t ), 1 ); + w->name = strdup( "Synchronization" ); + w->work = Work; + w->close = Close; + + w->job = job; + w->pts_offset = INT64_MIN; + w->pts_offset_old = INT64_MIN; + w->count_frames = 0; + + /* Calculate how many video frames we are expecting */ + duration = 0; + for( i = job->chapter_start; i <= job->chapter_end; i++ ) + { + chapter = hb_list_item( title->list_chapter, i - 1 ); + duration += chapter->duration; + } + duration += 90000; + /* 1 second safety so we're sure we won't miss anything */ + w->count_frames_max = duration * job->vrate / job->vrate_base / 90000; + + hb_log( "sync: expecting %lld video frames", w->count_frames_max ); + + /* Initialize libsamplerate for every audio track we have */ + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + InitAudio( w, i ); + } + + /* Get subtitle info, if any */ + w->subtitle = hb_list_item( title->list_subtitle, 0 ); + + return w; +} + +static void InitAudio( hb_work_object_t * w, int i ) +{ + hb_job_t * job = w->job; + hb_title_t * title = job->title; + hb_sync_audio_t * sync; + + sync = &w->sync_audio[i]; + sync->audio = hb_list_item( title->list_audio, i ); + + if( job->acodec & HB_ACODEC_AC3 ) + { + /* Have a silent AC-3 frame ready in case we have to fill a + gap */ + AVCodec * codec; + AVCodecContext * c; + short * zeros; + + codec = avcodec_find_encoder( CODEC_ID_AC3 ); + c = avcodec_alloc_context(); + + c->bit_rate = sync->audio->bitrate; + c->sample_rate = sync->audio->rate; + c->channels = sync->audio->channels; + + if( avcodec_open( c, codec ) < 0 ) + { + hb_log( "sync: avcodec_open failed" ); + return; + } + + zeros = calloc( AC3_SAMPLES_PER_FRAME * + sizeof( short ) * c->channels, 1 ); + sync->ac3_size = sync->audio->bitrate * AC3_SAMPLES_PER_FRAME / + sync->audio->rate / 8; + sync->ac3_buf = malloc( sync->ac3_size ); + + if( avcodec_encode_audio( c, sync->ac3_buf, sync->ac3_size, + zeros ) != sync->ac3_size ) + { + hb_log( "sync: avcodec_encode_audio failed" ); + } + + free( zeros ); + avcodec_close( c ); + av_free( c ); + } + else + { + /* Initialize libsamplerate */ + int error; + sync->state = src_new( SRC_LINEAR, 2, &error ); + sync->data.end_of_input = 0; + } +} + +/*********************************************************************** + * Close + *********************************************************************** + * + **********************************************************************/ +static void Close( hb_work_object_t ** _w ) +{ + hb_work_object_t * w = *_w; + hb_job_t * job = w->job; + hb_title_t * title = job->title; + + int i; + + if( w->cur ) hb_buffer_close( &w->cur ); + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + if( job->acodec & HB_ACODEC_AC3 ) + { + free( w->sync_audio[i].ac3_buf ); + } + else + { + src_delete( w->sync_audio[i].state ); + } + } + + free( w->name ); + free( w ); + *_w = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * The root routine of this work abject + **********************************************************************/ +static int Work( hb_work_object_t * w, hb_buffer_t ** unused1, + hb_buffer_t ** unused2 ) +{ + int i; + + /* If we ever got a video frame, handle audio now */ + if( w->pts_offset != INT64_MIN ) + { + for( i = 0; i < hb_list_count( w->job->title->list_audio ); i++ ) + { + SyncAudio( w, i ); + } + } + + /* Handle video */ + return SyncVideo( w ); +} + +/*********************************************************************** + * SyncVideo + *********************************************************************** + * + **********************************************************************/ +static int SyncVideo( hb_work_object_t * w ) +{ + hb_buffer_t * cur, * next, * sub = NULL; + hb_job_t * job = w->job; + int64_t pts_expected; + + if( w->done ) + { + return HB_WORK_DONE; + } + + if( hb_thread_has_exited( job->reader ) && + !hb_fifo_size( job->fifo_mpeg2 ) && + !hb_fifo_size( job->fifo_raw ) ) + { + /* All video data has been processed already, we won't get + more */ + hb_log( "sync: got %lld frames, %lld expected", + w->count_frames, w->count_frames_max ); + w->done = 1; + return HB_WORK_DONE; + } + + if( !w->cur && !( w->cur = hb_fifo_get( job->fifo_raw ) ) ) + { + /* We haven't even got a frame yet */ + return HB_WORK_OK; + } + cur = w->cur; + + /* At this point we have a frame to process. Let's check + 1) if we will be able to push into the fifo ahead + 2) if the next frame is there already, since we need it to + know whether we'll have to repeat the current frame or not */ + while( !hb_fifo_is_full( job->fifo_sync ) && + ( next = hb_fifo_see( job->fifo_raw ) ) ) + { + hb_buffer_t * buf_tmp; + + if( w->pts_offset == INT64_MIN ) + { + /* This is our first frame */ + hb_log( "sync: first pts is %lld", cur->start ); + w->pts_offset = cur->start; + } + + /* Check for PTS jumps over 0.5 second */ + if( next->start < cur->start - 45000 || + next->start > cur->start + 45000 ) + { + hb_log( "PTS discontinuity (%lld, %lld)", + cur->start, next->start ); + + /* Trash all subtitles */ + if( w->subtitle ) + { + while( ( sub = hb_fifo_get( w->subtitle->fifo_raw ) ) ) + { + hb_buffer_close( &sub ); + } + } + + /* Trash current picture */ + hb_buffer_close( &cur ); + w->cur = cur = hb_fifo_get( job->fifo_raw ); + + /* Calculate new offset */ + w->pts_offset_old = w->pts_offset; + w->pts_offset = cur->start - + w->count_frames * w->job->vrate_base / 300; + continue; + } + + /* Look for a subtitle for this frame */ + if( w->subtitle ) + { + /* Trash subtitles older than this picture */ + while( ( sub = hb_fifo_see( w->subtitle->fifo_raw ) ) && + sub->stop < cur->start ) + { + sub = hb_fifo_get( w->subtitle->fifo_raw ); + hb_buffer_close( &sub ); + } + + /* If we have subtitles left in the fifo, check if we should + apply the first one to the current frame or if we should + keep it for later */ + if( sub && sub->start > cur->start ) + { + sub = NULL; + } + } + + /* The PTS of the frame we are expecting now */ + pts_expected = w->pts_offset + + w->count_frames * w->job->vrate_base / 300; + + if( cur->start < pts_expected - w->job->vrate_base / 300 / 2 && + next->start < pts_expected + w->job->vrate_base / 300 / 2 ) + { + /* The current frame is too old but the next one matches, + let's trash */ + hb_buffer_close( &cur ); + w->cur = cur = hb_fifo_get( job->fifo_raw ); + continue; + } + + if( next->start > pts_expected + 3 * w->job->vrate_base / 300 / 2 ) + { + /* We'll need the current frame more than one time. Make a + copy of it and keep it */ + buf_tmp = hb_buffer_init( cur->size ); + memcpy( buf_tmp->data, cur->data, cur->size ); + } + else + { + /* The frame has the expected date and won't have to be + duplicated, just put it through */ + buf_tmp = cur; + w->cur = cur = hb_fifo_get( job->fifo_raw ); + } + + /* Replace those MPEG-2 dates with our dates */ + buf_tmp->start = (uint64_t) w->count_frames * + w->job->vrate_base / 300; + buf_tmp->stop = (uint64_t) ( w->count_frames + 1 ) * + w->job->vrate_base / 300; + + /* If we have a subtitle for this picture, copy it */ + /* FIXME: we should avoid this memcpy */ + if( sub ) + { + buf_tmp->sub = hb_buffer_init( sub->size ); + buf_tmp->sub->x = sub->x; + buf_tmp->sub->y = sub->y; + buf_tmp->sub->width = sub->width; + buf_tmp->sub->height = sub->height; + memcpy( buf_tmp->sub->data, sub->data, sub->size ); + } + + /* Push the frame to the renderer */ + hb_fifo_push( job->fifo_sync, buf_tmp ); + + /* Update UI */ + UpdateState( w ); + + /* Make sure we won't get more frames then expected */ + if( w->count_frames >= w->count_frames_max ) + { + hb_log( "sync: got %lld frames", w->count_frames ); + w->done = 1; + break; + } + } + + return HB_WORK_OK; +} + +/*********************************************************************** + * SyncAudio + *********************************************************************** + * + **********************************************************************/ +static void SyncAudio( hb_work_object_t * w, int i ) +{ + hb_job_t * job; + hb_audio_t * audio; + hb_buffer_t * buf; + hb_sync_audio_t * sync; + + hb_fifo_t * fifo; + int rate; + + int64_t pts_expected; + int64_t start; + + job = w->job; + sync = &w->sync_audio[i]; + audio = sync->audio; + + if( job->acodec & HB_ACODEC_AC3 ) + { + fifo = audio->fifo_out; + rate = audio->rate; + } + else + { + fifo = audio->fifo_sync; + rate = job->arate; + } + + while( !hb_fifo_is_full( fifo ) && + ( buf = hb_fifo_see( audio->fifo_raw ) ) ) + { + /* The PTS of the samples we are expecting now */ + pts_expected = w->pts_offset + sync->count_frames * 90000 / rate; + + if( ( buf->start > pts_expected + 45000 || + buf->start < pts_expected - 45000 ) && + w->pts_offset_old > INT64_MIN ) + { + /* There has been a PTS discontinuity, and this frame might + be from before the discontinuity */ + pts_expected = w->pts_offset_old + sync->count_frames * + 90000 / rate; + + if( buf->start > pts_expected + 45000 || + buf->start < pts_expected - 45000 ) + { + /* There is really nothing we can do with it */ + buf = hb_fifo_get( audio->fifo_raw ); + hb_buffer_close( &buf ); + continue; + } + + /* Use the older offset */ + start = pts_expected - w->pts_offset_old; + } + else + { + start = pts_expected - w->pts_offset; + } + + if( ( buf->start + buf->stop ) / 2 < pts_expected ) + { + /* Late audio, trash it */ + buf = hb_fifo_get( audio->fifo_raw ); + hb_buffer_close( &buf ); + continue; + } + + if( buf->start > pts_expected + ( buf->stop - buf->start ) / 2 ) + { + /* Audio push, send a frame of silence */ + InsertSilence( w, i ); + continue; + } + + if( job->acodec & HB_ACODEC_AC3 ) + { + buf = hb_fifo_get( audio->fifo_raw ); + buf->start = start; + buf->stop = start + 90000 * AC3_SAMPLES_PER_FRAME / rate; + + sync->count_frames += AC3_SAMPLES_PER_FRAME; + } + else + { + hb_buffer_t * buf_raw = hb_fifo_get( audio->fifo_raw ); + + int count_in, count_out; + + count_in = buf_raw->size / 2 / sizeof( float ); + count_out = ( buf->stop - pts_expected ) * job->arate / 90000; + + sync->data.data_in = (float *) buf_raw->data; + sync->data.input_frames = count_in; + + if( buf->start < pts_expected - ( buf->stop - buf->start ) / 5 ) + { + /* Avoid too heavy downsampling, trash the beginning of + the buffer instead */ + int drop; + drop = count_in * ( pts_expected - buf->start ) / + ( buf->stop - buf->start ); + sync->data.data_in += 2 * drop; + sync->data.input_frames -= drop; + hb_log( "dropping %d of %d samples", drop, count_in ); + } + + sync->data.output_frames = count_out; + sync->data.src_ratio = (double) sync->data.output_frames / + (double) sync->data.input_frames; + + buf = hb_buffer_init( sync->data.output_frames * 2 * + sizeof( float ) ); + sync->data.data_out = (float *) buf->data; + if( src_process( sync->state, &sync->data ) ) + { + /* XXX If this happens, we're screwed */ + hb_log( "sync: src_process failed" ); + } + hb_buffer_close( &buf_raw ); + + buf->size = sync->data.output_frames_gen * 2 * sizeof( float ); + + /* Set dates for resampled data */ + buf->start = start; + buf->stop = start + sync->data.output_frames_gen * + 90000 / job->arate; + + sync->count_frames += sync->data.output_frames_gen; + } + + buf->key = 1; + hb_fifo_push( fifo, buf ); + } + + if( NeedSilence( w, audio ) ) + { + InsertSilence( w, i ); + } +} + +static int NeedSilence( hb_work_object_t * w, hb_audio_t * audio ) +{ + hb_job_t * job = w->job; + + if( hb_fifo_size( audio->fifo_in ) || + hb_fifo_size( audio->fifo_raw ) || + hb_fifo_size( audio->fifo_sync ) || + hb_fifo_size( audio->fifo_out ) ) + { + /* We have some audio, we are fine */ + return 0; + } + + /* No audio left in fifos */ + + if( hb_thread_has_exited( job->reader ) ) + { + /* We might miss some audio to complete encoding and muxing + the video track */ + return 1; + } + + if( hb_fifo_is_full( job->fifo_mpeg2 ) && + hb_fifo_is_full( job->fifo_raw ) && + hb_fifo_is_full( job->fifo_sync ) && + hb_fifo_is_full( job->fifo_render ) && + hb_fifo_is_full( job->fifo_mpeg4 ) ) + { + /* Too much video and no audio, oh-oh */ + return 1; + } + + return 0; +} + +static void InsertSilence( hb_work_object_t * w, int i ) +{ + hb_job_t * job; + hb_sync_audio_t * sync; + hb_buffer_t * buf; + + job = w->job; + sync = &w->sync_audio[i]; + + if( job->acodec & HB_ACODEC_AC3 ) + { + buf = hb_buffer_init( sync->ac3_size ); + buf->start = sync->count_frames * 90000 / sync->audio->rate; + buf->stop = buf->start + 90000 * AC3_SAMPLES_PER_FRAME / + sync->audio->rate; + memcpy( buf->data, sync->ac3_buf, buf->size ); + + hb_log( "sync: adding a silent AC-3 frame for track %x", + sync->audio->id ); + hb_fifo_push( sync->audio->fifo_out, buf ); + + sync->count_frames += AC3_SAMPLES_PER_FRAME; + + } + else + { + buf = hb_buffer_init( 2 * job->arate / 20 * + sizeof( float ) ); + buf->start = sync->count_frames * 90000 / job->arate; + buf->stop = buf->start + 90000 / 20; + memset( buf->data, 0, buf->size ); + + hb_log( "sync: adding 50 ms of silence for track %x", + sync->audio->id ); + hb_fifo_push( sync->audio->fifo_sync, buf ); + + sync->count_frames += job->arate / 20; + } +} + +static void UpdateState( hb_work_object_t * w ) +{ + hb_state_t state; + + if( !w->count_frames ) + { + w->st_first = hb_get_date(); + } + w->count_frames++; + + if( hb_get_date() > w->st_dates[3] + 1000 ) + { + memmove( &w->st_dates[0], &w->st_dates[1], + 3 * sizeof( uint64_t ) ); + memmove( &w->st_counts[0], &w->st_counts[1], + 3 * sizeof( uint64_t ) ); + w->st_dates[3] = hb_get_date(); + w->st_counts[3] = w->count_frames; + } + +#define p state.param.working + state.state = HB_STATE_WORKING; + p.progress = (float) w->count_frames / (float) w->count_frames_max; + if( p.progress > 1.0 ) + { + p.progress = 1.0; + } + p.rate_cur = 1000.0 * + (float) ( w->st_counts[3] - w->st_counts[0] ) / + (float) ( w->st_dates[3] - w->st_dates[0] ); + if( hb_get_date() > w->st_first + 4000 ) + { + int eta; + p.rate_avg = 1000.0 * (float) w->st_counts[3] / + (float) ( w->st_dates[3] - w->st_first ); + eta = (float) ( w->count_frames_max - w->st_counts[3] ) / + p.rate_avg; + p.hours = eta / 3600; + p.minutes = ( eta % 3600 ) / 60; + p.seconds = eta % 60; + } + else + { + p.rate_avg = 0.0; + p.hours = -1; + p.minutes = -1; + p.seconds = -1; + } +#undef p + + hb_set_state( w->job->h, &state ); +} diff --git a/libhb/update.c b/libhb/update.c new file mode 100644 index 000000000..767807038 --- /dev/null +++ b/libhb/update.c @@ -0,0 +1,157 @@ +/* $Id: update.c,v 1.7 2005/03/26 23:04:14 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +#define HB_URL "handbrake.m0k.org" +#define HB_QUERY "GET /LATEST HTTP/1.0\r\nHost: " HB_URL "\r\n\r\n" + +typedef struct +{ + int * build; + char * version; + +} hb_update_t; + +static void UpdateFunc( void * ); + +hb_thread_t * hb_update_init( int * build, char * version ) +{ + hb_update_t * data = calloc( sizeof( hb_update_t ), 1 ); + data->build = build; + data->version = version; + + return hb_thread_init( "update", UpdateFunc, data, + HB_NORMAL_PRIORITY ); +} + +static void UpdateFunc( void * _data ) +{ + hb_update_t * data = (hb_update_t *) _data; + + hb_net_t * net; + int ret; + char buf[1024]; + char * cur, * end, * p; + int size; + int stable, unstable; + char stable_str[16], unstable_str[16]; + int i; + + if( !( net = hb_net_open( HB_URL, 80 ) ) ) + { + goto error; + } + + if( hb_net_send( net, HB_QUERY ) < 0 ) + { + hb_net_close( &net ); + goto error; + } + + size = 0; + memset( buf, 0, 1024 ); + for( ;; ) + { + ret = hb_net_recv( net, &buf[size], sizeof( buf ) - size ); + if( ret < 1 ) + { + hb_net_close( &net ); + break; + } + size += ret; + } + + cur = buf; + end = &buf[sizeof( buf )]; + + /* Make sure we got it */ + cur += 9; + if( size < 15 || strncmp( cur, "200 OK", 6 ) ) + { + /* Something went wrong */ + goto error; + } + cur += 6; + + /* Find the end of the headers and the beginning of the content */ + for( ; &cur[3] < end; cur++ ) + { + if( cur[0] == '\r' && cur[1] == '\n' && + cur[2] == '\r' && cur[3] == '\n' ) + { + cur += 4; + break; + } + } + + if( cur >= end ) + { + goto error; + } + + stable = strtol( cur, &p, 10 ); + if( cur == p ) + { + goto error; + } + cur = p + 1; + memset( stable_str, 0, sizeof( stable_str ) ); + for( i = 0; + i < sizeof( stable_str ) - 1 && cur < end && *cur != '\n'; + i++, cur++ ) + { + stable_str[i] = *cur; + } + + hb_log( "latest stable: %s, build %d", stable_str, stable ); + + cur++; + if( cur >= end ) + { + goto error; + } + + unstable = strtol( cur, &p, 10 ); + if( cur == p ) + { + goto error; + } + cur = p + 1; + memset( unstable_str, 0, sizeof( unstable_str ) ); + for( i = 0; + i < sizeof( unstable_str ) - 1 && cur < end && *cur != '\n'; + i++, cur++ ) + { + unstable_str[i] = *cur; + } + + hb_log( "latest unstable: %s, build %d", unstable_str, unstable ); + + if( HB_BUILD % 100 ) + { + /* We are runnning an unstable build */ + if( unstable > HB_BUILD ) + { + memcpy( data->version, unstable_str, sizeof( unstable_str ) ); + *(data->build) = unstable; + } + } + else + { + /* We are runnning an stable build */ + if( stable > HB_BUILD ) + { + memcpy( data->version, stable_str, sizeof( stable_str ) ); + *(data->build) = stable; + } + } + +error: + free( data ); + return; +} + diff --git a/libhb/work.c b/libhb/work.c new file mode 100644 index 000000000..6c0be24e3 --- /dev/null +++ b/libhb/work.c @@ -0,0 +1,400 @@ +/* $Id: work.c,v 1.43 2005/03/17 16:38:49 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" + +struct hb_work_object_s +{ + HB_WORK_COMMON; +}; + +typedef struct +{ + hb_list_t * jobs; + int cpu_count; + int * error; + volatile int * die; + +} hb_work_t; + +static void work_func(); +static void do_job( hb_job_t *, int cpu_count ); +static void job_loop( void * ); + +hb_thread_t * hb_work_init( hb_list_t * jobs, int cpu_count, + volatile int * die, int * error ) +{ + hb_work_t * work = calloc( sizeof( hb_work_t ), 1 ); + + work->jobs = jobs; + work->cpu_count = cpu_count; + work->die = die; + work->error = error; + + return hb_thread_init( "work", work_func, work, HB_LOW_PRIORITY ); +} + +static void work_func( void * _work ) +{ + hb_work_t * work = _work; + hb_job_t * job; + + hb_log( "%d job(s) to process", hb_list_count( work->jobs ) ); + + while( !*work->die && ( job = hb_list_item( work->jobs, 0 ) ) ) + { + hb_list_rem( work->jobs, job ); + job->die = work->die; + do_job( job, work->cpu_count ); + } + + *(work->error) = HB_ERROR_NONE; + + free( work ); +} + +static void do_job( hb_job_t * job, int cpu_count ) +{ + hb_title_t * title; + int i; + hb_thread_t * threads[8]; + hb_work_object_t * w; + uint64_t time_total; + hb_audio_t * audio; + hb_subtitle_t * subtitle; + + title = job->title; + + job->list_work = hb_list_init(); + + hb_log( "starting job" ); + hb_log( " + device %s", title->dvd ); + hb_log( " + title %d, chapter(s) %d to %d", title->index, + job->chapter_start, job->chapter_end ); + hb_log( " + %dx%d -> %dx%d, crop %d/%d/%d/%d", + title->width, title->height, job->width, job->height, + job->crop[0], job->crop[1], job->crop[2], job->crop[3] ); + hb_log( " + deinterlace %s", job->deinterlace ? "on" : "off" ); + hb_log( " + grayscale %s", job->grayscale ? "on" : "off" ); + if( job->vquality >= 0.0 && job->vquality <= 1.0 ) + { + hb_log( " + %.3f fps, video quality %.2f", (float) job->vrate / + (float) job->vrate_base, job->vquality ); + } + else + { + hb_log( " + %.3f fps, video bitrate %d kbps, pass %d", + (float) job->vrate / (float) job->vrate_base, + job->vbitrate, job->pass ); + } + + job->fifo_mpeg2 = hb_fifo_init( 2048 ); + job->fifo_raw = hb_fifo_init( 8 ); + job->fifo_sync = hb_fifo_init( 8 ); + job->fifo_render = hb_fifo_init( 8 ); + job->fifo_mpeg4 = hb_fifo_init( 8 ); + + /* Synchronization */ + w = hb_work_sync_init( job ); + w->fifo_in = NULL; + w->fifo_out = NULL; + hb_list_add( job->list_work, w ); + + /* Video decoder */ + w = hb_work_decmpeg2_init( job ); + w->fifo_in = job->fifo_mpeg2; + w->fifo_out = job->fifo_raw; + hb_list_add( job->list_work, w ); + + /* Video renderer */ + w = hb_work_render_init( job ); + w->fifo_in = job->fifo_sync; + w->fifo_out = job->fifo_render; + hb_list_add( job->list_work, w ); + + /* Video encoder */ + switch( job->vcodec ) + { + case HB_VCODEC_FFMPEG: + hb_log( " + encoder FFmpeg" ); + w = hb_work_encavcodec_init( job ); + break; + case HB_VCODEC_XVID: + hb_log( " + encoder XviD" ); + w = hb_work_encxvid_init( job ); + break; + case HB_VCODEC_X264: + hb_log( " + encoder x264" ); + w = hb_work_encx264_init( job ); + break; + } + w->fifo_in = job->fifo_render; + w->fifo_out = job->fifo_mpeg4; + hb_list_add( job->list_work, w ); + + subtitle = hb_list_item( title->list_subtitle, 0 ); + if( subtitle ) + { + hb_log( " + subtitle %x, %s", subtitle->id, subtitle->lang ); + + subtitle->fifo_in = hb_fifo_init( 8 ); + subtitle->fifo_raw = hb_fifo_init( 8 ); + + w = hb_work_decsub_init( job ); + w->fifo_in = subtitle->fifo_in; + w->fifo_out = subtitle->fifo_raw; + hb_list_add( job->list_work, w ); + } + + if( job->acodec & HB_ACODEC_AC3 ) + { + hb_log( " + audio AC3 passthrough" ); + } + else + { + hb_log( " + audio %d kbps, %d Hz", job->abitrate, job->arate ); + hb_log( " + encoder %s", ( job->acodec & HB_ACODEC_FAAC ) ? + "faac" : ( ( job->acodec & HB_ACODEC_LAME ) ? "lame" : + "vorbis" ) ); + } + + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + hb_log( " + %x, %s", audio->id, audio->lang ); + + audio->fifo_in = hb_fifo_init( 2048 ); + audio->fifo_raw = hb_fifo_init( 8 ); + audio->fifo_sync = hb_fifo_init( 8 ); + audio->fifo_out = hb_fifo_init( 8 ); + + switch( audio->codec ) + { + case HB_ACODEC_AC3: + w = hb_work_deca52_init( job, audio ); + break; + case HB_ACODEC_MPGA: + w = hb_work_decavcodec_init( job, audio ); + break; + case HB_ACODEC_LPCM: + w = hb_work_declpcm_init( job, audio ); + break; + } + w->fifo_in = audio->fifo_in; + w->fifo_out = audio->fifo_raw; + hb_list_add( job->list_work, w ); + + switch( job->acodec ) + { + case HB_ACODEC_FAAC: + w = hb_work_encfaac_init( job, audio ); + break; + case HB_ACODEC_LAME: + w = hb_work_enclame_init( job, audio ); + break; + case HB_ACODEC_VORBIS: + w = hb_work_encvorbis_init( job, audio ); + break; + } + if( job->acodec != HB_ACODEC_AC3 ) + { + w->fifo_in = audio->fifo_sync; + w->fifo_out = audio->fifo_out; + hb_list_add( job->list_work, w ); + } + } + + /* Init read & write threads */ + job->reader = hb_reader_init( job ); + + hb_log( " + output: %s", job->file ); + job->muxer = hb_muxer_init( job ); + + for( i = 0; i < hb_list_count( job->list_work ); i++ ) + { + w = hb_list_item( job->list_work, i ); + w->lock = hb_lock_init(); + w->used = 0; + w->time = 0; + } + + job->done = 0; + + /* Launch processing threads */ + for( i = 0; i < cpu_count; i++ ) + { + char thread_name[16]; + if( cpu_count - 1 ) + { + snprintf( thread_name, 16, "cpu killer %d", i + 1 ); + } + else + { + snprintf( thread_name, 16, "cpu killer" ); + } + threads[i] = hb_thread_init( thread_name, job_loop, job, + HB_LOW_PRIORITY ); + } + + while( !*job->die && !job->done ) + { + hb_snooze( 500 ); + } + + for( i = 0; i < cpu_count; i++ ) + { + hb_thread_close( &threads[i] ); + } + + /* Stop read & write threads */ + hb_thread_close( &job->reader ); + hb_thread_close( &job->muxer ); + + /* Stats */ + time_total = 0; + for( i = 0; i < hb_list_count( job->list_work ); i++ ) + { + w = hb_list_item( job->list_work, i ); + time_total += w->time; + } + for( i = 0; i < hb_list_count( job->list_work ); i++ ) + { + w = hb_list_item( job->list_work, i ); + hb_log( "%s: %.2f %%", w->name, + 100.0 * (float) w->time / (float) time_total ); + } + + /* Close work objects */ + while( ( w = hb_list_item( job->list_work, 0 ) ) ) + { + hb_list_rem( job->list_work, w ); + hb_lock_close( &w->lock ); + w->close( &w ); + } + + /* Close fifos */ + hb_fifo_close( &job->fifo_mpeg2 ); + hb_fifo_close( &job->fifo_raw ); + hb_fifo_close( &job->fifo_sync ); + hb_fifo_close( &job->fifo_render ); + hb_fifo_close( &job->fifo_mpeg4 ); + if( subtitle ) + { + hb_fifo_close( &subtitle->fifo_in ); + hb_fifo_close( &subtitle->fifo_raw ); + } + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + hb_fifo_close( &audio->fifo_in ); + hb_fifo_close( &audio->fifo_raw ); + hb_fifo_close( &audio->fifo_sync ); + hb_fifo_close( &audio->fifo_out ); + } +} + +static int lock( hb_work_object_t * w ) +{ + hb_lock( w->lock ); + if( w->used ) + { + hb_unlock( w->lock ); + return 0; + } + w->used = 1; + hb_unlock( w->lock ); + return 1; +} + +static void unlock( hb_work_object_t * w ) +{ + hb_lock( w->lock ); + w->used = 0; + hb_unlock( w->lock ); +} + +static void job_loop( void * _job ) +{ + hb_job_t * job = _job; + hb_buffer_t * buf_in, * buf_out; + hb_work_object_t * w; + int work_count; + int act; + int i; + uint64_t date; + int done; + + work_count = hb_list_count( job->list_work ); + act = 0; + done = 0; + + while( !*job->die && !job->done ) + { + /* Handle synchronization, resampling, framerate change, + etc */ + w = hb_list_item( job->list_work, 0 ); + if( lock( w ) ) + { + date = hb_get_date(); + if( w->work( w, NULL, NULL ) == HB_WORK_DONE ) + { + done = 1; + } + w->time += hb_get_date() - date; + unlock( w ); + } + + for( i = 1; !*job->die && !job->done && i < work_count; i++ ) + { + w = hb_list_item( job->list_work, i ); + if( !lock( w ) ) + continue; + + for( ;; ) + { + hb_lock( job->pause ); + hb_unlock( job->pause ); + + if( hb_fifo_is_full( w->fifo_out ) || + !( buf_in = hb_fifo_get( w->fifo_in ) ) ) + { + break; + } + + date = hb_get_date(); + w->work( w, &buf_in, &buf_out ); + w->time += hb_get_date() - date; + if( buf_in ) + { + hb_buffer_close( &buf_in ); + } + if( buf_out ) + { + act = 1; + hb_fifo_push( w->fifo_out, buf_out ); + } + } + + unlock( w ); + } + + if( done && + !hb_fifo_size( job->fifo_sync ) && + !hb_fifo_size( job->fifo_render ) && + hb_fifo_size( job->fifo_mpeg4 ) < 2 ) + { + job->done = 1; + break; + } + + /* If we did nothing, wait a bit before trying again */ + if( !act ) + { + hb_snooze( 50 ); + } + act = 0; + } +} diff --git a/macosx/Controller.h b/macosx/Controller.h index 400246af8..c32dacc04 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -1,4 +1,4 @@ -/* $Id: Controller.h,v 1.14 2004/02/13 13:45:51 titer Exp $ +/* $Id: Controller.h,v 1.35 2005/08/01 14:29:50 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -6,153 +6,138 @@ #include <Cocoa/Cocoa.h> -#include "HandBrake.h" -#include "PictureGLView.h" -#include "TargetSizeField.h" +#include "hb.h" + +#include "ScanController.h" +#include "PictureController.h" +#include "QueueController.h" @interface HBController : NSObject { IBOutlet NSWindow * fWindow; - /* Scan view */ - IBOutlet NSView * fScView; - IBOutlet NSTextField * fScWelcomeField; - IBOutlet NSTextField * fScSelectField; - IBOutlet NSMatrix * fScMatrix; - IBOutlet NSButtonCell * fScDetectedCell; - IBOutlet NSPopUpButton * fScDetectedPopUp; - IBOutlet NSButtonCell * fScFolderCell; - IBOutlet NSTextField * fScFolderField; - IBOutlet NSButton * fScBrowseButton; - IBOutlet NSTextField * fScStatusField; - IBOutlet NSProgressIndicator * fScProgress; - IBOutlet NSButton * fScOpenButton; - - IBOutlet NSView * fTempView; - - /* Rip view */ - IBOutlet NSView * fRipView; - - /* General box */ - IBOutlet NSTextField * fRipGeneralField; - IBOutlet NSTextField * fRipTitleField; - IBOutlet NSPopUpButton * fRipTitlePopUp; - IBOutlet NSTextField * fRipFormatField; - IBOutlet NSPopUpButton * fRipFormatPopUp; - IBOutlet NSTextField * fRipFileField1; - IBOutlet NSTextField * fRipFileField2; - IBOutlet NSButton * fRipBrowseButton; + /* Scan panel */ + IBOutlet ScanController * fScanController; + IBOutlet NSPanel * fScanPanel; + + /* Picture panel */ + IBOutlet PictureController * fPictureController; + IBOutlet NSPanel * fPicturePanel; + + /* Queue panel */ + IBOutlet QueueController * fQueueController; + IBOutlet NSPanel * fQueuePanel; + IBOutlet NSButton * fQueueCheck; + IBOutlet NSButton * fQueueAddButton; + IBOutlet NSButton * fQueueShowButton; + + /* Source box */ + IBOutlet NSTextField * fSrcDVD1Field; + IBOutlet NSTextField * fSrcDVD2Field; + IBOutlet NSTextField * fSrcTitleField; + IBOutlet NSPopUpButton * fSrcTitlePopUp; + IBOutlet NSTextField * fSrcChapterField; + IBOutlet NSPopUpButton * fSrcChapterStartPopUp; + IBOutlet NSTextField * fSrcChapterToField; + IBOutlet NSPopUpButton * fSrcChapterEndPopUp; + IBOutlet NSTextField * fSrcDuration1Field; + IBOutlet NSTextField * fSrcDuration2Field; + + /* Destination box */ + IBOutlet NSTextField * fDstFormatField; + IBOutlet NSPopUpButton * fDstFormatPopUp; + IBOutlet NSTextField * fDstCodecsField; + IBOutlet NSPopUpButton * fDstCodecsPopUp; + IBOutlet NSTextField * fDstFile1Field; + IBOutlet NSTextField * fDstFile2Field; + IBOutlet NSButton * fDstBrowseButton; /* Video box */ - IBOutlet NSTextField * fRipVideoField; - IBOutlet NSTextField * fRipEncoderField; - IBOutlet NSPopUpButton * fRipEncoderPopUp; - IBOutlet NSTextField * fRipBitrateField; - IBOutlet NSMatrix * fRipVideoMatrix; - IBOutlet NSButtonCell * fRipCustomCell; - IBOutlet NSTextField * fRipCustomField; - IBOutlet NSButtonCell * fRipTargetCell; - IBOutlet HBTargetSizeField * fRipTargetField; - IBOutlet NSButton * fRipTwoPassCheck; - IBOutlet NSButton * fRipCropButton; + IBOutlet NSTextField * fVidRateField; + IBOutlet NSPopUpButton * fVidRatePopUp; + IBOutlet NSTextField * fVidEncoderField; + IBOutlet NSPopUpButton * fVidEncoderPopUp; + IBOutlet NSTextField * fVidQualityField; + IBOutlet NSMatrix * fVidQualityMatrix; + IBOutlet NSButtonCell * fVidTargetCell; + IBOutlet NSTextField * fVidTargetSizeField; + IBOutlet NSButtonCell * fVidBitrateCell; + IBOutlet NSTextField * fVidBitrateField; + IBOutlet NSButtonCell * fVidConstantCell; + IBOutlet NSSlider * fVidQualitySlider; + IBOutlet NSButton * fVidGrayscaleCheck; + IBOutlet NSButton * fVidTwoPassCheck; + + /* Subtitles box */ + IBOutlet NSTextField * fSubField; + IBOutlet NSPopUpButton * fSubPopUp; /* Audio box */ - IBOutlet NSTextField * fRipAudioField; - IBOutlet NSTextField * fRipLang1Field; - IBOutlet NSPopUpButton * fRipLang1PopUp; - IBOutlet NSTextField * fRipLang2Field; - IBOutlet NSPopUpButton * fRipLang2PopUp; - IBOutlet NSTextField * fRipAudBitField; - IBOutlet NSPopUpButton * fRipAudBitPopUp; + IBOutlet NSTextField * fAudLang1Field; + IBOutlet NSPopUpButton * fAudLang1PopUp; + IBOutlet NSTextField * fAudLang2Field; + IBOutlet NSPopUpButton * fAudLang2PopUp; + IBOutlet NSTextField * fAudRateField; + IBOutlet NSPopUpButton * fAudRatePopUp; + IBOutlet NSTextField * fAudBitrateField; + IBOutlet NSPopUpButton * fAudBitratePopUp; /* Bottom */ - IBOutlet NSTextField * fRipStatusField; - IBOutlet NSTextField * fRipInfoField; - IBOutlet NSProgressIndicator * fRipProgress; - IBOutlet NSButton * fRipPauseButton; - IBOutlet NSButton * fRipRipButton; + IBOutlet NSButton * fPictureButton; + IBOutlet NSTextField * fStatusField; + IBOutlet NSProgressIndicator * fRipIndicator; + IBOutlet NSButton * fShowQuButton; + IBOutlet NSButton * fAddToQuButton; + IBOutlet NSButton * fPauseButton; + IBOutlet NSButton * fRipButton; + + hb_handle_t * fHandle; +} - /* "Done" alert panel */ - IBOutlet NSPanel * fDonePanel; +- (void) TranslateStrings; - /* Crop & scale panel */ - IBOutlet NSPanel * fPicturePanel; - IBOutlet HBPictureGLView * fPictureGLView; - IBOutlet NSTextField * fWidthField1; - IBOutlet NSTextField * fWidthField2; - IBOutlet NSStepper * fWidthStepper; - IBOutlet NSButton * fDeinterlaceCheck; - IBOutlet NSTextField * fTopField1; - IBOutlet NSTextField * fTopField2; - IBOutlet NSStepper * fTopStepper; - IBOutlet NSTextField * fBottomField1; - IBOutlet NSTextField * fBottomField2; - IBOutlet NSStepper * fBottomStepper; - IBOutlet NSTextField * fLeftField1; - IBOutlet NSTextField * fLeftField2; - IBOutlet NSStepper * fLeftStepper; - IBOutlet NSTextField * fRightField1; - IBOutlet NSTextField * fRightField2; - IBOutlet NSStepper * fRightStepper; - IBOutlet NSButton * fPreviousButton; - IBOutlet NSButton * fNextButton; - IBOutlet NSButton * fAutocropButton; - IBOutlet NSButton * fOpenGLCheck; - IBOutlet NSTextField * fInfoField; - IBOutlet NSButton * fCloseButton; - int fPicture; - - HBHandle * fHandle; - int fTitle; - int fTitleCount; - HBList * fTitleList; - float fPosition; - int fPass; - int fPassCount; - float fCurFrameRate; - float fAvgFrameRate; - int fRemainingTime; - int fResult; -} +- (void) UpdateUI: (NSTimer *) timer; +- (void) EnableUI: (bool) enable; -- (IBAction) ScanMatrixChanged: (id) sender; -- (IBAction) BrowseDVD: (id) sender; -- (void) BrowseDVDDone: (NSOpenPanel *) sheet - returnCode: (int) returnCode contextInfo: (void *) contextInfo; -- (IBAction) Scan: (id) sender; +- (IBAction) ShowScanPanel: (id) sender; - (IBAction) TitlePopUpChanged: (id) sender; +- (IBAction) ChapterPopUpChanged: (id) sender; + - (IBAction) FormatPopUpChanged: (id) sender; -- (IBAction) VideoMatrixChanged: (id) sender; -- (IBAction) AudioPopUpChanged: (id) sender; +- (IBAction) CodecsPopUpChanged: (id) sender; - (IBAction) BrowseFile: (id) sender; - (void) BrowseFileDone: (NSSavePanel *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo; + +- (IBAction) VideoMatrixChanged: (id) sender; +- (IBAction) QualitySliderChanged: (id) sender; + - (IBAction) ShowPicturePanel: (id) sender; -- (IBAction) ClosePanel: (id) sender; + +- (IBAction) EnableQueue: (id) sender; +- (IBAction) AddToQueue: (id) sender; +- (IBAction) ShowQueuePanel: (id) sender; + - (IBAction) Rip: (id) sender; - (void) OverwriteAlertDone: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo; +- (void) UpdateAlertDone: (NSWindow *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo; - (void) _Rip; - (IBAction) Cancel: (id) sender; - (void) _Cancel: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo; - (IBAction) Pause: (id) sender; -- (IBAction) Resume: (id) sender; - -- (IBAction) PreviousPicture: (id) sender; -- (IBAction) NextPicture: (id) sender; -- (IBAction) UpdatePicture: (id) sender; -- (IBAction) AutoCrop: (id) sender; -- (void) DetectDrives: (NSNotification *) notification; +- (IBAction) CalculateBitrate: (id) sender; +- (void) controlTextDidBeginEditing: (NSNotification *) notification; +- (void) controlTextDidEndEditing: (NSNotification *) notification; +- (void) controlTextDidChange: (NSNotification *) notification; -/* libhb callbacks */ -- (void) Scanning: (id) sender; -- (void) ScanDone: (id) sender; -- (void) Encoding: (id) sender; -- (void) RipDone: (id) sender; +- (IBAction) OpenHomepage: (id) sender; +- (IBAction) OpenForums: (id) sender; @end diff --git a/macosx/Controller.mm b/macosx/Controller.mm index eb53a9dd5..a4ba98afe 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -1,229 +1,488 @@ -/* $Id: Controller.mm,v 1.31 2004/04/21 21:21:17 titer Exp $ +/* $Id: Controller.mm,v 1.78 2005/11/04 13:09:41 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#include <paths.h> -#include <IOKit/IOKitLib.h> -#include <IOKit/IOBSD.h> -#include <IOKit/storage/IOMedia.h> -#include <IOKit/storage/IODVDMedia.h> - #include "Controller.h" -#define _(a) NSLocalizedString(a,nil) - -static void _Scanning( void * data, int title, int titleCount ); -static void _ScanDone( void * data, HBList * titleList ); -static void _Encoding( void * data, float position, int pass, - int passCount, float curFrameRate, - float avgFrameRate, int remainingTime ); -static void _RipDone( void * data, int result ); +#define _(a) NSLocalizedString(a,NULL) + +static int FormatSettings[3][4] = + { { HB_MUX_MP4 | HB_VCODEC_FFMPEG | HB_ACODEC_FAAC, + HB_MUX_MP4 | HB_VCODEC_X264 | HB_ACODEC_FAAC, + 0, + 0 }, + { HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_LAME, + HB_MUX_AVI | HB_VCODEC_FFMPEG | HB_ACODEC_AC3, + HB_MUX_AVI | HB_VCODEC_X264 | HB_ACODEC_LAME, + HB_MUX_AVI | HB_VCODEC_X264 | HB_ACODEC_AC3 }, + { HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_VORBIS, + HB_MUX_OGM | HB_VCODEC_FFMPEG | HB_ACODEC_LAME, + 0, + 0 } }; /******************************* * HBController implementation * *******************************/ @implementation HBController -- (void) applicationDidFinishLaunching: (NSNotification *) notification +- init { - /* Init libhb */ - HBCallbacks callbacks; - callbacks.data = self; - callbacks.scanning = _Scanning; - callbacks.scanDone = _ScanDone; - callbacks.encoding = _Encoding; - callbacks.ripDone = _RipDone; + self = [super init]; + fHandle = NULL; + return self; +} - fHandle = HBInit( 1, 0 ); - HBSetCallbacks( fHandle, callbacks ); +- (void) applicationDidFinishLaunching: (NSNotification *) notification +{ + int build; + char * version; - [fPictureGLView SetHandle: fHandle]; + /* Init libhb */ + fHandle = hb_init( HB_DEBUG_ALL, [[NSUserDefaults + standardUserDefaults] boolForKey:@"CheckForUpdates"] ); + + /* Init others controllers */ + [fScanController SetHandle: fHandle]; + [fPictureController SetHandle: fHandle]; + [fQueueController SetHandle: fHandle]; + + /* Call UpdateUI every 2/10 sec */ + [[NSRunLoop currentRunLoop] addTimer: [NSTimer + scheduledTimerWithTimeInterval: 0.2 target: self + selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE] + forMode: NSModalPanelRunLoopMode]; + + if( ( build = hb_check_update( fHandle, &version ) ) > -1 ) + { + /* Update available - tell the user */ + NSBeginInformationalAlertSheet( _( @"Update is available" ), + _( @"Go get it!" ), _( @"Discard" ), NULL, fWindow, self, + @selector( UpdateAlertDone:returnCode:contextInfo: ), + NULL, NULL, [NSString stringWithFormat: + _( @"HandBrake %s (build %d) is now available for download." ), + version, build] ); + return; + } - /* Detect drives mounted after the app is started */ - [[[NSWorkspace sharedWorkspace] notificationCenter] - addObserver: self selector: @selector( DetectDrives: ) - name: NSWorkspaceDidMountNotification object: nil]; + /* Show scan panel ASAP */ + [self performSelectorOnMainThread: @selector(ShowScanPanel:) + withObject: NULL waitUntilDone: NO]; } - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) app { - if( [[fRipRipButton title] compare: _( @"Cancel" ) ] - == NSOrderedSame ) + if( [[fRipButton title] isEqualToString: _( @"Cancel" )] ) { - [self Cancel: self]; + [self Cancel: NULL]; return NSTerminateCancel; } /* Clean up */ - HBClose( &fHandle ); - + hb_close( &fHandle ); return NSTerminateNow; } - (void) awakeFromNib { - /* Strings for the Scan view */ - [fScWelcomeField setStringValue: _( @"Welcome to HandBrake" )]; - [fScSelectField setStringValue: _( @"Select a DVD:" )]; - [fScDetectedCell setTitle: _( @"Detected volume" )]; - [fScDetectedPopUp removeAllItems]; - [fScFolderCell setTitle: _( @"DVD Folder" )]; - [fScBrowseButton setTitle: _( @"Browse" )]; - [fScStatusField setStringValue: @""]; - [fScOpenButton setTitle: _( @"Open" )]; - - /* Strings for the Rip view */ - /* General box */ - [fRipGeneralField setStringValue: _( @"General" )]; - [fRipTitleField setStringValue: _( @"DVD title" )]; - [fRipTitlePopUp removeAllItems]; - [fRipFormatField setStringValue: _( @"Output format" )]; - [fRipFormatPopUp removeAllItems]; - [fRipFormatPopUp addItemWithTitle: - _( @"MP4 file / MPEG-4 video / AAC audio" )]; - [fRipFormatPopUp addItemWithTitle: - _( @"AVI file / MPEG-4 video / MP3 audio" )]; - [fRipFormatPopUp addItemWithTitle: - _( @"AVI file / H264 video / MP3 audio" )]; - [fRipFormatPopUp addItemWithTitle: - _( @"OGM file / MPEG-4 video / Vorbis audio" )]; - [fRipFileField1 setStringValue: _( @"File" )]; - [fRipFileField2 setStringValue: [NSString stringWithFormat: + [fWindow center]; + + [self TranslateStrings]; + + /* Destination box */ + [fDstFormatPopUp removeAllItems]; + [fDstFormatPopUp addItemWithTitle: _( @"MP4 file" )]; + [fDstFormatPopUp addItemWithTitle: _( @"AVI file" )]; + [fDstFormatPopUp addItemWithTitle: _( @"OGM file" )]; + [fDstFormatPopUp selectItemAtIndex: 0]; + + [self FormatPopUpChanged: NULL]; + + [fDstFile2Field setStringValue: [NSString stringWithFormat: @"%@/Desktop/Movie.mp4", NSHomeDirectory()]]; - [fRipBrowseButton setTitle: _( @"Browse" )]; - - /* Video box */ - [fRipVideoField setStringValue: _( @"Video" )]; - [fRipEncoderField setStringValue: _( @"MPEG-4 encoder" )]; - [fRipEncoderPopUp removeAllItems]; - [fRipEncoderPopUp addItemWithTitle: @"FFmpeg"]; - [fRipEncoderPopUp addItemWithTitle: @"XviD"]; - [fRipBitrateField setStringValue: _( @"Bitrate" )]; - [fRipCustomCell setTitle: _( @"Custom (kbps)" )]; - [fRipCustomField setIntValue: 1024]; - [fRipTargetCell setTitle: _( @"Target size (MB)" )]; - [fRipTargetField setIntValue: 700]; - [fRipTwoPassCheck setTitle: _( @"2-pass encoding" )]; - [fRipCropButton setTitle: _( @"Crop & Scale..." )]; - - /* Audio box */ - [fRipAudioField setStringValue: _( @"Audio" )]; - [fRipLang1Field setStringValue: _( @"Language 1" )]; - [fRipLang1PopUp removeAllItems]; - [fRipLang2Field setStringValue: _( @"Language 2 (optional)" )]; - [fRipLang2PopUp removeAllItems]; - [fRipAudBitField setStringValue: _( @"Bitrate (kbps)" )]; - [fRipAudBitPopUp removeAllItems]; - [fRipAudBitPopUp addItemWithTitle: @"32"]; - [fRipAudBitPopUp addItemWithTitle: @"40"]; - [fRipAudBitPopUp addItemWithTitle: @"48"]; - [fRipAudBitPopUp addItemWithTitle: @"56"]; - [fRipAudBitPopUp addItemWithTitle: @"64"]; - [fRipAudBitPopUp addItemWithTitle: @"80"]; - [fRipAudBitPopUp addItemWithTitle: @"96"]; - [fRipAudBitPopUp addItemWithTitle: @"112"]; - [fRipAudBitPopUp addItemWithTitle: @"128"]; - [fRipAudBitPopUp addItemWithTitle: @"160"]; - [fRipAudBitPopUp addItemWithTitle: @"192"]; - [fRipAudBitPopUp addItemWithTitle: @"224"]; - [fRipAudBitPopUp addItemWithTitle: @"256"]; - [fRipAudBitPopUp addItemWithTitle: @"320"]; - [fRipAudBitPopUp selectItemWithTitle: @"128"]; + + /* Video encoder */ + [fVidEncoderPopUp removeAllItems]; + [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"]; + [fVidEncoderPopUp addItemWithTitle: @"XviD"]; + + /* Video quality */ + [fVidTargetSizeField setIntValue: 700]; + [fVidBitrateField setIntValue: 1000]; + [fVidQualityMatrix selectCell: fVidBitrateCell]; + [self VideoMatrixChanged: NULL]; + + /* Video framerate */ + [fVidRatePopUp removeAllItems]; + [fVidRatePopUp addItemWithTitle: _( @"Same as source" )]; + for( int i = 0; i < hb_video_rates_count; i++ ) + { + [fVidRatePopUp addItemWithTitle: + [NSString stringWithCString: hb_video_rates[i].string]]; + } + [fVidRatePopUp selectItemAtIndex: 0]; + + /* Audio bitrate */ + [fAudBitratePopUp removeAllItems]; + for( int i = 0; i < hb_audio_bitrates_count; i++ ) + { + [fAudBitratePopUp addItemWithTitle: + [NSString stringWithCString: hb_audio_bitrates[i].string]]; + } + [fAudBitratePopUp selectItemAtIndex: hb_audio_bitrates_default]; + + /* Audio samplerate */ + [fAudRatePopUp removeAllItems]; + for( int i = 0; i < hb_audio_rates_count; i++ ) + { + [fAudRatePopUp addItemWithTitle: + [NSString stringWithCString: hb_audio_rates[i].string]]; + } + [fAudRatePopUp selectItemAtIndex: hb_audio_rates_default]; /* Bottom */ - [fRipStatusField setStringValue: @""]; - [fRipInfoField setStringValue: @""]; - [fRipPauseButton setTitle: _( @"Pause" )]; - [fRipRipButton setTitle: _( @"Rip" )]; - - /* Strings for the crop panel */ - [fWidthField1 setStringValue: _( @"Picture width" )]; - [fDeinterlaceCheck setTitle: _( @"Deinterlace picture" )]; - [fTopField1 setStringValue: _( @"Top cropping" )]; - [fBottomField1 setStringValue: _( @"Bottom cropping" )]; - [fLeftField1 setStringValue: _( @"Left cropping" )]; - [fRightField1 setStringValue: _( @"Right cropping" )]; - [fPreviousButton setTitle: _( @"Previous" )]; - [fNextButton setTitle: _( @"Next" )]; - [fAutocropButton setTitle: _( @"Autocrop" )]; - [fOpenGLCheck setTitle: _( @"Useless OpenGL effects" )]; - [fInfoField setStringValue: @""]; - [fCloseButton setTitle: _( @"Close" )]; - - [self VideoMatrixChanged: self]; - - /* Show the scan view */ - [fWindow setContentSize: [fScView frame].size]; - [fWindow setContentView: fScView]; - [fWindow center]; + [fStatusField setStringValue: @""]; - /* Detect DVD drives */ - [self DetectDrives: nil]; - [self ScanMatrixChanged: self]; + [self EnableUI: NO]; + [fPauseButton setEnabled: NO]; + [fRipButton setEnabled: NO]; } -- (BOOL) windowShouldClose: (id) sender +- (void) TranslateStrings { - if( [[fRipRipButton title] compare: _( @"Cancel" ) ] - == NSOrderedSame ) + [fSrcDVD1Field setStringValue: _( @"DVD:" )]; + [fSrcTitleField setStringValue: _( @"Title:" )]; + [fSrcChapterField setStringValue: _( @"Chapters:" )]; + [fSrcChapterToField setStringValue: _( @"to" )]; + [fSrcDuration1Field setStringValue: _( @"Duration:" )]; + + [fDstFormatField setStringValue: _( @"File format:" )]; + [fDstCodecsField setStringValue: _( @"Codecs:" )]; + [fDstFile1Field setStringValue: _( @"File:" )]; + [fDstBrowseButton setTitle: _( @"Browse" )]; + + [fVidRateField setStringValue: _( @"Framerate (fps):" )]; + [fVidEncoderField setStringValue: _( @"Encoder:" )]; + [fVidQualityField setStringValue: _( @"Quality:" )]; +} + +/*********************************************************************** + * UpdateDockIcon + *********************************************************************** + * Shows a progression bar on the dock icon, filled according to + * 'progress' (0.0 <= progress <= 1.0). + * Called with progress < 0.0 or progress > 1.0, restores the original + * icon. + **********************************************************************/ +- (void) UpdateDockIcon: (float) progress +{ + NSImage * icon; + NSData * tiff; + NSBitmapImageRep * bmp; + uint32_t * pen; + int row_start, row_end; + int i, j; + + /* Get application original icon */ + icon = [NSImage imageNamed: @"NSApplicationIcon"]; + + if( progress < 0.0 || progress > 1.0 ) { - [self Cancel: self]; - return NO; + [NSApp setApplicationIconImage: icon]; + return; } - /* Stop the application when the user closes the window */ - [NSApp terminate: self]; - return YES; + /* Get it in a raw bitmap form */ + tiff = [icon TIFFRepresentationUsingCompression: + NSTIFFCompressionNone factor: 1.0]; + bmp = [NSBitmapImageRep imageRepWithData: tiff]; + + /* Draw the progression bar */ + /* It's pretty simple (ugly?) now, but I'm no designer */ + + row_start = 3 * (int) [bmp size].height / 4; + row_end = 7 * (int) [bmp size].height / 8; + + for( i = row_start; i < row_start + 2; i++ ) + { + pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] ); + for( j = 0; j < (int) [bmp size].width; j++ ) + { + pen[j] = 0x000000FF; /* Black */ + } + } + for( i = row_start + 2; i < row_end - 2; i++ ) + { + pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] ); + pen[0] = 0x000000FF; + pen[1] = 0x000000FF; + for( j = 2; j < (int) [bmp size].width - 2; j++ ) + { + if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) ) + { + pen[j] = 0xFF0000FF; /* Red */ + } + else + { + pen[j] = 0xFFFFFFFF; /* White */ + } + } + pen[j] = 0x000000FF; + pen[j+1] = 0x000000FF; + } + for( i = row_end - 2; i < row_end; i++ ) + { + pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] ); + for( j = 0; j < (int) [bmp size].width; j++ ) + { + pen[j] = 0x000000FF; /* Black */ + } + } + + /* Now update the dock icon */ + tiff = [bmp TIFFRepresentationUsingCompression: + NSTIFFCompressionNone factor: 1.0]; + icon = [[NSImage alloc] initWithData: tiff]; + [NSApp setApplicationIconImage: icon]; + [icon release]; } -- (IBAction) BrowseDVD: (id) sender +- (void) UpdateUI: (NSTimer *) timer { - /* Open a panel to let the user choose and update the text field */ - NSOpenPanel * panel = [NSOpenPanel openPanel]; + hb_state_t s; + hb_get_state( fHandle, &s ); + + switch( s.state ) + { + case HB_STATE_IDLE: + /* If the scan panel is currently showing, recheck for DVD + drives. The clean way would be to use + NSWorkspaceDidMountNotification, but for some reason the + notifications don't work when having the sheet attached */ + if( [fWindow attachedSheet] == fScanPanel ) + { + [fScanController DetectDrives: NULL]; + } + break; - [panel setAllowsMultipleSelection: NO]; - [panel setCanChooseFiles: NO]; - [panel setCanChooseDirectories: YES ]; + case HB_STATE_SCANNING: + [fScanController UpdateUI: &s]; + break; - [panel beginSheetForDirectory: nil file: nil types: nil - modalForWindow: fWindow modalDelegate: self - didEndSelector: @selector( BrowseDVDDone:returnCode:contextInfo: ) - contextInfo: nil]; +#define p s.param.scandone + case HB_STATE_SCANDONE: + { + hb_list_t * list; + hb_title_t * title; + + [fScanController UpdateUI: &s]; + + list = hb_get_titles( fHandle ); + + if( !hb_list_count( list ) ) + { + break; + } + + [fSrcTitlePopUp removeAllItems]; + for( int i = 0; i < hb_list_count( list ); i++ ) + { + title = (hb_title_t *) hb_list_item( list, i ); + [fSrcDVD2Field setStringValue: [NSString + stringWithUTF8String: title->dvd]]; + [fSrcTitlePopUp addItemWithTitle: [NSString + stringWithFormat: @"%d - %02dh%02dm%02ds", + title->index, title->hours, title->minutes, + title->seconds]]; + } + + [self TitlePopUpChanged: NULL]; + [self EnableUI: YES]; + [fPauseButton setEnabled: NO]; + [fRipButton setEnabled: YES]; + break; + } +#undef p + +#define p s.param.working + case HB_STATE_WORKING: + { + float progress_total; + NSMutableString * string; + + /* Update text field */ + string = [NSMutableString stringWithFormat: + _( @"Encoding: task %d of %d, %.2f %%" ), + p.job_cur, p.job_count, 100.0 * p.progress]; + if( p.seconds > -1 ) + { + [string appendFormat: + _( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)" ), + p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds]; + } + [fStatusField setStringValue: string]; + + /* Update slider */ + progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count; + [fRipIndicator setDoubleValue: 100.0 * progress_total]; + + /* Update dock icon */ + [self UpdateDockIcon: progress_total]; + + [fPauseButton setEnabled: YES]; + [fPauseButton setTitle: _( @"Pause" )]; + [fRipButton setEnabled: YES]; + [fRipButton setTitle: _( @"Cancel" )]; + break; + } +#undef p + + case HB_STATE_PAUSED: + [fStatusField setStringValue: _( @"Paused" )]; + [fPauseButton setEnabled: YES]; + [fPauseButton setTitle: _( @"Resume" )]; + [fRipButton setEnabled: YES]; + [fRipButton setTitle: _( @"Cancel" )]; + break; + + case HB_STATE_WORKDONE: + { + [self EnableUI: YES]; + [fStatusField setStringValue: _( @"Done." )]; + [fRipIndicator setDoubleValue: 0.0]; + [fRipButton setTitle: _( @"Rip" )]; + + /* Restore dock icon */ + [self UpdateDockIcon: -1.0]; + + [fPauseButton setEnabled: NO]; + [fPauseButton setTitle: _( @"Pause" )]; + [fRipButton setEnabled: YES]; + [fRipButton setTitle: _( @"Rip" )]; + + /* FIXME */ + hb_job_t * job; + while( ( job = hb_job( fHandle, 0 ) ) ) + { + hb_rem( fHandle, job ); + } + break; + } + } + + /* FIXME: we should only do that when necessary */ + if( [fQueueCheck state] == NSOnState ) + { + int count = hb_count( fHandle ); + if( count ) + { + [fQueueCheck setTitle: [NSString stringWithFormat: + @"Enable queue (%d task%s in queue)", + count, ( count > 1 ) ? "s" : ""]]; + } + else + { + [fQueueCheck setTitle: @"Enable queue (no task in queue)"]; + } + } + + [[NSRunLoop currentRunLoop] addTimer: [NSTimer + scheduledTimerWithTimeInterval: 0.2 target: self + selector: @selector( UpdateUI: ) userInfo: NULL repeats: FALSE] + forMode: NSModalPanelRunLoopMode]; } -- (void) BrowseDVDDone: (NSOpenPanel *) sheet - returnCode: (int) returnCode contextInfo: (void *) contextInfo +- (void) EnableUI: (bool) b { - if( returnCode == NSOKButton ) + NSControl * controls[] = + { fSrcDVD1Field, fSrcDVD2Field, fSrcTitleField, fSrcTitlePopUp, + fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField, + fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field, + fDstFormatField, fDstFormatPopUp, fDstCodecsField, + fDstCodecsPopUp, fDstFile1Field, fDstFile2Field, + fDstBrowseButton, fVidRateField, fVidRatePopUp, + fVidEncoderField, fVidEncoderPopUp, fVidQualityField, + fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp, + fAudLang1Field, fAudLang1PopUp, fAudLang2Field, fAudLang2PopUp, + fAudRateField, fAudRatePopUp, fAudBitrateField, + fAudBitratePopUp, fPictureButton }; + + for( unsigned i = 0; + i < sizeof( controls ) / sizeof( NSControl * ); i++ ) { - [fScFolderField setStringValue: - [[sheet filenames] objectAtIndex: 0]]; + if( [[controls[i] className] isEqualToString: @"NSTextField"] ) + { + NSTextField * tf = (NSTextField *) controls[i]; + if( ![tf isBezeled] ) + { + [tf setTextColor: b ? [NSColor controlTextColor] : + [NSColor disabledControlTextColor]]; + continue; + } + } + [controls[i] setEnabled: b]; } + + [self VideoMatrixChanged: NULL]; +} + +- (IBAction) ShowScanPanel: (id) sender +{ + [NSApp beginSheet: fScanPanel modalForWindow: fWindow + modalDelegate: NULL didEndSelector: NULL contextInfo: NULL]; + [NSApp runModalForWindow: fScanPanel]; + [NSApp endSheet: fScanPanel]; + [fScanPanel orderOut: self]; +} + +- (BOOL) windowShouldClose: (id) sender +{ + /* Stop the application when the user closes the window */ + [NSApp terminate: self]; + return YES; } - (IBAction) VideoMatrixChanged: (id) sender; { - if( ![fRipVideoMatrix isEnabled] ) - { - [fRipCustomField setEnabled: NO]; - [fRipTargetField setEnabled: NO]; - return; - } - - if( ![fRipVideoMatrix selectedRow] ) + bool target, bitrate, quality; + + target = bitrate = quality = false; + if( [fVidQualityMatrix isEnabled] ) { - [fRipCustomField setEnabled: YES]; - [fRipTargetField setEnabled: NO]; + switch( [fVidQualityMatrix selectedRow] ) + { + case 0: + target = true; + break; + case 1: + bitrate = true; + break; + case 2: + quality = true; + break; + } } - else + [fVidTargetSizeField setEnabled: target]; + [fVidBitrateField setEnabled: bitrate]; + [fVidQualitySlider setEnabled: quality]; + [fVidTwoPassCheck setEnabled: !quality && + [fVidQualityMatrix isEnabled]]; + if( quality ) { - [fRipCustomField setEnabled: NO]; - [fRipTargetField setEnabled: YES]; - [fRipTargetField UpdateBitrate]; + [fVidTwoPassCheck setState: NSOffState]; } + + [self QualitySliderChanged: sender]; + [self CalculateBitrate: sender]; +} + +- (IBAction) QualitySliderChanged: (id) sender +{ + [fVidConstantCell setTitle: [NSString stringWithFormat: + _( @"Constant quality: %.0f %%" ), 100.0 * + [fVidQualitySlider floatValue]]]; } - (IBAction) BrowseFile: (id) sender @@ -231,10 +490,10 @@ static void _RipDone( void * data, int result ); /* Open a panel to let the user choose and update the text field */ NSSavePanel * panel = [NSSavePanel savePanel]; - [panel beginSheetForDirectory: nil file: nil + [panel beginSheetForDirectory: NULL file: NULL modalForWindow: fWindow modalDelegate: self didEndSelector: @selector( BrowseFileDone:returnCode:contextInfo: ) - contextInfo: nil]; + contextInfo: NULL]; } - (void) BrowseFileDone: (NSSavePanel *) sheet @@ -242,146 +501,176 @@ static void _RipDone( void * data, int result ); { if( returnCode == NSOKButton ) { - [fRipFileField2 setStringValue: [sheet filename]]; - [self FormatPopUpChanged: self]; - } -} - -- (IBAction) Scan: (id) sender -{ - [fScMatrix setEnabled: NO]; - [fScDetectedPopUp setEnabled: NO]; - [fScFolderField setEnabled: NO]; - [fScBrowseButton setEnabled: NO]; - [fScProgress setIndeterminate: YES]; - [fScProgress startAnimation: self]; - [fScOpenButton setEnabled: NO]; - [fScStatusField setStringValue: _( @"Opening device..." )]; - - /* Ask libhb to start scanning the specified volume */ - if( ![fScMatrix selectedRow] ) - { - /* DVD drive */ - HBScanDVD( fHandle, - [[fScDetectedPopUp titleOfSelectedItem] cString], 0 ); - } - else - { - /* DVD folder */ - HBScanDVD( fHandle, - [[fScFolderField stringValue] cString], 0 ); + [fDstFile2Field setStringValue: [sheet filename]]; + [self FormatPopUpChanged: NULL]; } } - (IBAction) ShowPicturePanel: (id) sender { - HBTitle * title = (HBTitle*) - HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] ); - - [fPictureGLView SetTitle: title]; - - fPicture = 0; - [fPictureGLView ShowPicture: fPicture animate: HB_ANIMATE_NONE]; - - [fWidthStepper setValueWraps: NO]; - [fWidthStepper setIncrement: 16]; - [fWidthStepper setMinValue: 16]; - [fWidthStepper setMaxValue: title->outWidthMax]; - [fWidthStepper setIntValue: title->outWidth]; - [fWidthField2 setIntValue: title->outWidth]; - [fDeinterlaceCheck setState: - title->deinterlace ? NSOnState : NSOffState]; - [fTopStepper setValueWraps: NO]; - [fTopStepper setIncrement: 2]; - [fTopStepper setMinValue: 0]; - [fTopStepper setMaxValue: title->inHeight / 4]; - [fTopStepper setIntValue: title->topCrop]; - [fTopField2 setIntValue: title->topCrop]; - [fBottomStepper setValueWraps: NO]; - [fBottomStepper setIncrement: 2]; - [fBottomStepper setMinValue: 0]; - [fBottomStepper setMaxValue: title->inHeight / 4]; - [fBottomStepper setIntValue: title->bottomCrop]; - [fBottomField2 setIntValue: title->bottomCrop]; - [fLeftStepper setValueWraps: NO]; - [fLeftStepper setIncrement: 2]; - [fLeftStepper setMinValue: 0]; - [fLeftStepper setMaxValue: title->inWidth / 4]; - [fLeftStepper setIntValue: title->leftCrop]; - [fLeftField2 setIntValue: title->leftCrop]; - [fRightStepper setValueWraps: NO]; - [fRightStepper setIncrement: 2]; - [fRightStepper setMinValue: 0]; - [fRightStepper setMaxValue: title->inWidth / 4]; - [fRightStepper setIntValue: title->rightCrop]; - [fRightField2 setIntValue: title->rightCrop]; - - [fPreviousButton setEnabled: NO]; - [fNextButton setEnabled: YES]; - - [fInfoField setStringValue: [NSString stringWithFormat: - _( @"Final size: %dx%d" ), title->outWidth, title->outHeight] ]; + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t *) hb_list_item( list, + [fSrcTitlePopUp indexOfSelectedItem] ); /* Resize the panel */ NSSize newSize; - newSize.width = 42 + MAX( 720, title->outWidthMax ); - newSize.height = 165 + title->outHeightMax; + newSize.width = 246 + title->width; + newSize.height = 80 + title->height; [fPicturePanel setContentSize: newSize]; + [fPictureController SetTitle: title]; + [NSApp beginSheet: fPicturePanel modalForWindow: fWindow - modalDelegate: nil didEndSelector: nil contextInfo: nil]; + modalDelegate: NULL didEndSelector: NULL contextInfo: NULL]; [NSApp runModalForWindow: fPicturePanel]; [NSApp endSheet: fPicturePanel]; [fPicturePanel orderOut: self]; } -- (IBAction) ClosePanel: (id) sender +- (IBAction) ShowQueuePanel: (id) sender { - [NSApp stopModal]; + /* Update the OutlineView */ + [fQueueController Update: sender]; + + /* Show the panel */ + [NSApp beginSheet: fQueuePanel modalForWindow: fWindow + modalDelegate: NULL didEndSelector: NULL contextInfo: NULL]; + [NSApp runModalForWindow: fQueuePanel]; + [NSApp endSheet: fQueuePanel]; + [fQueuePanel orderOut: self]; } -- (IBAction) Rip: (id) sender +- (void) PrepareJob { - /* Rip or Cancel ? */ - if( [[fRipRipButton title] compare: _( @"Cancel" ) ] - == NSOrderedSame ) + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t *) hb_list_item( list, + [fSrcTitlePopUp indexOfSelectedItem] ); + hb_job_t * job = title->job; + + /* Chapter selection */ + job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1; + job->chapter_end = [fSrcChapterEndPopUp indexOfSelectedItem] + 1; + + /* Format and codecs */ + int format = [fDstFormatPopUp indexOfSelectedItem]; + int codecs = [fDstCodecsPopUp indexOfSelectedItem]; + job->mux = FormatSettings[format][codecs] & HB_MUX_MASK; + job->vcodec = FormatSettings[format][codecs] & HB_VCODEC_MASK; + job->acodec = FormatSettings[format][codecs] & HB_ACODEC_MASK; + + if( ( job->vcodec & HB_VCODEC_FFMPEG ) && + [fVidEncoderPopUp indexOfSelectedItem] > 0 ) { - [self Cancel: self]; - return; + job->vcodec = HB_VCODEC_XVID; + } + if( job->vcodec & HB_VCODEC_X264 ) + { + job->h264_13 = [fVidEncoderPopUp indexOfSelectedItem]; } - if( [fRipCustomField intValue] < 64 ) + /* Video settings */ + if( [fVidRatePopUp indexOfSelectedItem] > 0 ) { - NSBeginCriticalAlertSheet( _( @"Invalid video bitrate" ), - _( @"Ooops" ), nil, nil, fWindow, self, nil, nil, nil, - _( @"Video bitrate is too low." ) ); - return; + job->vrate = 27000000; + job->vrate_base = hb_video_rates[[fVidRatePopUp + indexOfSelectedItem]-1].rate; } - if( [fRipCustomField intValue] > 8192 ) + else { - NSBeginCriticalAlertSheet( _( @"Invalid video bitrate" ), - _( @"Ooops" ), nil, nil, fWindow, self, nil, nil, nil, - _( @"Video bitrate is too high." ) ); - return; + job->vrate = title->rate; + job->vrate_base = title->rate_base; } - if( [fRipLang1PopUp indexOfSelectedItem] == - [fRipLang2PopUp indexOfSelectedItem] ) + + switch( [fVidQualityMatrix selectedRow] ) { - NSBeginCriticalAlertSheet( _( @"Invalid secondary language" ), - _( @"Ooops" ), nil, nil, fWindow, self, nil, nil, nil, - _( @"You can't encode the same audio track twice." ) ); + case 0: + /* Target size. + Bitrate should already have been calculated and displayed + in fVidBitrateField, so let's just use it */ + case 1: + job->vquality = -1.0; + job->vbitrate = [fVidBitrateField intValue]; + break; + case 2: + job->vquality = [fVidQualitySlider floatValue]; + job->vbitrate = 0; + break; + } + + job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState ); + + /* Subtitle settings */ + job->subtitle = [fSubPopUp indexOfSelectedItem] - 1; + + /* Audio tracks */ + job->audios[0] = [fAudLang1PopUp indexOfSelectedItem] - 1; + job->audios[1] = [fAudLang2PopUp indexOfSelectedItem] - 1; + job->audios[2] = -1; + + /* Audio settings */ + job->arate = hb_audio_rates[[fAudRatePopUp + indexOfSelectedItem]].rate; + job->abitrate = hb_audio_bitrates[[fAudBitratePopUp + indexOfSelectedItem]].rate; +} + +- (IBAction) EnableQueue: (id) sender +{ + bool e = ( [fQueueCheck state] == NSOnState ); + [fQueueAddButton setHidden: !e]; + [fQueueShowButton setHidden: !e]; + [fRipButton setTitle: e ? @"Start" : @"Rip"]; +} + +- (IBAction) AddToQueue: (id) sender +{ + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t *) hb_list_item( list, + [fSrcTitlePopUp indexOfSelectedItem] ); + hb_job_t * job = title->job; + + [self PrepareJob]; + + /* Destination file */ + job->file = strdup( [[fDstFile2Field stringValue] UTF8String] ); + + if( [fVidTwoPassCheck state] == NSOnState ) + { + job->pass = 1; + hb_add( fHandle, job ); + job->pass = 2; + hb_add( fHandle, job ); + } + else + { + job->pass = 0; + hb_add( fHandle, job ); + } +} + +- (IBAction) Rip: (id) sender +{ + /* Rip or Cancel ? */ + if( [[fRipButton title] isEqualToString: _( @"Cancel" )] ) + { + [self Cancel: sender]; return; } + if( [fQueueCheck state] == NSOffState ) + { + [self AddToQueue: sender]; + } + if( [[NSFileManager defaultManager] fileExistsAtPath: - [fRipFileField2 stringValue]] ) + [fDstFile2Field stringValue]] ) { NSBeginCriticalAlertSheet( _( @"File already exists" ), - _( @"No" ), _( @"Yes" ), nil, fWindow, self, + _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self, @selector( OverwriteAlertDone:returnCode:contextInfo: ), - nil, nil, [NSString stringWithFormat: + NULL, NULL, [NSString stringWithFormat: _( @"Do you want to overwrite %@?" ), - [fRipFileField2 stringValue]] ); + [fDstFile2Field stringValue]] ); return; } @@ -397,70 +686,38 @@ static void _RipDone( void * data, int result ); } } -- (void) _Rip +- (void) UpdateAlertDone: (NSWindow *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo { - /* Get the specified title & audio track(s) */ - HBTitle * title = (HBTitle*) HBListItemAt( fTitleList, - [fRipTitlePopUp indexOfSelectedItem] ); - HBAudio * audio1 = (HBAudio*) HBListItemAt( title->audioList, - [fRipLang1PopUp indexOfSelectedItem] ); - HBAudio * audio2 = (HBAudio*) HBListItemAt( title->audioList, - [fRipLang2PopUp indexOfSelectedItem] ); - - /* Use user settings */ - title->file = strdup( [[fRipFileField2 stringValue] cString] ); - title->bitrate = [fRipCustomField intValue]; - title->twoPass = ( [fRipTwoPassCheck state] == NSOnState ); - - int format = [fRipFormatPopUp indexOfSelectedItem]; - int codec = [fRipEncoderPopUp indexOfSelectedItem]; - title->mux = ( !format ) ? HB_MUX_MP4 : ( ( format == 3 ) ? - HB_MUX_OGM : HB_MUX_AVI ); - title->codec = ( format == 2 ) ? HB_CODEC_X264 : ( ( !codec ) ? - HB_CODEC_FFMPEG : HB_CODEC_XVID ); - - audio1->outBitrate = [[fRipAudBitPopUp titleOfSelectedItem] - intValue]; - audio1->outCodec = ( !format ) ? HB_CODEC_AAC : ( ( format == 3 ) ? - HB_CODEC_VORBIS : HB_CODEC_MP3 );; - HBListAdd( title->ripAudioList, audio1 ); - if( audio2 ) - { - audio2->outBitrate = [[fRipAudBitPopUp - titleOfSelectedItem] intValue]; - audio2->outCodec = ( !format ) ? HB_CODEC_AAC : ( ( format == 3 ) ? - HB_CODEC_VORBIS : HB_CODEC_MP3 ); - HBListAdd( title->ripAudioList, audio2 ); + if( returnCode == NSAlertAlternateReturn ) + { + /* Show scan panel */ + [self performSelectorOnMainThread: @selector(ShowScanPanel:) + withObject: NULL waitUntilDone: NO]; + return; } - /* Disable interface */ - [fRipTitlePopUp setEnabled: NO]; - [fRipFormatPopUp setEnabled: NO]; - [fRipVideoMatrix setEnabled: NO]; - [fRipCustomField setEnabled: NO]; - [fRipTargetField setEnabled: NO]; - [fRipTwoPassCheck setEnabled: NO]; - [fRipCropButton setEnabled: NO]; - [fRipLang1PopUp setEnabled: NO]; - [fRipLang2PopUp setEnabled: NO]; - [fRipAudBitPopUp setEnabled: NO]; - [fRipFileField2 setEnabled: NO]; - [fRipEncoderPopUp setEnabled: NO]; - [fRipBrowseButton setEnabled: NO]; - [fRipPauseButton setEnabled: YES]; - [fRipRipButton setTitle: _( @"Cancel" )]; - [fRipProgress setIndeterminate: YES]; - [fRipProgress startAnimation: self];; + /* Go to HandBrake homepage and exit */ + [self OpenHomepage: NULL]; + [NSApp terminate: self]; +} +- (void) _Rip +{ /* Let libhb do the job */ - HBStartRip( fHandle, title ); + hb_start( fHandle ); + + /* Disable interface */ + [self EnableUI: NO]; + [fPauseButton setEnabled: NO]; + [fRipButton setEnabled: NO]; } - (IBAction) Cancel: (id) sender { NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ), - _( @"No" ), _( @"Yes" ), nil, fWindow, self, - @selector( _Cancel:returnCode:contextInfo: ), nil, nil, + _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self, + @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL, _( @"Encoding won't be recoverable." ) ); } @@ -469,500 +726,241 @@ static void _RipDone( void * data, int result ); { if( returnCode == NSAlertAlternateReturn ) { - if( [[fRipPauseButton title] compare: _( @"Resume" ) ] - == NSOrderedSame ) - { - HBResumeRip( fHandle ); - } - HBStopRip( fHandle ); + hb_stop( fHandle ); + [fPauseButton setEnabled: NO]; + [fRipButton setEnabled: NO]; } } - (IBAction) Pause: (id) sender { - if( [[fRipPauseButton title] compare: _( @"Resume" ) ] - == NSOrderedSame ) - { - [self Resume: self]; - return; - } - - [fRipPauseButton setTitle: _( @"Resume" )]; - HBPauseRip( fHandle ); -} - -- (IBAction) Resume: (id) sender -{ - [fRipPauseButton setTitle: _( @"Pause" )]; - HBResumeRip( fHandle ); -} - -- (IBAction) PreviousPicture: (id) sender -{ - fPicture--; - if( [fOpenGLCheck state] == NSOnState ) - { - [fPictureGLView ShowPicture: fPicture - animate: HB_ANIMATE_LEFT]; - } - else - { - [fPictureGLView ShowPicture: fPicture - animate: HB_ANIMATE_NONE]; - } - - [fPreviousButton setEnabled: ( fPicture > 0 )]; - [fNextButton setEnabled: YES]; -} + [fPauseButton setEnabled: NO]; + [fRipButton setEnabled: NO]; -- (IBAction) NextPicture: (id) sender -{ - fPicture++; - if( [fOpenGLCheck state] == NSOnState ) + if( [[fPauseButton title] isEqualToString: _( @"Resume" )] ) { - [fPictureGLView ShowPicture: fPicture - animate: HB_ANIMATE_RIGHT]; + hb_resume( fHandle ); } else { - [fPictureGLView ShowPicture: fPicture - animate: HB_ANIMATE_NONE]; + hb_pause( fHandle ); } - - [fPreviousButton setEnabled: YES]; - [fNextButton setEnabled: ( fPicture < 9 )]; } -- (IBAction) UpdatePicture: (id) sender -{ - HBTitle * title = (HBTitle*) - HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] ); - title->outWidth = [fWidthStepper intValue]; - title->deinterlace = ( [fDeinterlaceCheck state] == NSOnState ); - title->topCrop = [fTopStepper intValue]; - title->bottomCrop = [fBottomStepper intValue]; - title->leftCrop = [fLeftStepper intValue]; - title->rightCrop = [fRightStepper intValue]; - - [fPictureGLView ShowPicture: fPicture animate: HB_ANIMATE_NONE]; - - [fWidthStepper setIntValue: title->outWidth]; - [fTopStepper setIntValue: title->topCrop]; - [fBottomStepper setIntValue: title->bottomCrop]; - [fLeftStepper setIntValue: title->leftCrop]; - [fRightStepper setIntValue: title->rightCrop]; - [fWidthField2 setIntValue: [fWidthStepper intValue]]; - [fTopField2 setIntValue: [fTopStepper intValue]]; - [fBottomField2 setIntValue: [fBottomStepper intValue]]; - [fLeftField2 setIntValue: [fLeftStepper intValue]]; - [fRightField2 setIntValue: [fRightStepper intValue]]; - - [fInfoField setStringValue: [NSString stringWithFormat: - _( @"Final size: %dx%d" ), title->outWidth, title->outHeight]]; -} - -- (IBAction) AutoCrop: (id) sender -{ - HBTitle * title = (HBTitle*) - HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] ); - title->topCrop = title->autoTopCrop; - title->bottomCrop = title->autoBottomCrop; - title->leftCrop = title->autoLeftCrop; - title->rightCrop = title->autoRightCrop; - - [fPictureGLView ShowPicture: fPicture animate: HB_ANIMATE_NONE]; - - [fWidthStepper setIntValue: title->outWidth]; - [fTopStepper setIntValue: title->topCrop]; - [fBottomStepper setIntValue: title->bottomCrop]; - [fLeftStepper setIntValue: title->leftCrop]; - [fRightStepper setIntValue: title->rightCrop]; - [fWidthField2 setIntValue: [fWidthStepper intValue]]; - [fTopField2 setIntValue: [fTopStepper intValue]]; - [fBottomField2 setIntValue: [fBottomStepper intValue]]; - [fLeftField2 setIntValue: [fLeftStepper intValue]]; - [fRightField2 setIntValue: [fRightStepper intValue]]; - - [fInfoField setStringValue: [NSString stringWithFormat: - _( @"Final size: %dx%d" ), title->outWidth, title->outHeight]]; -} - -- (void) DetectDrives: (NSNotification *) notification +- (IBAction) TitlePopUpChanged: (id) sender { - /* Scan DVD drives (stolen from VLC) */ - io_object_t next_media; - mach_port_t master_port; - kern_return_t kern_result; - io_iterator_t media_iterator; - CFMutableDictionaryRef classes_to_match; - - kern_result = IOMasterPort( MACH_PORT_NULL, &master_port ); - if( kern_result != KERN_SUCCESS ) - { - return; - } + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t*) + hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); - classes_to_match = IOServiceMatching( kIODVDMediaClass ); - if( classes_to_match == NULL ) + /* Update chapter popups */ + [fSrcChapterStartPopUp removeAllItems]; + [fSrcChapterEndPopUp removeAllItems]; + for( int i = 0; i < hb_list_count( title->list_chapter ); i++ ) { - return; + [fSrcChapterStartPopUp addItemWithTitle: [NSString + stringWithFormat: @"%d", i + 1]]; + [fSrcChapterEndPopUp addItemWithTitle: [NSString + stringWithFormat: @"%d", i + 1]]; } + [fSrcChapterStartPopUp selectItemAtIndex: 0]; + [fSrcChapterEndPopUp selectItemAtIndex: + hb_list_count( title->list_chapter ) - 1]; + [self ChapterPopUpChanged: NULL]; - CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectableKey ), - kCFBooleanTrue ); - - kern_result = - IOServiceGetMatchingServices( master_port, classes_to_match, - &media_iterator ); - if( kern_result != KERN_SUCCESS ) + /* Update subtitle popups */ + hb_subtitle_t * subtitle; + [fSubPopUp removeAllItems]; + [fSubPopUp addItemWithTitle: @"None"]; + for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ ) { - return; - } - - NSMutableArray * drivesList; - drivesList = [NSMutableArray arrayWithCapacity: 1]; - - next_media = IOIteratorNext( media_iterator ); - if( next_media != NULL ) - { - char psz_buf[0x32]; - size_t dev_path_length; - CFTypeRef str_bsd_path; - do - { - str_bsd_path = - IORegistryEntryCreateCFProperty( next_media, - CFSTR( kIOBSDNameKey ), - kCFAllocatorDefault, - 0 ); - if( str_bsd_path == NULL ) - { - IOObjectRelease( next_media ); - continue; - } + subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i ); - snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' ); - dev_path_length = strlen( psz_buf ); - - if( CFStringGetCString( (CFStringRef) str_bsd_path, - (char*)&psz_buf + dev_path_length, - sizeof(psz_buf) - dev_path_length, - kCFStringEncodingASCII ) ) - { - [drivesList addObject: - [NSString stringWithCString: psz_buf]]; - } - - CFRelease( str_bsd_path ); - - IOObjectRelease( next_media ); - - } while( ( next_media = IOIteratorNext( media_iterator ) ) != NULL ); + /* We cannot use NSPopUpButton's addItemWithTitle because + it checks for duplicate entries */ + [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString: + subtitle->lang] action: NULL keyEquivalent: @""]; } + [fSubPopUp selectItemAtIndex: 0]; - IOObjectRelease( media_iterator ); - - [fScDetectedPopUp removeAllItems]; - for( unsigned i = 0; i < [drivesList count]; i++ ) + /* Update lang popups */ + hb_audio_t * audio; + [fAudLang1PopUp removeAllItems]; + [fAudLang2PopUp removeAllItems]; + [fAudLang1PopUp addItemWithTitle: _( @"None" )]; + [fAudLang2PopUp addItemWithTitle: _( @"None" )]; + for( int i = 0; i < hb_list_count( title->list_audio ); i++ ) { - [[fScDetectedPopUp menu] addItemWithTitle: - [drivesList objectAtIndex: i] action: nil - keyEquivalent: @""]; - } - [self ScanMatrixChanged: self]; -} + audio = (hb_audio_t *) hb_list_item( title->list_audio, i ); -- (IBAction) ScanMatrixChanged: (id) sender -{ - if( ![fScMatrix selectedRow] ) - { - [fScDetectedPopUp setEnabled: YES]; - [fScFolderField setEnabled: NO]; - [fScBrowseButton setEnabled: NO]; - [fScOpenButton setEnabled: ( [fScDetectedPopUp selectedItem] != nil )]; - } - else - { - [fScDetectedPopUp setEnabled: NO]; - [fScFolderField setEnabled: YES]; - [fScBrowseButton setEnabled: YES]; - [fScOpenButton setEnabled: YES]; + [[fAudLang1PopUp menu] addItemWithTitle: + [NSString stringWithCString: audio->lang] + action: NULL keyEquivalent: @""]; + [[fAudLang2PopUp menu] addItemWithTitle: + [NSString stringWithCString: audio->lang] + action: NULL keyEquivalent: @""]; } + [fAudLang1PopUp selectItemAtIndex: 1]; + [fAudLang2PopUp selectItemAtIndex: 0]; } -- (IBAction) TitlePopUpChanged: (id) sender +- (IBAction) ChapterPopUpChanged: (id) sender { - HBTitle * title = (HBTitle*) - HBListItemAt( fTitleList, [fRipTitlePopUp indexOfSelectedItem] ); + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t *) + hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); - [fRipLang1PopUp removeAllItems]; - [fRipLang2PopUp removeAllItems]; - - HBAudio * audio; - for( int i = 0; i < HBListCount( title->audioList ); i++ ) + hb_chapter_t * chapter; + int64_t duration = 0; + for( int i = [fSrcChapterStartPopUp indexOfSelectedItem]; + i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ ) { - audio = (HBAudio*) HBListItemAt( title->audioList, i ); - - /* We cannot use NSPopUpButton's addItemWithTitle because - it checks for duplicate entries */ - [[fRipLang1PopUp menu] addItemWithTitle: - [NSString stringWithCString: audio->language] - action: nil keyEquivalent: @""]; - [[fRipLang2PopUp menu] addItemWithTitle: - [NSString stringWithCString: audio->language] - action: nil keyEquivalent: @""]; + chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i ); + duration += chapter->duration; } - [fRipLang2PopUp addItemWithTitle: _( @"None" )]; - [fRipLang2PopUp selectItemWithTitle: _( @"None" )]; - [fRipLang2PopUp setEnabled: - ( HBListCount( title->audioList ) > 1 )]; + + duration /= 90000; /* pts -> seconds */ + [fSrcDuration2Field setStringValue: [NSString stringWithFormat: + @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60, + duration % 60]]; - [fRipTargetField SetHBTitle: title]; - if( [fRipVideoMatrix selectedRow] ) - { - [fRipTargetField UpdateBitrate]; - } + [self CalculateBitrate: sender]; } - (IBAction) FormatPopUpChanged: (id) sender { - /* Headers size changes depending on the format, so let's - recalculate the bitrate if necessary */ - if( [fRipVideoMatrix selectedRow] ) + NSString * string = [fDstFile2Field stringValue]; + int format = [fDstFormatPopUp indexOfSelectedItem]; + char * ext = NULL; + + /* Update the codecs popup */ + [fDstCodecsPopUp removeAllItems]; + switch( format ) { - [fRipTargetField UpdateBitrate]; + case 0: + ext = "mp4"; + [fDstCodecsPopUp addItemWithTitle: + _( @"MPEG-4 Video / AAC Audio" )]; + [fDstCodecsPopUp addItemWithTitle: + _( @"AVC/H.264 Video / AAC Audio" )]; + break; + case 1: + ext = "avi"; + [fDstCodecsPopUp addItemWithTitle: + _( @"MPEG-4 Video / MP3 Audio" )]; + [fDstCodecsPopUp addItemWithTitle: + _( @"MPEG-4 Video / AC-3 Audio" )]; + [fDstCodecsPopUp addItemWithTitle: + _( @"AVC/H.264 Video / MP3 Audio" )]; + [fDstCodecsPopUp addItemWithTitle: + _( @"AVC/H.264 Video / AC-3 Audio" )]; + break; + case 2: + ext = "ogm"; + [fDstCodecsPopUp addItemWithTitle: + _( @"MPEG-4 Video / Vorbis Audio" )]; + [fDstCodecsPopUp addItemWithTitle: + _( @"MPEG-4 Video / MP3 Audio" )]; + break; } + [self CodecsPopUpChanged: NULL]; /* Add/replace to the correct extension */ - NSString * string = [fRipFileField2 stringValue]; - int format = [fRipFormatPopUp indexOfSelectedItem]; if( [string characterAtIndex: [string length] - 4] == '.' ) { - [fRipFileField2 setStringValue: [NSString stringWithFormat: + [fDstFile2Field setStringValue: [NSString stringWithFormat: @"%@.%s", [string substringToIndex: [string length] - 4], - ( !format ) ? "mp4" : ( ( format == 3 ) ? - "ogm" : "avi" )]]; + ext]]; } else { - [fRipFileField2 setStringValue: [NSString stringWithFormat: - @"%@.%s", string, ( !format ) ? "mp4" : - ( ( format == 3 ) ? "ogm" : "avi" )]]; + [fDstFile2Field setStringValue: [NSString stringWithFormat: + @"%@.%s", string, ext]]; } +} - if( format == 2 ) +- (IBAction) CodecsPopUpChanged: (id) sender +{ + int format = [fDstFormatPopUp indexOfSelectedItem]; + int codecs = [fDstCodecsPopUp indexOfSelectedItem]; + + /* Update the encoder popup if necessary */ + if( ( FormatSettings[format][codecs] & HB_VCODEC_X264 ) && + [fVidEncoderPopUp numberOfItems] > 1 ) { - /* Can't set X264 bitrate */ - [fRipEncoderPopUp setEnabled: NO]; - [fRipVideoMatrix setEnabled: NO]; - [fRipTwoPassCheck setEnabled: NO]; + /* MPEG-4 -> H.264 */ + [fVidEncoderPopUp removeAllItems]; + [fVidEncoderPopUp addItemWithTitle: @"x264 (Main profile)"]; + [fVidEncoderPopUp addItemWithTitle: @"x264 (Baseline profile)"]; } - else if( format == 3 ) + else if( ( FormatSettings[format][codecs] & HB_VCODEC_FFMPEG ) && + [fVidEncoderPopUp numberOfItems] < 2 ) + { + /* H.264 -> MPEG-4 */ + [fVidEncoderPopUp removeAllItems]; + [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"]; + [fVidEncoderPopUp addItemWithTitle: @"XviD"]; + [fVidEncoderPopUp selectItemAtIndex: 0]; + } + + if( FormatSettings[format][codecs] & HB_ACODEC_AC3 ) { - [fRipEncoderPopUp setEnabled: YES]; - [fRipVideoMatrix setEnabled: YES]; - [fRipTwoPassCheck setEnabled: YES]; + /* AC-3 pass-through: disable samplerate and bitrate */ + [fAudRatePopUp setEnabled: NO]; + [fAudBitratePopUp setEnabled: NO]; } else { - [fRipEncoderPopUp setEnabled: YES]; - [fRipVideoMatrix setEnabled: YES]; - [fRipTwoPassCheck setEnabled: YES]; + [fAudRatePopUp setEnabled: YES]; + [fAudBitratePopUp setEnabled: YES]; } - [self VideoMatrixChanged: self]; + + [self CalculateBitrate: sender]; } -- (IBAction) AudioPopUpChanged: (id) sender +- (IBAction) CalculateBitrate: (id) sender { - /* Recalculate the bitrate */ - if( [fRipVideoMatrix selectedRow] ) + if( !fHandle || [fVidQualityMatrix selectedRow] != 0 ) { - [fRipTargetField UpdateBitrate]; + return; } + + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t *) hb_list_item( list, + [fSrcTitlePopUp indexOfSelectedItem] ); + hb_job_t * job = title->job; + + [self PrepareJob]; + + [fVidBitrateField setIntValue: hb_calc_bitrate( job, + [fVidTargetSizeField intValue] )]; } -/******************* - * libhb callbacks * - *******************/ -static void _Scanning( void * data, int title, int titleCount ) +- (void) controlTextDidBeginEditing: (NSNotification *) notification { - HBController * controller = (HBController*) data; - controller->fTitle = title; - controller->fTitleCount = titleCount; - [controller performSelectorOnMainThread: @selector(Scanning:) - withObject: nil waitUntilDone: YES]; + [self CalculateBitrate: NULL]; } -- (void) Scanning: (id) sender -{ - [fScProgress stopAnimation: self]; - [fScProgress setIndeterminate: NO]; - [fScProgress setDoubleValue: 100.0 * fTitle / fTitleCount]; - [fScStatusField setStringValue: [NSString stringWithFormat: - _( @"Scanning title %d of %d..." ), fTitle, fTitleCount]]; +- (void) controlTextDidEndEditing: (NSNotification *) notification +{ + [self CalculateBitrate: NULL]; } -static void _ScanDone( void * data, HBList * titleList ) +- (void) controlTextDidChange: (NSNotification *) notification { - HBController * controller = (HBController*) data; - controller->fTitleList = titleList; - [controller performSelectorOnMainThread: @selector(ScanDone:) - withObject: nil waitUntilDone: YES]; + [self CalculateBitrate: NULL]; } -- (void) ScanDone: (id) sender + +- (IBAction) OpenHomepage: (id) sender { - if( !fTitleList ) - { - [fScMatrix setEnabled: YES]; - [self ScanMatrixChanged: self]; - [fScProgress stopAnimation: self]; - [fScProgress setIndeterminate: NO]; - [fScOpenButton setEnabled: YES]; - [fScStatusField setStringValue: - _( @"Invalid volume, try again" ) ]; - return; - } + [[NSWorkspace sharedWorkspace] openURL: [NSURL + URLWithString:@"http://handbrake.m0k.org/"]]; +} - /* Show a temporary empty view while the window - resizing animation */ - [fWindow setContentView: fTempView ]; - - /* Actually resize it */ - NSRect newFrame; - newFrame = [NSWindow contentRectForFrameRect: [fWindow frame] - styleMask: [fWindow styleMask]]; - newFrame.origin.y += newFrame.size.height - - [fRipView frame].size.height; - newFrame.size.height = [fRipView frame].size.height; - newFrame.size.width = [fRipView frame].size.width; - newFrame = [NSWindow frameRectForContentRect: newFrame - styleMask: [fWindow styleMask]]; - [fWindow setFrame: newFrame display: YES animate: YES]; - - /* Show the new GUI */ - [fWindow setContentView: fRipView ]; - [fRipPauseButton setEnabled: NO]; - - [fRipTitlePopUp removeAllItems]; - HBTitle * title; - for( int i = 0; i < HBListCount( fTitleList ); i++ ) - { - title = (HBTitle*) HBListItemAt( fTitleList, i ); - [[fRipTitlePopUp menu] addItemWithTitle: - [NSString stringWithFormat: @"%d - %02dh%02dm%02ds", - title->title, title->hours, title->minutes, - title->seconds] action: nil keyEquivalent: @""]; - } - [self TitlePopUpChanged: self]; -} - -static void _Encoding( void * data, float position, int pass, - int passCount, float curFrameRate, - float avgFrameRate, int remainingTime ) -{ - HBController * controller = (HBController*) data; - controller->fPosition = position; - controller->fPass = pass; - controller->fPassCount = passCount; - controller->fCurFrameRate = curFrameRate; - controller->fAvgFrameRate = avgFrameRate; - controller->fRemainingTime = remainingTime; - [controller performSelectorOnMainThread: @selector(Encoding:) - withObject: nil waitUntilDone: YES]; -} -- (void) Encoding: (id) sender -{ - [fRipStatusField setStringValue: [NSString stringWithFormat: - _( @"Encoding: %.2f %% (pass %d of %d)" ), - 100.0 * fPosition, fPass, fPassCount]]; - [fRipInfoField setStringValue: [NSString stringWithFormat: - _( @"Speed: %.2f fps (avg %.2f fps), %02dh%02dm%02ds remaining" ), - fCurFrameRate, fAvgFrameRate, fRemainingTime / 3600, - ( fRemainingTime / 60 ) % 60, fRemainingTime % 60]]; - - [fRipProgress setIndeterminate: NO]; - [fRipProgress setDoubleValue: 100.0 * fPosition]; -} - -static void _RipDone( void * data, int result ) -{ - HBController * controller = (HBController*) data; - controller->fResult = result; - [controller performSelectorOnMainThread: @selector(RipDone:) - withObject: nil waitUntilDone: YES]; -} -- (void) RipDone: (id) sender -{ - [fRipTitlePopUp setEnabled: YES]; - [fRipFormatPopUp setEnabled: YES]; - [fRipVideoMatrix setEnabled: YES]; - [fRipTwoPassCheck setEnabled: YES]; - [fRipCropButton setEnabled: YES]; - [fRipLang1PopUp setEnabled: YES]; - [fRipLang2PopUp setEnabled: YES]; - [fRipAudBitPopUp setEnabled: YES]; - [fRipFileField2 setEnabled: YES]; - [fRipBrowseButton setEnabled: YES]; - [fRipEncoderPopUp setEnabled: YES]; - [fRipPauseButton setEnabled: NO]; - [fRipPauseButton setTitle: _( @"Pause" )]; - [fRipRipButton setTitle: _( @"Rip" )]; - [fRipProgress setIndeterminate: NO]; - [fRipProgress setDoubleValue: 0.0]; - [self VideoMatrixChanged: self]; - - switch( fResult ) - { - case HB_SUCCESS: - [fRipStatusField setStringValue: _( @"Rip completed." )]; - [fRipInfoField setStringValue: @""]; - NSBeep(); - [NSApp requestUserAttention: NSInformationalRequest]; - [NSApp beginSheet: fDonePanel - modalForWindow: fWindow modalDelegate: nil - didEndSelector: nil contextInfo: nil]; - [NSApp runModalForWindow: fDonePanel]; - [NSApp endSheet: fDonePanel]; - [fDonePanel orderOut: self]; - break; - case HB_CANCELED: - [fRipStatusField setStringValue: _( @"Canceled." )]; - [fRipInfoField setStringValue: @""]; - break; - case HB_ERROR_A52_SYNC: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: @"Corrupted AC3 data"]; - break; - case HB_ERROR_AVI_WRITE: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: @"Write error"]; - break; - case HB_ERROR_DVD_OPEN: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: @"Could not open the DVD"]; - break; - case HB_ERROR_DVD_READ: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: @"DVD read error"]; - break; - case HB_ERROR_MP3_INIT: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: - @"MP3 encoder initialization failed"]; - break; - case HB_ERROR_MP3_ENCODE: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: @"MP3 encoder failed"]; - break; - case HB_ERROR_MPEG4_INIT: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: - @"MPEG4 encoder initialization failed"]; - break; - default: - [fRipStatusField setStringValue: @"Error."]; - [fRipInfoField setStringValue: @"Unknown error"]; - } +- (IBAction) OpenForums: (id) sender +{ + [[NSWorkspace sharedWorkspace] openURL: [NSURL + URLWithString:@"http://handbrake.m0k.org/forum/"]]; } @end diff --git a/macosx/English.lproj/MainMenu.nib/classes.nib b/macosx/English.lproj/MainMenu.nib/classes.nib index b77248ae6..59629f07f 100644 --- a/macosx/English.lproj/MainMenu.nib/classes.nib +++ b/macosx/English.lproj/MainMenu.nib/classes.nib @@ -3,102 +3,85 @@ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { ACTIONS = { - AudioPopUpChanged = id; - AutoCrop = id; - BrowseDVD = id; + AddToQueue = id; BrowseFile = id; + CalculateBitrate = id; Cancel = id; - ClosePanel = id; - Encoding = id; + ChapterPopUpChanged = id; + CodecsPopUpChanged = id; + EnableQueue = id; FormatPopUpChanged = id; - NextPicture = id; + OpenForums = id; + OpenHomepage = id; Pause = id; - PreviousPicture = id; - Resume = id; + QualitySliderChanged = id; Rip = id; - RipDone = id; - Scan = id; - ScanDone = id; - ScanMatrixChanged = id; - Scanning = id; ShowPicturePanel = id; + ShowQueuePanel = id; + ShowScanPanel = id; TitlePopUpChanged = id; - UpdatePicture = id; VideoMatrixChanged = id; }; CLASS = HBController; LANGUAGE = ObjC; OUTLETS = { - fAutocropButton = NSButton; - fBottomField1 = NSTextField; - fBottomField2 = NSTextField; - fBottomStepper = NSStepper; - fCloseButton = NSButton; - fDeinterlaceCheck = NSButton; - fDonePanel = NSPanel; - fInfoField = NSTextField; - fLeftField1 = NSTextField; - fLeftField2 = NSTextField; - fLeftStepper = NSStepper; - fNextButton = NSButton; - fOpenGLCheck = NSButton; - fPictureGLView = HBPictureGLView; + fAddToQuButton = NSButton; + fAudBitrateField = NSTextField; + fAudBitratePopUp = NSPopUpButton; + fAudLang1Field = NSTextField; + fAudLang1PopUp = NSPopUpButton; + fAudLang2Field = NSTextField; + fAudLang2PopUp = NSPopUpButton; + fAudRateField = NSTextField; + fAudRatePopUp = NSPopUpButton; + fDstBrowseButton = NSButton; + fDstCodecsField = NSTextField; + fDstCodecsPopUp = NSPopUpButton; + fDstFile1Field = NSTextField; + fDstFile2Field = NSTextField; + fDstFormatField = NSTextField; + fDstFormatPopUp = NSPopUpButton; + fPauseButton = NSButton; + fPictureButton = NSButton; + fPictureController = PictureController; fPicturePanel = NSPanel; - fPreviousButton = NSButton; - fRightField1 = NSTextField; - fRightField2 = NSTextField; - fRightStepper = NSStepper; - fRipAudBitField = NSTextField; - fRipAudBitPopUp = NSPopUpButton; - fRipAudioField = NSTextField; - fRipBitrateField = NSTextField; - fRipBrowseButton = NSButton; - fRipCropButton = NSButton; - fRipCustomCell = NSButtonCell; - fRipCustomField = NSTextField; - fRipEncoderField = NSTextField; - fRipEncoderPopUp = NSPopUpButton; - fRipFileField1 = NSTextField; - fRipFileField2 = NSTextField; - fRipFormatField = NSTextField; - fRipFormatPopUp = NSPopUpButton; - fRipGeneralField = NSTextField; - fRipInfoField = NSTextField; - fRipLang1Field = NSTextField; - fRipLang1PopUp = NSPopUpButton; - fRipLang2Field = NSTextField; - fRipLang2PopUp = NSPopUpButton; - fRipPauseButton = NSButton; - fRipProgress = NSProgressIndicator; - fRipRipButton = NSButton; - fRipStatusField = NSTextField; - fRipTargetCell = NSButtonCell; - fRipTargetField = HBTargetSizeField; - fRipTitleField = NSTextField; - fRipTitlePopUp = NSPopUpButton; - fRipTwoPassCheck = NSButton; - fRipVideoField = NSTextField; - fRipVideoMatrix = NSMatrix; - fRipView = NSView; - fScBrowseButton = NSButton; - fScDetectedCell = NSButtonCell; - fScDetectedPopUp = NSPopUpButton; - fScFolderCell = NSButtonCell; - fScFolderField = NSTextField; - fScMatrix = NSMatrix; - fScOpenButton = NSButton; - fScProgress = NSProgressIndicator; - fScSelectField = NSTextField; - fScStatusField = NSTextField; - fScView = NSView; - fScWelcomeField = NSTextField; - fTempView = NSView; - fTopField1 = NSTextField; - fTopField2 = NSTextField; - fTopStepper = NSStepper; - fWidthField1 = NSTextField; - fWidthField2 = NSTextField; - fWidthStepper = NSStepper; + fQueueAddButton = NSButton; + fQueueCheck = NSButton; + fQueueController = QueueController; + fQueuePanel = NSPanel; + fQueueShowButton = NSButton; + fRipButton = NSButton; + fRipIndicator = NSProgressIndicator; + fScanController = ScanController; + fScanPanel = NSPanel; + fShowQuButton = NSButton; + fSrcChapterEndPopUp = NSPopUpButton; + fSrcChapterField = NSTextField; + fSrcChapterStartPopUp = NSPopUpButton; + fSrcChapterToField = NSTextField; + fSrcDVD1Field = NSTextField; + fSrcDVD2Field = NSTextField; + fSrcDuration1Field = NSTextField; + fSrcDuration2Field = NSTextField; + fSrcTitleField = NSTextField; + fSrcTitlePopUp = NSPopUpButton; + fStatusField = NSTextField; + fSubField = NSTextField; + fSubPopUp = NSPopUpButton; + fVidBitrateCell = NSButtonCell; + fVidBitrateField = NSTextField; + fVidConstantCell = NSButtonCell; + fVidEncoderField = NSTextField; + fVidEncoderPopUp = NSPopUpButton; + fVidGrayscaleCheck = NSButton; + fVidQualityField = NSTextField; + fVidQualityMatrix = NSMatrix; + fVidQualitySlider = NSSlider; + fVidRateField = NSTextField; + fVidRatePopUp = NSPopUpButton; + fVidTargetCell = NSButtonCell; + fVidTargetSizeField = NSTextField; + fVidTwoPassCheck = NSButton; fWindow = NSWindow; }; SUPERCLASS = NSObject; @@ -115,7 +98,82 @@ }; SUPERCLASS = NSTextField; }, - {CLASS = PictureGLView; LANGUAGE = ObjC; SUPERCLASS = NSOpenGLView; } + { + ACTIONS = { + ClosePanel = id; + NextPicture = id; + PreviousPicture = id; + SettingsChanged = id; + }; + CLASS = PictureController; + LANGUAGE = ObjC; + OUTLETS = { + fCropBottomField = NSTextField; + fCropBottomStepper = NSStepper; + fCropLeftField = NSTextField; + fCropLeftStepper = NSStepper; + fCropMatrix = NSMatrix; + fCropRightField = NSTextField; + fCropRightStepper = NSStepper; + fCropTopField = NSTextField; + fCropTopStepper = NSStepper; + fDeinterlaceCheck = NSButton; + fEffectsCheck = NSButton; + fHeightField = NSTextField; + fHeightStepper = NSStepper; + fInfoField = NSTextField; + fNextButton = NSButton; + fPictureGLView = HBPictureGLView; + fPrevButton = NSButton; + fRatioCheck = NSButton; + fWidthField = NSTextField; + fWidthStepper = NSStepper; + }; + SUPERCLASS = NSObject; + }, + {CLASS = PictureGLView; LANGUAGE = ObjC; SUPERCLASS = NSOpenGLView; }, + { + ACTIONS = {CheckChanged = id; ClosePanel = id; OpenPanel = id; }; + CLASS = PrefsController; + LANGUAGE = ObjC; + OUTLETS = {fPanel = NSPanel; fUpdateCheck = NSButton; }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = {ClosePanel = id; Remove = id; Update = id; }; + CLASS = QueueController; + LANGUAGE = ObjC; + OUTLETS = {fScrollView = NSScrollView; fTaskView = NSView; }; + SUPERCLASS = NSObject; + }, + { + ACTIONS = { + Browse = id; + Browse2 = id; + BrowseDone2 = id; + Cancel = id; + MatrixChanged = id; + Open = id; + }; + CLASS = ScanController; + LANGUAGE = ObjC; + OUTLETS = { + fBrowseButton = NSButton; + fCancelButton = NSButton; + fDetectedCell = NSButtonCell; + fDetectedPopUp = NSPopUpButton; + fFolderCell = NSButtonCell; + fFolderField = NSTextField; + fIndicator = NSProgressIndicator; + fMatrix = NSMatrix; + fOpenButton = NSButton; + fPanel = NSPanel; + fSelectString = NSTextField; + fStatusField = NSTextField; + fWindow = NSWindow; + }; + SUPERCLASS = NSObject; + } ); IBVersion = 1; }
\ No newline at end of file diff --git a/macosx/English.lproj/MainMenu.nib/info.nib b/macosx/English.lproj/MainMenu.nib/info.nib index 07d1cfa67..0854e6d3d 100644 --- a/macosx/English.lproj/MainMenu.nib/info.nib +++ b/macosx/English.lproj/MainMenu.nib/info.nib @@ -3,29 +3,24 @@ <plist version="1.0"> <dict> <key>IBDocumentLocation</key> - <string>37 177 381 380 0 0 1440 878 </string> + <string>73 30 382 380 0 0 1440 878 </string> <key>IBEditorPositions</key> <dict> <key>29</key> - <string>277 674 165 44 0 0 1440 878 </string> - <key>556</key> - <string>130 59 470 306 0 0 1440 878 </string> - <key>583</key> - <string>650 499 144 171 0 0 1440 878 </string> - <key>689</key> - <string>513 258 470 610 0 0 1440 878 </string> + <string>157 764 261 44 0 0 1280 832 </string> </dict> <key>IBFramework Version</key> - <string>349.0</string> + <string>439.0</string> <key>IBOpenObjects</key> <array> - <integer>29</integer> <integer>365</integer> - <integer>583</integer> - <integer>434</integer> + <integer>1438</integer> <integer>21</integer> + <integer>29</integer> + <integer>1162</integer> + <integer>1348</integer> </array> <key>IBSystem Version</key> - <string>7F44</string> + <string>8F46</string> </dict> </plist> diff --git a/macosx/English.lproj/MainMenu.nib/keyedobjects.nib b/macosx/English.lproj/MainMenu.nib/keyedobjects.nib Binary files differnew file mode 100644 index 000000000..9d8af0121 --- /dev/null +++ b/macosx/English.lproj/MainMenu.nib/keyedobjects.nib diff --git a/macosx/English.lproj/MainMenu.nib/objects.nib b/macosx/English.lproj/MainMenu.nib/objects.nib Binary files differdeleted file mode 100644 index 5a2d37443..000000000 --- a/macosx/English.lproj/MainMenu.nib/objects.nib +++ /dev/null diff --git a/macosx/HandBrake.icns b/macosx/HandBrake.icns Binary files differindex f1d08d36f..f81352be3 100644 --- a/macosx/HandBrake.icns +++ b/macosx/HandBrake.icns diff --git a/macosx/HandBrake.xcode/project.pbxproj b/macosx/HandBrake.xcode/project.pbxproj deleted file mode 100644 index c9ac3a6a3..000000000 --- a/macosx/HandBrake.xcode/project.pbxproj +++ /dev/null @@ -1,560 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 39; - objects = { - 080E96DCFE201CFB7F000001 = { - fileRef = 29B97318FDCFA39411CA2CEA; - isa = PBXBuildFile; - settings = { - }; - }; - 080E96DDFE201D6D7F000001 = { - children = ( - 4DF3C8CB052889CD00A80101, - 4DF3C8CC052889CD00A80101, - 4D85758E052B78E300C39CA9, - 4D85758F052B78E300C39CA9, - 4D358C000534A91300D654EB, - 4D358C010534A91300D654EB, - ); - isa = PBXGroup; - name = Classes; - refType = 4; - sourceTree = "<group>"; - }; - 089C165CFE840E0CC02AAC07 = { - children = ( - 089C165DFE840E0CC02AAC07, - ); - isa = PBXVariantGroup; - name = InfoPlist.strings; - refType = 4; - sourceTree = "<group>"; - }; - 089C165DFE840E0CC02AAC07 = { - fileEncoding = 10; - isa = PBXFileReference; - lastKnownFileType = text.plist.strings; - name = English; - path = English.lproj/InfoPlist.strings; - refType = 4; - sourceTree = "<group>"; - }; - 089C165EFE840E0CC02AAC07 = { - fileRef = 089C165CFE840E0CC02AAC07; - isa = PBXBuildFile; - settings = { - }; - }; -//080 -//081 -//082 -//083 -//084 -//100 -//101 -//102 -//103 -//104 - 1058C7A0FEA54F0111CA2CBB = { - children = ( - 1058C7A1FEA54F0111CA2CBB, - 4DEB2024052B055F00C39CA9, - 4DDE9724052B7B2B00C39CA9, - ); - isa = PBXGroup; - name = "Linked Frameworks"; - refType = 4; - sourceTree = "<group>"; - }; - 1058C7A1FEA54F0111CA2CBB = { - fallbackIsa = PBXFileReference; - isa = PBXFrameworkReference; - lastKnownFileType = wrapper.framework; - name = Cocoa.framework; - path = /System/Library/Frameworks/Cocoa.framework; - refType = 0; - sourceTree = "<absolute>"; - }; - 1058C7A2FEA54F0111CA2CBB = { - children = ( - 29B97325FDCFA39411CA2CEA, - 29B97324FDCFA39411CA2CEA, - ); - isa = PBXGroup; - name = "Other Frameworks"; - refType = 4; - sourceTree = "<group>"; - }; - 1058C7A3FEA54F0111CA2CBB = { - fileRef = 1058C7A1FEA54F0111CA2CBB; - isa = PBXBuildFile; - settings = { - }; - }; -//100 -//101 -//102 -//103 -//104 -//170 -//171 -//172 -//173 -//174 - 17587328FF379C6511CA2CBB = { - explicitFileType = wrapper.application; - fallbackIsa = PBXFileReference; - isa = PBXApplicationReference; - path = HandBrake.app; - refType = 3; - sourceTree = BUILT_PRODUCTS_DIR; - }; -//170 -//171 -//172 -//173 -//174 -//190 -//191 -//192 -//193 -//194 - 19C28FACFE9D520D11CA2CBB = { - children = ( - 17587328FF379C6511CA2CBB, - ); - isa = PBXGroup; - name = Products; - refType = 4; - sourceTree = "<group>"; - }; -//190 -//191 -//192 -//193 -//194 -//290 -//291 -//292 -//293 -//294 - 29B97313FDCFA39411CA2CEA = { - buildSettings = { - MACOSX_DEPLOYMENT_TARGET = 10.2; - SDKROOT = /Developer/SDKs/MacOSX10.2.7.sdk; - }; - buildStyles = ( - 4A9504CCFFE6A4B311CA0CBA, - 4A9504CDFFE6A4B311CA0CBA, - ); - hasScannedForEncodings = 1; - isa = PBXProject; - mainGroup = 29B97314FDCFA39411CA2CEA; - projectDirPath = ""; - targets = ( - 29B97326FDCFA39411CA2CEA, - ); - }; - 29B97314FDCFA39411CA2CEA = { - children = ( - 080E96DDFE201D6D7F000001, - 29B97315FDCFA39411CA2CEA, - 29B97317FDCFA39411CA2CEA, - 29B97323FDCFA39411CA2CEA, - 19C28FACFE9D520D11CA2CBB, - ); - isa = PBXGroup; - name = HandBrake; - path = ""; - refType = 4; - sourceTree = "<group>"; - }; - 29B97315FDCFA39411CA2CEA = { - children = ( - 29B97316FDCFA39411CA2CEA, - 4DFDC318054AC84C00151618, - ); - isa = PBXGroup; - name = "Other Sources"; - path = ""; - refType = 4; - sourceTree = "<group>"; - }; - 29B97316FDCFA39411CA2CEA = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.cpp.objcpp; - path = main.mm; - refType = 4; - sourceTree = "<group>"; - }; - 29B97317FDCFA39411CA2CEA = { - children = ( - 29B97318FDCFA39411CA2CEA, - 4D118405053054CD00C39CA9, - 089C165CFE840E0CC02AAC07, - ); - isa = PBXGroup; - name = Resources; - path = ""; - refType = 4; - sourceTree = "<group>"; - }; - 29B97318FDCFA39411CA2CEA = { - children = ( - 29B97319FDCFA39411CA2CEA, - ); - isa = PBXVariantGroup; - name = MainMenu.nib; - path = ""; - refType = 4; - sourceTree = "<group>"; - }; - 29B97319FDCFA39411CA2CEA = { - isa = PBXFileReference; - lastKnownFileType = wrapper.nib; - name = English; - path = English.lproj/MainMenu.nib; - refType = 4; - sourceTree = "<group>"; - }; - 29B97323FDCFA39411CA2CEA = { - children = ( - 1058C7A0FEA54F0111CA2CBB, - 1058C7A2FEA54F0111CA2CBB, - ); - isa = PBXGroup; - name = Frameworks; - path = ""; - refType = 4; - sourceTree = "<group>"; - }; - 29B97324FDCFA39411CA2CEA = { - fallbackIsa = PBXFileReference; - isa = PBXFrameworkReference; - lastKnownFileType = wrapper.framework; - name = AppKit.framework; - path = /System/Library/Frameworks/AppKit.framework; - refType = 0; - sourceTree = "<absolute>"; - }; - 29B97325FDCFA39411CA2CEA = { - fallbackIsa = PBXFileReference; - isa = PBXFrameworkReference; - lastKnownFileType = wrapper.framework; - name = Foundation.framework; - path = /System/Library/Frameworks/Foundation.framework; - refType = 0; - sourceTree = "<absolute>"; - }; - 29B97326FDCFA39411CA2CEA = { - buildPhases = ( - 29B97327FDCFA39411CA2CEA, - 29B97328FDCFA39411CA2CEA, - 29B9732BFDCFA39411CA2CEA, - 29B9732DFDCFA39411CA2CEA, - ); - buildSettings = { - FRAMEWORK_SEARCH_PATHS = ""; - GCC_TREAT_WARNINGS_AS_ERRORS = YES; - HEADER_SEARCH_PATHS = ""; - LIBRARY_SEARCH_PATHS = ""; - OPTIMIZATION_CFLAGS = "-O3"; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = "../core/libhb.a ../contrib/liba52/liba52.a ../contrib/libavcodec/libavcodec.a ../contrib/libdvdread/libdvdread.a ../contrib/libdvdcss/libdvdcss.a ../contrib/libfaac/libfaac.a ../contrib/libmp3lame/libmp3lame.a ../contrib/libmp4v2/libmp4v2.a ../contrib/libmpeg2/libmpeg2.a ../contrib/libvorbis/libvorbis.a ../contrib/libvorbis/libvorbisenc.a ../contrib/libogg/libogg.a ../contrib/libsamplerate/libsamplerate.a ../contrib/libx264/libx264.a ../contrib/libxvidcore/libxvidcore.a"; - PRODUCT_NAME = HandBrake; - SECTORDER_FLAGS = ""; - WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; - WRAPPER_EXTENSION = app; - }; - dependencies = ( - ); - isa = PBXApplicationTarget; - name = HandBrake; - productName = HandBrake; - productReference = 17587328FF379C6511CA2CBB; - productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> -<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> -<plist version=\"1.0\"> -<dict> - <key>CFBundleDevelopmentRegion</key> - <string>English</string> - <key>CFBundleDisplayName</key> - <string>HandBrake</string> - <key>CFBundleExecutable</key> - <string>HandBrake</string> - <key>CFBundleGetInfoString</key> - <string>0.6.2</string> - <key>CFBundleIconFile</key> - <string>HandBrake.icns</string> - <key>CFBundleIdentifier</key> - <string>org.m0k.handbrake</string> - <key>CFBundleInfoDictionaryVersion</key> - <string>6.0</string> - <key>CFBundleName</key> - <string>HandBrake</string> - <key>CFBundlePackageType</key> - <string>APPL</string> - <key>CFBundleShortVersionString</key> - <string>0.6.2</string> - <key>CFBundleSignature</key> - <string>HB##</string> - <key>CFBundleVersion</key> - <string>0.6.2</string> - <key>NSHumanReadableCopyright</key> - <string>By Eric Petit <[email protected]></string> - <key>NSMainNibFile</key> - <string>MainMenu</string> - <key>NSPrincipalClass</key> - <string>NSApplication</string> -</dict> -</plist> -"; - }; - 29B97327FDCFA39411CA2CEA = { - buildActionMask = 2147483647; - files = ( - 4D6615EA05288C2300A80101, - 4D857591052B78E300C39CA9, - 4D358C020534A91300D654EB, - 4DFDC319054AC84C00151618, - ); - isa = PBXHeadersBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - 29B97328FDCFA39411CA2CEA = { - buildActionMask = 2147483647; - files = ( - 080E96DCFE201CFB7F000001, - 089C165EFE840E0CC02AAC07, - 4D118406053054CD00C39CA9, - ); - isa = PBXResourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - 29B9732BFDCFA39411CA2CEA = { - buildActionMask = 2147483647; - files = ( - 29B9732CFDCFA39411CA2CEA, - 4DF3C8CE052889CD00A80101, - 4D857590052B78E300C39CA9, - 4D358C030534A91300D654EB, - ); - isa = PBXSourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - 29B9732CFDCFA39411CA2CEA = { - fileRef = 29B97316FDCFA39411CA2CEA; - isa = PBXBuildFile; - settings = { - ATTRIBUTES = ( - ); - }; - }; - 29B9732DFDCFA39411CA2CEA = { - buildActionMask = 2147483647; - files = ( - 1058C7A3FEA54F0111CA2CBB, - 4DEB2025052B055F00C39CA9, - 4DDE9725052B7B2B00C39CA9, - ); - isa = PBXFrameworksBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; -//290 -//291 -//292 -//293 -//294 -//4A0 -//4A1 -//4A2 -//4A3 -//4A4 - 4A9504CCFFE6A4B311CA0CBA = { - buildRules = ( - ); - buildSettings = { - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = "0.6.2"; - GCC_DYNAMIC_NO_PIC = YES; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - GCC_OPTIMIZATION_LEVEL = 3; - LIBRARY_SEARCH_PATHS = ../core; - OPTIMIZATION_CFLAGS = "-O0"; - ZERO_LINK = NO; - }; - isa = PBXBuildStyle; - name = Development; - }; - 4A9504CDFFE6A4B311CA0CBA = { - buildRules = ( - ); - buildSettings = { - COPY_PHASE_STRIP = YES; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - ZERO_LINK = NO; - }; - isa = PBXBuildStyle; - name = Deployment; - }; -//4A0 -//4A1 -//4A2 -//4A3 -//4A4 -//4D0 -//4D1 -//4D2 -//4D3 -//4D4 - 4D118405053054CD00C39CA9 = { - isa = PBXFileReference; - lastKnownFileType = image.icns; - path = HandBrake.icns; - refType = 4; - sourceTree = "<group>"; - }; - 4D118406053054CD00C39CA9 = { - fileRef = 4D118405053054CD00C39CA9; - isa = PBXBuildFile; - settings = { - }; - }; - 4D358C000534A91300D654EB = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - path = TargetSizeField.h; - refType = 4; - sourceTree = "<group>"; - }; - 4D358C010534A91300D654EB = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.cpp.objcpp; - path = TargetSizeField.mm; - refType = 4; - sourceTree = "<group>"; - }; - 4D358C020534A91300D654EB = { - fileRef = 4D358C000534A91300D654EB; - isa = PBXBuildFile; - settings = { - }; - }; - 4D358C030534A91300D654EB = { - fileRef = 4D358C010534A91300D654EB; - isa = PBXBuildFile; - settings = { - }; - }; - 4D6615EA05288C2300A80101 = { - fileRef = 4DF3C8CB052889CD00A80101; - isa = PBXBuildFile; - settings = { - }; - }; - 4D85758E052B78E300C39CA9 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.cpp.objcpp; - path = PictureGLView.mm; - refType = 4; - sourceTree = "<group>"; - }; - 4D85758F052B78E300C39CA9 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - path = PictureGLView.h; - refType = 4; - sourceTree = "<group>"; - }; - 4D857590052B78E300C39CA9 = { - fileRef = 4D85758E052B78E300C39CA9; - isa = PBXBuildFile; - settings = { - }; - }; - 4D857591052B78E300C39CA9 = { - fileRef = 4D85758F052B78E300C39CA9; - isa = PBXBuildFile; - settings = { - }; - }; - 4DDE9724052B7B2B00C39CA9 = { - fallbackIsa = PBXFileReference; - isa = PBXFrameworkReference; - lastKnownFileType = wrapper.framework; - name = OpenGL.framework; - path = /System/Library/Frameworks/OpenGL.framework; - refType = 0; - sourceTree = "<absolute>"; - }; - 4DDE9725052B7B2B00C39CA9 = { - fileRef = 4DDE9724052B7B2B00C39CA9; - isa = PBXBuildFile; - settings = { - }; - }; - 4DEB2024052B055F00C39CA9 = { - fallbackIsa = PBXFileReference; - isa = PBXFrameworkReference; - lastKnownFileType = wrapper.framework; - name = IOKit.framework; - path = /System/Library/Frameworks/IOKit.framework; - refType = 0; - sourceTree = "<absolute>"; - }; - 4DEB2025052B055F00C39CA9 = { - fileRef = 4DEB2024052B055F00C39CA9; - isa = PBXBuildFile; - settings = { - }; - }; - 4DF3C8CB052889CD00A80101 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - path = Controller.h; - refType = 4; - sourceTree = "<group>"; - }; - 4DF3C8CC052889CD00A80101 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.cpp.objcpp; - path = Controller.mm; - refType = 4; - sourceTree = "<group>"; - }; - 4DF3C8CE052889CD00A80101 = { - fileRef = 4DF3C8CC052889CD00A80101; - isa = PBXBuildFile; - settings = { - }; - }; - 4DFDC318054AC84C00151618 = { - fileEncoding = 30; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = HandBrake.h; - path = ../core/HandBrake.h; - refType = 4; - sourceTree = "<group>"; - }; - 4DFDC319054AC84C00151618 = { - fileRef = 4DFDC318054AC84C00151618; - isa = PBXBuildFile; - settings = { - }; - }; - }; - rootObject = 29B97313FDCFA39411CA2CEA; -} diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj new file mode 100644 index 000000000..e733e1991 --- /dev/null +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -0,0 +1,502 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXBuildFile section */ + 4DD93F8F082036E8008E1322 /* Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DF3C8CB052889CD00A80101 /* Controller.h */; }; + 4DD93F90082036E8008E1322 /* PictureGLView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D85758F052B78E300C39CA9 /* PictureGLView.h */; }; + 4DD93F91082036E8008E1322 /* ScanController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D86C74F07281F4E007BA979 /* ScanController.h */; }; + 4DD93F92082036E8008E1322 /* PictureController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D1FD381073D19CE00E46515 /* PictureController.h */; }; + 4DD93F93082036E8008E1322 /* QueueController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD27BA507C0065C0023D231 /* QueueController.h */; }; + 4DD93F94082036E8008E1322 /* PrefsController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DE93A3507F5A2C900F3C78F /* PrefsController.h */; }; + 4DD93F96082036E8008E1322 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; }; + 4DD93F97082036E8008E1322 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 4DD93F98082036E8008E1322 /* HandBrake.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4D118405053054CD00C39CA9 /* HandBrake.icns */; }; + 4DD93F9A082036E8008E1322 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.mm */; settings = {ATTRIBUTES = (); }; }; + 4DD93F9B082036E8008E1322 /* Controller.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4DF3C8CC052889CD00A80101 /* Controller.mm */; }; + 4DD93F9C082036E8008E1322 /* PictureGLView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4D85758E052B78E300C39CA9 /* PictureGLView.mm */; }; + 4DD93F9D082036E8008E1322 /* ScanController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4D86C74E07281F4E007BA979 /* ScanController.mm */; }; + 4DD93F9E082036E8008E1322 /* PictureController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4D1FD382073D19CE00E46515 /* PictureController.mm */; }; + 4DD93F9F082036E8008E1322 /* QueueController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4DD27BA607C0065C0023D231 /* QueueController.mm */; }; + 4DD93FA0082036E8008E1322 /* PrefsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DE93A3607F5A2C900F3C78F /* PrefsController.m */; }; + 4DD93FA2082036E8008E1322 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + 4DD93FA3082036E8008E1322 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DEB2024052B055F00C39CA9 /* IOKit.framework */; }; + 4DD93FA4082036E8008E1322 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DDE9724052B7B2B00C39CA9 /* OpenGL.framework */; }; + 4DE09E63082038A400FB751F /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4DE09E62082038A400FB751F /* Info.plist */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildStyle section */ + 4A9504CCFFE6A4B311CA0CBA /* Development */ = { + isa = PBXBuildStyle; + buildSettings = { + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = "0.7.0"; + GCC_DYNAMIC_NO_PIC = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + LIBRARY_SEARCH_PATHS = ""; + ZERO_LINK = NO; + }; + name = Development; + }; + 4A9504CDFFE6A4B311CA0CBA /* Deployment */ = { + isa = PBXBuildStyle; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + ZERO_LINK = NO; + }; + name = Deployment; + }; +/* End PBXBuildStyle section */ + +/* Begin PBXFileReference section */ + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; }; + 29B97316FDCFA39411CA2CEA /* main.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; }; + 29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; }; + 4D118405053054CD00C39CA9 /* HandBrake.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = HandBrake.icns; sourceTree = "<group>"; }; + 4D1FD381073D19CE00E46515 /* PictureController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PictureController.h; sourceTree = "<group>"; }; + 4D1FD382073D19CE00E46515 /* PictureController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = PictureController.mm; sourceTree = "<group>"; }; + 4D85758E052B78E300C39CA9 /* PictureGLView.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = PictureGLView.mm; sourceTree = "<group>"; }; + 4D85758F052B78E300C39CA9 /* PictureGLView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PictureGLView.h; sourceTree = "<group>"; }; + 4D86C74E07281F4E007BA979 /* ScanController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = ScanController.mm; sourceTree = "<group>"; }; + 4D86C74F07281F4E007BA979 /* ScanController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ScanController.h; sourceTree = "<group>"; }; + 4DD27BA507C0065C0023D231 /* QueueController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = QueueController.h; sourceTree = SOURCE_ROOT; }; + 4DD27BA607C0065C0023D231 /* QueueController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = QueueController.mm; sourceTree = SOURCE_ROOT; }; + 4DD93FA6082036E8008E1322 /* HandBrake.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HandBrake.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4DDE9724052B7B2B00C39CA9 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; }; + 4DE09E62082038A400FB751F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = Info.plist; sourceTree = "<group>"; }; + 4DE93A3507F5A2C900F3C78F /* PrefsController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PrefsController.h; sourceTree = "<group>"; }; + 4DE93A3607F5A2C900F3C78F /* PrefsController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PrefsController.m; sourceTree = "<group>"; }; + 4DEB2024052B055F00C39CA9 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; }; + 4DF3C8CB052889CD00A80101 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; }; + 4DF3C8CC052889CD00A80101 /* Controller.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = Controller.mm; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4DD93FA1082036E8008E1322 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4DD93FA2082036E8008E1322 /* Cocoa.framework in Frameworks */, + 4DD93FA3082036E8008E1322 /* IOKit.framework in Frameworks */, + 4DD93FA4082036E8008E1322 /* OpenGL.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 4D1FD381073D19CE00E46515 /* PictureController.h */, + 4D1FD382073D19CE00E46515 /* PictureController.mm */, + 4DF3C8CB052889CD00A80101 /* Controller.h */, + 4DF3C8CC052889CD00A80101 /* Controller.mm */, + 4D86C74E07281F4E007BA979 /* ScanController.mm */, + 4D86C74F07281F4E007BA979 /* ScanController.h */, + 4D85758E052B78E300C39CA9 /* PictureGLView.mm */, + 4D85758F052B78E300C39CA9 /* PictureGLView.h */, + 4DD27BA507C0065C0023D231 /* QueueController.h */, + 4DD27BA607C0065C0023D231 /* QueueController.mm */, + 4DE93A3507F5A2C900F3C78F /* PrefsController.h */, + 4DE93A3607F5A2C900F3C78F /* PrefsController.m */, + ); + name = Classes; + sourceTree = "<group>"; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + 4DEB2024052B055F00C39CA9 /* IOKit.framework */, + 4DDE9724052B7B2B00C39CA9 /* OpenGL.framework */, + ); + name = "Linked Frameworks"; + sourceTree = "<group>"; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + ); + name = "Other Frameworks"; + sourceTree = "<group>"; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 4DD93FA6082036E8008E1322 /* HandBrake.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + 29B97314FDCFA39411CA2CEA /* HandBrake */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + 4DE09E62082038A400FB751F /* Info.plist */, + ); + name = HandBrake; + sourceTree = "<group>"; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 29B97316FDCFA39411CA2CEA /* main.mm */, + ); + name = "Other Sources"; + sourceTree = "<group>"; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */, + 4D118405053054CD00C39CA9 /* HandBrake.icns */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = "<group>"; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 4DD93F8E082036E8008E1322 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4DD93F8F082036E8008E1322 /* Controller.h in Headers */, + 4DD93F90082036E8008E1322 /* PictureGLView.h in Headers */, + 4DD93F91082036E8008E1322 /* ScanController.h in Headers */, + 4DD93F92082036E8008E1322 /* PictureController.h in Headers */, + 4DD93F93082036E8008E1322 /* QueueController.h in Headers */, + 4DD93F94082036E8008E1322 /* PrefsController.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 4DD93F8D082036E8008E1322 /* HandBrake */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4D4E7BC0087804870051572B /* Build configuration list for PBXNativeTarget "HandBrake" */; + buildPhases = ( + 4DD93F8E082036E8008E1322 /* Headers */, + 4DD93F95082036E8008E1322 /* Resources */, + 4DD93F99082036E8008E1322 /* Sources */, + 4DD93FA1082036E8008E1322 /* Frameworks */, + ); + buildRules = ( + ); + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ""; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ../libhb; + INFOPLIST_FILE = Info.plist; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + ../libhb/libhb.a, + ../contrib/lib/liba52.a, + ../contrib/lib/libavcodec.a, + ../contrib/lib/libavutil.a, + ../contrib/lib/libdvdread.a, + ../contrib/lib/libdvdcss.a, + ../contrib/lib/libfaac.a, + ../contrib/lib/libmp3lame.a, + ../contrib/lib/libmp4v2.a, + ../contrib/lib/libmpeg2.a, + ../contrib/lib/libvorbis.a, + ../contrib/lib/libvorbisenc.a, + ../contrib/lib/libogg.a, + ../contrib/lib/libsamplerate.a, + ../contrib/lib/libx264.a, + ../contrib/lib/libxvidcore.a, + ); + PRODUCT_NAME = HandBrake; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + WRAPPER_EXTENSION = app; + }; + dependencies = ( + ); + name = HandBrake; + productName = HandBrake; + productReference = 4DD93FA6082036E8008E1322 /* HandBrake.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 4D4E7BC4087804870051572B /* Build configuration list for PBXProject "HandBrake" */; + buildSettings = { + MACOSX_DEPLOYMENT_TARGET = 10.3; + SDKROOT = /Developer/SDKs/MacOSX10.3.9.sdk; + }; + buildStyles = ( + 4A9504CCFFE6A4B311CA0CBA /* Development */, + 4A9504CDFFE6A4B311CA0CBA /* Deployment */, + ); + hasScannedForEncodings = 1; + mainGroup = 29B97314FDCFA39411CA2CEA /* HandBrake */; + projectDirPath = ""; + targets = ( + 4DD93F8D082036E8008E1322 /* HandBrake */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 4DD93F95082036E8008E1322 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4DD93F96082036E8008E1322 /* MainMenu.nib in Resources */, + 4DD93F97082036E8008E1322 /* InfoPlist.strings in Resources */, + 4DD93F98082036E8008E1322 /* HandBrake.icns in Resources */, + 4DE09E63082038A400FB751F /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4DD93F99082036E8008E1322 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4DD93F9A082036E8008E1322 /* main.mm in Sources */, + 4DD93F9B082036E8008E1322 /* Controller.mm in Sources */, + 4DD93F9C082036E8008E1322 /* PictureGLView.mm in Sources */, + 4DD93F9D082036E8008E1322 /* ScanController.mm in Sources */, + 4DD93F9E082036E8008E1322 /* PictureController.mm in Sources */, + 4DD93F9F082036E8008E1322 /* QueueController.mm in Sources */, + 4DD93FA0082036E8008E1322 /* PrefsController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = "<group>"; + }; + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = { + isa = PBXVariantGroup; + children = ( + 29B97319FDCFA39411CA2CEA /* English */, + ); + name = MainMenu.nib; + sourceTree = "<group>"; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 4D4E7BC1087804870051572B /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = "0.7.0"; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ../libhb; + INFOPLIST_FILE = Info.plist; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + ../libhb/libhb.a, + ../contrib/lib/liba52.a, + ../contrib/lib/libavcodec.a, + ../contrib/lib/libavutil.a, + ../contrib/lib/libdvdread.a, + ../contrib/lib/libdvdcss.a, + ../contrib/lib/libfaac.a, + ../contrib/lib/libmp3lame.a, + ../contrib/lib/libmp4v2.a, + ../contrib/lib/libmpeg2.a, + ../contrib/lib/libvorbis.a, + ../contrib/lib/libvorbisenc.a, + ../contrib/lib/libogg.a, + ../contrib/lib/libsamplerate.a, + ../contrib/lib/libx264.a, + ../contrib/lib/libxvidcore.a, + ); + PRODUCT_NAME = HandBrake; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + WRAPPER_EXTENSION = app; + ZERO_LINK = NO; + }; + name = Development; + }; + 4D4E7BC2087804870051572B /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ../libhb; + INFOPLIST_FILE = Info.plist; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + ../libhb/libhb.a, + ../contrib/lib/liba52.a, + ../contrib/lib/libavcodec.a, + ../contrib/lib/libavutil.a, + ../contrib/lib/libdvdread.a, + ../contrib/lib/libdvdcss.a, + ../contrib/lib/libfaac.a, + ../contrib/lib/libmp3lame.a, + ../contrib/lib/libmp4v2.a, + ../contrib/lib/libmpeg2.a, + ../contrib/lib/libvorbis.a, + ../contrib/lib/libvorbisenc.a, + ../contrib/lib/libogg.a, + ../contrib/lib/libsamplerate.a, + ../contrib/lib/libx264.a, + ../contrib/lib/libxvidcore.a, + ); + PRODUCT_NAME = HandBrake; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + WRAPPER_EXTENSION = app; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 4D4E7BC3087804870051572B /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ""; + GCC_OPTIMIZATION_LEVEL = 3; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ../libhb; + INFOPLIST_FILE = Info.plist; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + ../libhb/libhb.a, + ../contrib/lib/liba52.a, + ../contrib/lib/libavcodec.a, + ../contrib/lib/libavutil.a, + ../contrib/lib/libdvdread.a, + ../contrib/lib/libdvdcss.a, + ../contrib/lib/libfaac.a, + ../contrib/lib/libmp3lame.a, + ../contrib/lib/libmp4v2.a, + ../contrib/lib/libmpeg2.a, + ../contrib/lib/libvorbis.a, + ../contrib/lib/libvorbisenc.a, + ../contrib/lib/libogg.a, + ../contrib/lib/libsamplerate.a, + ../contrib/lib/libx264.a, + ../contrib/lib/libxvidcore.a, + ); + PRODUCT_NAME = HandBrake; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + WRAPPER_EXTENSION = app; + }; + name = Default; + }; + 4D4E7BC5087804870051572B /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Development; + }; + 4D4E7BC6087804870051572B /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Deployment; + }; + 4D4E7BC7087804870051572B /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4D4E7BC0087804870051572B /* Build configuration list for PBXNativeTarget "HandBrake" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4D4E7BC1087804870051572B /* Development */, + 4D4E7BC2087804870051572B /* Deployment */, + 4D4E7BC3087804870051572B /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 4D4E7BC4087804870051572B /* Build configuration list for PBXProject "HandBrake" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4D4E7BC5087804870051572B /* Development */, + 4D4E7BC6087804870051572B /* Deployment */, + 4D4E7BC7087804870051572B /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/macosx/Info.plist b/macosx/Info.plist new file mode 100644 index 000000000..f7df901d4 --- /dev/null +++ b/macosx/Info.plist @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleDisplayName</key> + <string>HandBrake</string> + <key>CFBundleExecutable</key> + <string>HandBrake</string> + <key>CFBundleGetInfoString</key> + <string>0.7.0</string> + <key>CFBundleIconFile</key> + <string>HandBrake.icns</string> + <key>CFBundleIdentifier</key> + <string>org.m0k.handbrake</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>HandBrake</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>0.7.0</string> + <key>CFBundleSignature</key> + <string>HB##</string> + <key>CFBundleVersion</key> + <string>2005110400</string> + <key>NSHumanReadableCopyright</key> + <string>By Eric Petit <[email protected]></string> + <key>NSMainNibFile</key> + <string>MainMenu</string> + <key>NSPrincipalClass</key> + <string>NSApplication</string> +</dict> +</plist> diff --git a/macosx/PictureController.h b/macosx/PictureController.h new file mode 100644 index 000000000..3a279e133 --- /dev/null +++ b/macosx/PictureController.h @@ -0,0 +1,55 @@ +/* $Id: PictureController.h,v 1.6 2005/04/14 20:40:05 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include <Cocoa/Cocoa.h> + +#include "hb.h" +#include "PictureGLView.h" + +@interface PictureController : NSObject +{ + hb_handle_t * fHandle; + hb_title_t * fTitle; + + bool fHasQE; + uint8_t * fBuffer; + int fBufferSize; + uint8_t * fTexBuf[2]; + int fTexBufSize; + int fPicture; + + IBOutlet HBPictureGLView * fPictureGLView; + IBOutlet NSTextField * fWidthField; + IBOutlet NSStepper * fWidthStepper; + IBOutlet NSTextField * fHeightField; + IBOutlet NSStepper * fHeightStepper; + IBOutlet NSButton * fRatioCheck; + IBOutlet NSMatrix * fCropMatrix; + IBOutlet NSTextField * fCropTopField; + IBOutlet NSStepper * fCropTopStepper; + IBOutlet NSTextField * fCropBottomField; + IBOutlet NSStepper * fCropBottomStepper; + IBOutlet NSTextField * fCropLeftField; + IBOutlet NSStepper * fCropLeftStepper; + IBOutlet NSTextField * fCropRightField; + IBOutlet NSStepper * fCropRightStepper; + IBOutlet NSButton * fDeinterlaceCheck; + IBOutlet NSButton * fEffectsCheck; + IBOutlet NSButton * fPrevButton; + IBOutlet NSButton * fNextButton; + IBOutlet NSTextField * fInfoField; +} + +- (void) SetHandle: (hb_handle_t *) handle; +- (void) SetTitle: (hb_title_t *) title; +- (void) Display: (int) anim; + +- (IBAction) SettingsChanged: (id) sender; +- (IBAction) PreviousPicture: (id) sender; +- (IBAction) NextPicture: (id) sender; +- (IBAction) ClosePanel: (id) sender; + +@end diff --git a/macosx/PictureController.mm b/macosx/PictureController.mm new file mode 100644 index 000000000..f4e9d51d9 --- /dev/null +++ b/macosx/PictureController.mm @@ -0,0 +1,228 @@ +/* $Id: PictureController.mm,v 1.11 2005/08/01 15:10:44 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "PictureController.h" + +static int GetAlignedSize( int size ) +{ + int result = 1; + while( result < size ) + { + result *= 2; + } + return result; +} + +@implementation PictureController + +- (void) SetHandle: (hb_handle_t *) handle +{ + fHandle = handle; + + fHasQE = CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ); + + fBuffer = NULL; + fBufferSize = 0; + fTexBuf[0] = NULL; + fTexBuf[1] = NULL; + fTexBufSize = 0; + + [fWidthStepper setValueWraps: NO]; + [fWidthStepper setIncrement: 16]; + [fWidthStepper setMinValue: 16]; + [fHeightStepper setValueWraps: NO]; + [fHeightStepper setIncrement: 16]; + [fHeightStepper setMinValue: 16]; + + [fCropTopStepper setIncrement: 2]; + [fCropTopStepper setMinValue: 0]; + [fCropBottomStepper setIncrement: 2]; + [fCropBottomStepper setMinValue: 0]; + [fCropLeftStepper setIncrement: 2]; + [fCropLeftStepper setMinValue: 0]; + [fCropRightStepper setIncrement: 2]; + [fCropRightStepper setMinValue: 0]; +} + +- (void) SetTitle: (hb_title_t *) title +{ + hb_job_t * job = title->job; + + fTitle = title; + + /* Make sure we have big enough buffers */ + int newSize; + newSize = ( title->width + 2 ) * (title->height + 2 ) * 4; + if( fBufferSize < newSize ) + { + fBufferSize = newSize; + fBuffer = (uint8_t *) realloc( fBuffer, fBufferSize ); + } + if( !fHasQE ) + { + newSize = ( GetAlignedSize( title->width + 2 ) * + GetAlignedSize( title->height + 2 ) * 4 ); + } + if( fTexBufSize < newSize ) + { + fTexBufSize = newSize; + fTexBuf[0] = (uint8_t *) realloc( fTexBuf[0], fTexBufSize ); + fTexBuf[1] = (uint8_t *) realloc( fTexBuf[1], fTexBufSize ); + } + + [fWidthStepper setMaxValue: title->width]; + [fWidthStepper setIntValue: job->width]; + [fWidthField setIntValue: job->width]; + [fHeightStepper setMaxValue: title->height]; + [fHeightStepper setIntValue: job->height]; + [fHeightField setIntValue: job->height]; + [fRatioCheck setState: job->keep_ratio ? NSOnState : NSOffState]; + [fCropTopStepper setMaxValue: title->height/2-2]; + [fCropBottomStepper setMaxValue: title->height/2-2]; + [fCropLeftStepper setMaxValue: title->width/2-2]; + [fCropRightStepper setMaxValue: title->width/2-2]; + [fDeinterlaceCheck setState: job->deinterlace ? NSOnState : NSOffState]; + + fPicture = 0; + [self SettingsChanged: nil]; +} + +- (void) Display: (int) anim +{ + hb_get_preview( fHandle, fTitle, fPicture, fBuffer ); + + /* Backup previous picture (for effects) */ + memcpy( fTexBuf[1], fTexBuf[0], fTexBufSize ); + + if( fHasQE ) + { + /* Simply copy */ + memcpy( fTexBuf[0], fBuffer, fTexBufSize ); + } + else + { + /* Copy line by line */ + uint8_t * in = fBuffer; + uint8_t * out = fTexBuf[0]; + for( int i = fTitle->height + 2; i--; ) + { + memcpy( out, in, 4 * ( fTitle->width + 2 ) ); + in += 4 * ( fTitle->width + 2 ); + out += 4 * GetAlignedSize( fTitle->width + 2 ); + } + } + + if( [fEffectsCheck state] == NSOffState ) + { + anim = HB_ANIMATE_NONE; + } + else if( [[NSApp currentEvent] modifierFlags] & NSShiftKeyMask ) + { + anim |= HB_ANIMATE_SLOW; + } + + [fPictureGLView Display: anim buffer1: fTexBuf[0] + buffer2: fTexBuf[1] width: ( fTitle->width + 2 ) + height: ( fTitle->height + 2 )]; + + [fInfoField setStringValue: [NSString stringWithFormat: + @"Source %dx%d, output %dx%d", fTitle->width, fTitle->height, + fTitle->job->width, fTitle->job->height]]; + + [fPrevButton setEnabled: ( fPicture > 0 )]; + [fNextButton setEnabled: ( fPicture < 9 )]; +} + +- (IBAction) SettingsChanged: (id) sender +{ + hb_job_t * job = fTitle->job; + + job->width = [fWidthStepper intValue]; + job->height = [fHeightStepper intValue]; + job->keep_ratio = ( [fRatioCheck state] == NSOnState ); + job->deinterlace = ( [fDeinterlaceCheck state] == NSOnState ); + + bool autocrop = ( [fCropMatrix selectedRow] == 0 ); + [fCropTopStepper setEnabled: !autocrop]; + [fCropBottomStepper setEnabled: !autocrop]; + [fCropLeftStepper setEnabled: !autocrop]; + [fCropRightStepper setEnabled: !autocrop]; + if( autocrop ) + { + memcpy( job->crop, fTitle->crop, 4 * sizeof( int ) ); + } + else + { + job->crop[0] = [fCropTopStepper intValue]; + job->crop[1] = [fCropBottomStepper intValue]; + job->crop[2] = [fCropLeftStepper intValue]; + job->crop[3] = [fCropRightStepper intValue]; + } + + if( job->keep_ratio ) + { + if( sender == fWidthStepper || sender == fRatioCheck || + sender == fCropTopStepper || sender == fCropBottomStepper ) + { + hb_fix_aspect( job, HB_KEEP_WIDTH ); + if( job->height > fTitle->height ) + { + job->height = fTitle->height; + hb_fix_aspect( job, HB_KEEP_HEIGHT ); + } + } + else + { + hb_fix_aspect( job, HB_KEEP_HEIGHT ); + if( job->width > fTitle->width ) + { + job->width = fTitle->width; + hb_fix_aspect( job, HB_KEEP_WIDTH ); + } + } + } + + [fWidthStepper setIntValue: job->width]; + [fWidthField setIntValue: job->width]; + [fHeightStepper setIntValue: job->height]; + [fHeightField setIntValue: job->height]; + [fCropTopStepper setIntValue: job->crop[0]]; + [fCropTopField setIntValue: job->crop[0]]; + [fCropBottomStepper setIntValue: job->crop[1]]; + [fCropBottomField setIntValue: job->crop[1]]; + [fCropLeftStepper setIntValue: job->crop[2]]; + [fCropLeftField setIntValue: job->crop[2]]; + [fCropRightStepper setIntValue: job->crop[3]]; + [fCropRightField setIntValue: job->crop[3]]; + [self Display: HB_ANIMATE_NONE]; +} + +- (IBAction) PreviousPicture: (id) sender +{ + if( fPicture <= 0 ) + { + return; + } + fPicture--; + [self Display: HB_ANIMATE_BACKWARD]; +} + +- (IBAction) NextPicture: (id) sender +{ + if( fPicture >= 9 ) + { + return; + } + fPicture++; + [self Display: HB_ANIMATE_FORWARD]; +} + +- (IBAction) ClosePanel: (id) sender +{ + [NSApp stopModal]; +} + +@end diff --git a/macosx/PictureGLView.h b/macosx/PictureGLView.h index c558c3c0f..229d822ac 100644 --- a/macosx/PictureGLView.h +++ b/macosx/PictureGLView.h @@ -1,4 +1,4 @@ -/* $Id: PictureGLView.h,v 1.1.1.1 2003/11/03 12:03:51 titer Exp $ +/* $Id: PictureGLView.h,v 1.7 2005/08/01 15:10:44 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -6,29 +6,41 @@ #include <Cocoa/Cocoa.h> -#include "HandBrake.h" +#include "hb.h" -#define HB_ANIMATE_NONE 0 -#define HB_ANIMATE_LEFT 1 -#define HB_ANIMATE_RIGHT 2 +#define HB_ANIMATE_NONE 1 +#define HB_ANIMATE_BACKWARD 2 +#define HB_ANIMATE_FORWARD 4 +#define HB_ANIMATE_SLOW 8 @interface HBPictureGLView : NSOpenGLView { - HBHandle * fHandle; - HBTitle * fTitle; - - uint8_t * fPicture; - uint8_t * fOldPicture; + bool fHasQE; + unsigned long fTarget; + + int fWidth; + int fHeight; + int fTexWidth; + int fTexHeight; + float fCoordX; + float fCoordY; + + uint8_t * fBuffers[2]; + unsigned long fTextures[2]; + + int fLastEffect; + int fAnimDuration; + int fFrameRate; } - (id) initWithFrame: (NSRect) frame; - (void) reshape; - (void) drawRect: (NSRect) rect; -- (void) drawAnimation: (int) how; +- (void) drawAnimation: (int) anim; -- (void) SetHandle: (HBHandle*) handle; -- (void) SetTitle: (HBTitle*) title; -- (void) ShowPicture: (int) index animate: (int) how; +- (void) Display: (int) anim buffer1: (uint8_t *) buffer1 + buffer2: (uint8_t *) buffer2 width: (int) width + height: (int) height; @end diff --git a/macosx/PictureGLView.mm b/macosx/PictureGLView.mm index dbb641729..611fb3a86 100644 --- a/macosx/PictureGLView.mm +++ b/macosx/PictureGLView.mm @@ -1,4 +1,4 @@ -/* $Id: PictureGLView.mm,v 1.6 2004/03/08 12:39:49 titer Exp $ +/* $Id: PictureGLView.mm,v 1.18 2005/08/01 15:10:44 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -6,146 +6,35 @@ #include <OpenGL/OpenGL.h> #include <OpenGL/gl.h> +#include <OpenGL/glext.h> #include <math.h> #include "PictureGLView.h" -#define PROUT 2.5 - -/* XXX This file needs some serious cleaning XXX */ - -GLuint texture[2]; -float rotation; -float translation; -uint8_t * truc; - -@implementation HBPictureGLView - -- (void) SetHandle: (HBHandle*) handle -{ - fHandle = handle; -} - -- (void) SetTitle: (HBTitle*) title -{ - fTitle = title; - - /* This is needed as the view's size may have changed */ - [self clearGLContext]; - [self openGLContext]; -} - -- (void) ShowPicture: (int) index animate: (int) how +static int GetAlignedSize( int size ) { - if( fOldPicture ) free( fOldPicture ); - fOldPicture = fPicture; - - /* Get the picture */ - uint8_t * tmp = HBGetPreview( fHandle, fTitle, index ); - - /* Make it be upside-down */ - fPicture = (uint8_t*) malloc( 4 * ( fTitle->outWidthMax + 2 ) * - ( fTitle->outHeightMax + 2 ) ); - uint8_t * in = tmp; - uint8_t * out = fPicture + - 4 * ( fTitle->outWidthMax + 2 ) * ( fTitle->outHeightMax + 1 ); - for( int i = fTitle->outHeightMax + 2; i--; ) - { - memcpy( out, in, 4 * ( fTitle->outWidthMax + 2 ) ); - in += 4 * ( fTitle->outWidthMax + 2 ); - out -= 4 * ( fTitle->outWidthMax + 2 ); - } - free( tmp ); - - /* ARGB -> RGBA */ - uint32_t * p = (uint32_t*) fPicture; - for( int i = ( fTitle->outHeightMax + 2 ) * - ( fTitle->outWidthMax + 2 ); i--; ) + int result = 1; + while( result < size ) { - *(p++) = ( ( (*p) & 0x00FFFFFF ) << 8 ) | 0xFF; + result *= 2; } - - if( how == HB_ANIMATE_NONE ) - { - [self drawRect: [self bounds]]; - return; - } - - in = fOldPicture; - out = truc; - for( int i = fTitle->outHeightMax + 2; i--; ) - { - memcpy( out, in, ( fTitle->outWidthMax + 2 ) * 4 ); - in += ( fTitle->outWidthMax + 2 ) * 4; - out += 1024 * 4; - } - glBindTexture( GL_TEXTURE_2D, texture[0] ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1024, - 1024, 0, GL_RGBA, - GL_UNSIGNED_BYTE, truc ); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - - in = fPicture; - out = truc; - for( int i = fTitle->outHeightMax + 2; i--; ) - { - memcpy( out, in, ( fTitle->outWidthMax + 2 ) * 4 ); - in += ( fTitle->outWidthMax + 2 ) * 4; - out += 1024 * 4; - } - glBindTexture( GL_TEXTURE_2D, texture[1] ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 1024, - 1024, 0, GL_RGBA, - GL_UNSIGNED_BYTE, truc ); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - - glEnable( GL_TEXTURE_2D ); - glShadeModel( GL_SMOOTH ); - glClearColor( 0.0f, 0.0f, 0.0f, 0.5f ); - glClearDepth( 1.0f ); - glEnable( GL_DEPTH_TEST ); - glDepthFunc( GL_LEQUAL ); - glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); - -#define ANIMATION_TIME 500000 -#define FRAME_PER_SEC 50 - - rotation = 0.0; - float w = ( how == HB_ANIMATE_LEFT ) ? 1.0 : -1.0; - uint64_t date; - int64_t wait; - for( ;; ) - { - date = HBGetDate(); - translation = - PROUT - cos( rotation * M_PI / 180 ) * - ( 1 + w * tan( rotation * M_PI / 180 ) ); - [self drawAnimation: how]; - - rotation += w * 90 * 1000000 / ANIMATION_TIME / FRAME_PER_SEC; - if( w * rotation >= 90.0 ) - { - break; - } - - wait = 1000000 / FRAME_PER_SEC - ( HBGetDate() - date ); - if( wait > 0 ) - { - HBSnooze( wait ); - } - } - - [self drawRect: [self bounds]]; + return result; } +@implementation HBPictureGLView + - (id) initWithFrame: (NSRect) frame { - fHandle = NULL; - fTitle = NULL; - fPicture = NULL; - fOldPicture = NULL; + fHasQE = CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay ); + fTarget = fHasQE ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D; + + fBuffers[0] = NULL; + fBuffers[1] = NULL; + fWidth = 0; + fHeight = 0; + fLastEffect = -1; + GLuint attribs[] = { NSOpenGLPFANoRecovery, @@ -173,110 +62,368 @@ uint8_t * truc; [[self openGLContext] makeCurrentContext]; [self reshape]; - - glGenTextures( 2, texture ); - truc = (uint8_t*) malloc( 1024*1024*4 ); + glGenTextures( 2, fTextures ); return self; } -/* - * Resize ourself - */ - (void) reshape { - NSRect bounds; - - [[self openGLContext] update]; - bounds = [self bounds]; - if( fTitle ) - { - glViewport( 0, 0, fTitle->outWidthMax + 2, - fTitle->outHeightMax + 2 ); - } + NSRect bounds; + [[self openGLContext] update]; + [[self openGLContext] makeCurrentContext]; + bounds = [self bounds]; + glViewport( 0, 0, (int) bounds.size.width, + (int) bounds.size.height ); } -- (void) drawAnimation: (int) how +- (void) drawRect: (NSRect) rect { - /* Swap buffers only during the vertical retrace of the monitor. - http://developer.apple.com/documentation/GraphicsImaging/ - Conceptual/OpenGL/chap5/chapter_5_section_44.html */ - long params[] = { 1 }; - CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, - params ); + [[self openGLContext] makeCurrentContext]; + + glDisable( GL_DEPTH_TEST ); + glDisable( GL_CULL_FACE ); + glDisable( GL_BLEND ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + if( fBuffers[0] ) + { + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + glEnable( fTarget ); + glBindTexture( fTarget, fTextures[0] ); + glTexImage2D( fTarget, 0, GL_RGBA, fTexWidth, fTexHeight, 0, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, fBuffers[0] ); + glTexParameteri( fTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( fTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + glBegin( GL_QUADS ); + glTexCoord2f( 0.0 , 0.0 ); glVertex2f( -1.0, 1.0 ); + glTexCoord2f( 0.0 , fCoordY ); glVertex2f( -1.0, -1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex2f( 1.0, -1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex2f( 1.0, 1.0 ); + glEnd(); + } + [[self openGLContext] flushBuffer]; +} + +#define FRUSTUM_NEAR 2.5 +#define FRUSTUM_FAR 20.0 + +- (void) drawCube: (int) anim +{ + uint64_t date; + float w, rotation, translation; + + w = ( anim & HB_ANIMATE_BACKWARD ) ? 1.0 : -1.0; + + glEnable( GL_DEPTH_TEST ); + glEnable( GL_CULL_FACE ); + glDisable( GL_BLEND ); + + for( rotation = 0.0; w * rotation < 90.0; + rotation += w * 90 * 1000 / fAnimDuration / fFrameRate ) + { + date = hb_get_date(); + translation = - FRUSTUM_NEAR - cos( rotation * M_PI / 180 ) * + ( 1 + w * tan( rotation * M_PI / 180 ) ); + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, FRUSTUM_NEAR, FRUSTUM_FAR ); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, translation ); + glRotatef( rotation, 0.0, 1.0, 0.0 ); + + glBindTexture( fTarget, fTextures[0] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0 , 0.0 ); glVertex3f( -1.0, 1.0, 1.0 ); + glTexCoord2f( 0.0 , fCoordY ); glVertex3f( -1.0, -1.0, 1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex3f( 1.0, -1.0, 1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex3f( 1.0, 1.0, 1.0 ); + glEnd(); + + glBindTexture( fTarget, fTextures[1] ); + glBegin( GL_QUADS ); + if( anim & HB_ANIMATE_FORWARD ) + { + glTexCoord2f( 0.0, 0.0 ); glVertex3f( 1.0, 1.0, 1.0 ); + glTexCoord2f( 0.0, fCoordY ); glVertex3f( 1.0, -1.0, 1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex3f( 1.0, -1.0, -1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex3f( 1.0, 1.0, -1.0 ); + } + else + { + glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, 1.0, -1.0 ); + glTexCoord2f( 0.0, fCoordY ); glVertex3f( -1.0, -1.0, -1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex3f( -1.0, -1.0, 1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex3f( -1.0, 1.0, 1.0 ); + } + glEnd(); + + [[self openGLContext] flushBuffer]; + + hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) ); + } + +} + +- (void) drawSwap: (int) anim +{ + uint64_t date; + float w, rotation, x, z; + + w = ( anim & HB_ANIMATE_BACKWARD ) ? 1.0 : -1.0; + + glEnable( GL_DEPTH_TEST ); + glEnable( GL_CULL_FACE ); + glDisable( GL_BLEND ); + glMatrixMode( GL_PROJECTION ); glLoadIdentity(); - glFrustum( -1.0, 1.0, -1.0, 1.0, PROUT, 20.0 ); + glFrustum( -1.0, 1.0, -1.0, 1.0, FRUSTUM_NEAR, FRUSTUM_FAR ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); - glTranslatef( 0.0, 0.0, translation ); - glRotatef( rotation, 0.0, 1.0, 0.0 ); - - glEnable( GL_POLYGON_SMOOTH ); - glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST ); - - glBindTexture( GL_TEXTURE_2D, texture[0] ); - - glBegin( GL_QUADS ); - glTexCoord2f( 0.0, 0.0 ); - glVertex3f( -1.0, -1.0, 1.0 ); - glTexCoord2f( ( 2.0 + fTitle->outWidthMax ) / 1024, 0.0 ); - glVertex3f( 1.0, -1.0, 1.0 ); - glTexCoord2f( ( 2.0 + fTitle->outWidthMax ) / 1024, - ( 2.0 + fTitle->outHeightMax ) / 1024 ); - glVertex3f( 1.0, 1.0, 1.0 ); - glTexCoord2f( 0.0, ( 2.0 + fTitle->outHeightMax ) / 1024 ); - glVertex3f( -1.0, 1.0, 1.0 ); - glEnd(); - - glBindTexture( GL_TEXTURE_2D, texture[1] ); - - glBegin( GL_QUADS ); - if( how == HB_ANIMATE_RIGHT ) + glTranslatef( 0.0, 0.0, - FRUSTUM_NEAR - 1.0 ); + + for( rotation = 0.0; w * rotation < 180.0; + rotation += w * 180 * 1000 / fAnimDuration / fFrameRate ) + { + date = hb_get_date(); + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + x = 1.1 * sin( rotation * M_PI / 180 ); + z = cos( rotation * M_PI / 180 ); + + glBindTexture( fTarget, fTextures[0] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0 + x, 1.0, z ); + glTexCoord2f( 0.0, fCoordY ); glVertex3f( -1.0 + x, -1.0, z ); + glTexCoord2f( fCoordX, fCoordY ); glVertex3f( 1.0 + x, -1.0, z ); + glTexCoord2f( fCoordX, 0.0 ); glVertex3f( 1.0 + x, 1.0, z ); + glEnd(); + + glBindTexture( fTarget, fTextures[1] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0 - x, 1.0, - z ); + glTexCoord2f( 0.0, fCoordY ); glVertex3f( -1.0 - x, -1.0, - z ); + glTexCoord2f( fCoordX, fCoordY ); glVertex3f( 1.0 - x, -1.0, - z ); + glTexCoord2f( fCoordX, 0.0 ); glVertex3f( 1.0 - x, 1.0, - z ); + glEnd(); + + [[self openGLContext] flushBuffer]; + + hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) ); + } +} + +- (void) drawFade +{ + uint64_t date; + float alpha; + + glDisable( GL_DEPTH_TEST ); + glDisable( GL_CULL_FACE ); + glEnable( GL_BLEND ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + for( alpha = 0.0; alpha < 1.0; + alpha += 1000.0 / fAnimDuration / fFrameRate ) + { + date = hb_get_date(); + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glColor4f( 1.0, 1.0, 1.0, 1.0 - alpha ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + + glBindTexture( fTarget, fTextures[0] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 ); + glTexCoord2f( 0.0, fCoordY ); glVertex2f( -1.0, -1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex2f( 1.0, -1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex2f( 1.0, 1.0 ); + glEnd(); + + glColor4f( 1.0, 1.0, 1.0, alpha ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + + glBindTexture( fTarget, fTextures[1] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, 1.0 ); + glTexCoord2f( 0.0, fCoordY ); glVertex2f( -1.0, -1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex2f( 1.0, -1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex2f( 1.0, 1.0 ); + glEnd(); + + [[self openGLContext] flushBuffer]; + + hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) ); + } +} + +- (void) drawSlide: (int) anim +{ + uint64_t date; + float foo, w; + int left, right; + if( anim & HB_ANIMATE_FORWARD ) { - glTexCoord2f( 0.0, 0.0 ); - glVertex3f( 1.0, -1.0, 1.0 ); - glTexCoord2f( ( 2.0 + fTitle->outWidthMax ) / 1024, 0.0 ); - glVertex3f( 1.0, -1.0, -1.0 ); - glTexCoord2f( ( 2.0 + fTitle->outWidthMax ) / 1024, - ( 2.0 + fTitle->outHeightMax ) / 1024 ); - glVertex3f( 1.0, 1.0, -1.0 ); - glTexCoord2f( 0.0, ( 2.0 + fTitle->outHeightMax ) / 1024 ); - glVertex3f( 1.0, 1.0, 1.0 ); + left = 0; + right = 1; + w = 1.0; } else { - glTexCoord2f( 0.0, 0.0 ); - glVertex3f( -1.0, -1.0, -1.0 ); - glTexCoord2f( ( 2.0 + fTitle->outWidthMax ) / 1024, 0.0 ); - glVertex3f( -1.0, -1.0, 1.0 ); - glTexCoord2f( ( 2.0 + fTitle->outWidthMax ) / 1024, - ( 2.0 + fTitle->outHeightMax ) / 1024 ); - glVertex3f( -1.0, 1.0, 1.0 ); - glTexCoord2f( 0.0, ( 2.0 + fTitle->outHeightMax ) / 1024 ); - glVertex3f( -1.0, 1.0, -1.0 ); + left = 1; + right = 0; + w = -1.0; + } + + glDisable( GL_DEPTH_TEST ); + glDisable( GL_CULL_FACE ); + glDisable( GL_BLEND ); + + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + for( foo = w; foo >= -1.0 && foo <= 1.0; + foo -= w * 2000.0 / fAnimDuration / fFrameRate ) + { + date = hb_get_date(); + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glBindTexture( fTarget, fTextures[left] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0, 0.0 ); glVertex2f( foo - 2.0, 1.0 ); + glTexCoord2f( 0.0, fCoordY ); glVertex2f( foo - 2.0, -1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex2f( foo, -1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex2f( foo, 1.0 ); + glEnd(); + + glBindTexture( fTarget, fTextures[right] ); + glBegin( GL_QUADS ); + glTexCoord2f( 0.0, 0.0 ); glVertex2f( foo, 1.0 ); + glTexCoord2f( 0.0, fCoordY ); glVertex2f( foo, -1.0 ); + glTexCoord2f( fCoordX, fCoordY ); glVertex2f( foo + 2.0, -1.0 ); + glTexCoord2f( fCoordX, 0.0 ); glVertex2f( foo + 2.0, 1.0 ); + glEnd(); + + [[self openGLContext] flushBuffer]; + + hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) ); } - glEnd(); - - [[self openGLContext] flushBuffer]; } -- (void) drawRect: (NSRect) rect +#undef FRUSTUM_NEAR +#undef FRUSTUM_FAR + +- (void) drawAnimation: (int) anim +{ + glEnable( fTarget ); + + glBindTexture( fTarget, fTextures[0] ); + glTexImage2D( fTarget, 0, GL_RGBA, fTexWidth, fTexHeight, 0, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, fBuffers[1] ); + glTexParameteri( fTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( fTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + glBindTexture( fTarget, fTextures[1] ); + glTexImage2D( fTarget, 0, GL_RGBA, fTexWidth, fTexHeight, 0, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, fBuffers[0] ); + glTexParameteri( fTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( fTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + /* Draw a random animation, just making sure we don't use the same + effect two times in a row */ + int effect; + do + { + effect = hb_get_date() % 4; + } + while( effect == fLastEffect ); + + fAnimDuration = ( anim & HB_ANIMATE_SLOW ) ? 3000 : 600; + fFrameRate = 60.0; + + switch( effect ) + { + case 0: + [self drawCube: anim]; + break; + case 1: + [self drawSwap: anim]; + break; + case 2: + [self drawFade]; + break; + case 3: + [self drawSlide: anim]; + break; + } + + fLastEffect = effect; +} + +- (void) Display: (int) anim buffer1: (uint8_t *) buffer1 + buffer2: (uint8_t *) buffer2 width: (int) width height: (int) height { - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + [[self openGLContext] makeCurrentContext]; - if( !fPicture ) - { - return; - } + if( width != fWidth || height != fHeight ) + { + fWidth = width; + fHeight = height; + if( fHasQE ) + { + fTexWidth = fWidth; + fTexHeight = fHeight; + fCoordX = (float) fWidth; + fCoordY = (float) fHeight; + } + else + { + fTexWidth = GetAlignedSize( fWidth ); + fTexHeight = GetAlignedSize( fHeight ); + fCoordX = (float) fWidth / (float) fTexWidth; + fCoordY = (float) fHeight / (float) fTexHeight; + } + [self clearGLContext]; + [self openGLContext]; + [self reshape]; + } - glDrawPixels( fTitle->outWidthMax + 2, - fTitle->outHeightMax + 2, GL_RGBA, - GL_UNSIGNED_BYTE, fPicture ); + fBuffers[0] = buffer1; + fBuffers[1] = buffer2; - [[self openGLContext] flushBuffer]; + /* Swap buffers only during the vertical retrace of the monitor. + http://developer.apple.com/documentation/GraphicsImaging/ + Conceptual/OpenGL/chap5/chapter_5_section_44.html */ + long params[] = { 1 }; + CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, + params ); + + if( !( anim & HB_ANIMATE_NONE ) ) + { + [self drawAnimation: anim]; + } + + [self drawRect: [self bounds]]; } @end diff --git a/macosx/PrefsController.h b/macosx/PrefsController.h new file mode 100644 index 000000000..cdd960f89 --- /dev/null +++ b/macosx/PrefsController.h @@ -0,0 +1,15 @@ +/* PrefsController */ + +#include <Cocoa/Cocoa.h> + +@interface PrefsController : NSObject +{ + IBOutlet NSPanel * fPanel; + IBOutlet NSButton * fUpdateCheck; +} + +- (IBAction) OpenPanel: (id) sender; +- (IBAction) ClosePanel: (id) sender; +- (IBAction) CheckChanged: (id) sender; + +@end diff --git a/macosx/PrefsController.m b/macosx/PrefsController.m new file mode 100644 index 000000000..8e7c865e2 --- /dev/null +++ b/macosx/PrefsController.m @@ -0,0 +1,47 @@ +#import "PrefsController.h" + +@implementation PrefsController + +- (void) awakeFromNib +{ + NSUserDefaults * defaults; + NSDictionary * appDefaults; + + /* Unless the user specified otherwise, default is to check + for update */ + defaults = [NSUserDefaults standardUserDefaults]; + appDefaults = [NSDictionary dictionaryWithObject:@"YES" + forKey:@"CheckForUpdates"]; + [defaults registerDefaults: appDefaults]; + + /* Check or uncheck according to the preferences */ + [fUpdateCheck setState: [defaults boolForKey:@"CheckForUpdates"] ? + NSOnState : NSOffState]; +} + +- (IBAction) OpenPanel: (id) sender; +{ + [NSApp runModalForWindow: fPanel]; +} + +- (IBAction) ClosePanel: (id) sender; +{ + [NSApp stopModal]; + [fPanel orderOut: sender]; +} + +- (IBAction) CheckChanged: (id) sender +{ + NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; + + if( [fUpdateCheck state] == NSOnState ) + { + [defaults setObject:@"YES" forKey:@"CheckForUpdates"]; + } + else + { + [defaults setObject:@"NO" forKey:@"CheckForUpdates"]; + } +} + +@end diff --git a/macosx/QueueController.h b/macosx/QueueController.h new file mode 100644 index 000000000..635adc7b8 --- /dev/null +++ b/macosx/QueueController.h @@ -0,0 +1,18 @@ +/* QueueController */ + +#include <Cocoa/Cocoa.h> + +#include "hb.h" + +@interface QueueController : NSObject +{ + hb_handle_t * fHandle; + IBOutlet NSScrollView * fScrollView; + IBOutlet NSView * fTaskView; +} + +- (void) SetHandle: (hb_handle_t *) handle; +- (IBAction) Update: (id) sender; +- (IBAction) ClosePanel: (id) sender; + +@end diff --git a/macosx/QueueController.mm b/macosx/QueueController.mm new file mode 100644 index 000000000..e775bb33d --- /dev/null +++ b/macosx/QueueController.mm @@ -0,0 +1,120 @@ +#include "QueueController.h" + +@implementation QueueController + +- (void) SetHandle: (hb_handle_t *) handle +{ + fHandle = handle; +} + +- (void) AddTextField: (NSString *) string rect: (NSRect *) rect +{ + NSTextField * textField; + + rect->origin.x = 10; + rect->origin.y -= 17; + rect->size.height = 17; + textField = [[NSTextField alloc] initWithFrame: *rect]; + + [textField setEditable: NO]; + [textField setSelectable: NO]; + [textField setDrawsBackground: NO]; + [textField setBordered: NO]; + [textField setStringValue: string]; + + [fTaskView addSubview: textField]; +} + +- (void) removeTask: (id) sender +{ + hb_rem( fHandle, hb_job( fHandle, [sender tag] ) ); + [self performSelectorOnMainThread: @selector( Update: ) + withObject: sender waitUntilDone: NO]; +} + +- (void) AddButton: (NSRect *) rect tag: (int) tag +{ + NSButton * button; + + rect->origin.x = rect->size.width - 90; + rect->origin.y -= 20; + rect->size.width = 100; + rect->size.height = 20; + button = [[NSButton alloc] initWithFrame: *rect]; + rect->size.width = rect->origin.x + 90; + + [button setTitle: @"Remove"]; + [button setBezelStyle: NSRoundedBezelStyle]; + [button setFont: [NSFont systemFontOfSize: + [NSFont systemFontSizeForControlSize: NSSmallControlSize]]]; + [[button cell] setControlSize: NSSmallControlSize]; + + [button setTag: tag]; + [button setTarget: self]; + [button setAction: @selector( removeTask: )]; + + [fTaskView addSubview: button]; + + NSBox * box; + + rect->origin.x = 15; + rect->origin.y -= 10; + rect->size.width -= 10; + rect->size.height = 1; + box = [[NSBox alloc] initWithFrame: *rect]; + [box setBoxType: NSBoxSeparator]; + rect->origin.y -= 10; + rect->size.width += 10; + + [fTaskView addSubview: box]; +} + +- (IBAction) Update: (id) sender +{ + int i; + hb_job_t * j; + hb_title_t * title; + + NSSize size = [fScrollView contentSize]; + int height = MAX( 20 + 125 * hb_count( fHandle ), size.height ); + [fTaskView setFrame: NSMakeRect(0,0,size.width,height)]; + + NSRect rect = NSMakeRect(10,height-10,size.width-20,10); + + NSArray * subviews = [fTaskView subviews]; + while( [subviews count] > 0 ) + { + [[subviews objectAtIndex: 0] + removeFromSuperviewWithoutNeedingDisplay]; + } + + for( i = 0; i < hb_count( fHandle ); i++ ) + { + j = hb_job( fHandle, i ); + title = j->title; + + [self AddTextField: [NSString stringWithFormat: + @"DVD: %s", title->dvd] rect: &rect]; + [self AddTextField: [NSString stringWithFormat: + @"Title: %d", title->index] rect: &rect]; + [self AddTextField: [NSString stringWithFormat: + @"Chapters: %d to %d", j->chapter_start, j->chapter_end] + rect: &rect]; + [self AddTextField: [NSString stringWithFormat: + @"Pass: %d of %d", MAX( 1, j->pass ), MIN( 2, j->pass + 1 )] + rect: &rect]; + [self AddTextField: [NSString stringWithFormat: + @"Destination: %s", j->file] rect: &rect]; + [self AddButton: &rect tag: i]; + } + + [fTaskView scrollPoint: NSMakePoint(0,height)]; + [fTaskView setNeedsDisplay: YES]; +} + +- (IBAction) ClosePanel: (id) sender +{ + [NSApp stopModal]; +} + +@end diff --git a/macosx/ScanController.h b/macosx/ScanController.h new file mode 100644 index 000000000..d038e6eea --- /dev/null +++ b/macosx/ScanController.h @@ -0,0 +1,47 @@ +/* $Id: ScanController.h,v 1.4 2005/03/21 12:37:32 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include <Cocoa/Cocoa.h> + +#include "hb.h" + +@interface ScanController : NSObject +{ + hb_handle_t * fHandle; + + IBOutlet NSWindow * fWindow; + IBOutlet NSPanel * fPanel; + IBOutlet NSTextField * fSelectString; + IBOutlet NSMatrix * fMatrix; + IBOutlet NSButtonCell * fDetectedCell; + IBOutlet NSPopUpButton * fDetectedPopUp; + IBOutlet NSButtonCell * fFolderCell; + IBOutlet NSTextField * fFolderField; + IBOutlet NSButton * fBrowseButton; + IBOutlet NSTextField * fStatusField; + IBOutlet NSProgressIndicator * fIndicator; + IBOutlet NSButton * fCancelButton; + IBOutlet NSButton * fOpenButton; + + uint64_t fLastCheck; +} + +- (void) TranslateStrings; +- (void) SetHandle: (hb_handle_t *) handle; +- (void) DetectDrives: (NSNotification *) notification; +- (void) UpdateUI: (hb_state_t *) state; + +- (IBAction) MatrixChanged: (id) sender; +- (IBAction) Browse: (id) sender; +- (IBAction) Open: (id) sender; +- (IBAction) Cancel: (id) sender; + +- (void) Browse2: (id) sender; +- (void) BrowseDone: (NSOpenPanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo; +- (void) BrowseDone2: (id) sender; + +@end diff --git a/macosx/ScanController.mm b/macosx/ScanController.mm new file mode 100644 index 000000000..5a4075416 --- /dev/null +++ b/macosx/ScanController.mm @@ -0,0 +1,272 @@ +/* $Id: ScanController.mm,v 1.10 2005/04/27 21:05:24 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include <paths.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/IOBSD.h> +#include <IOKit/storage/IOMedia.h> +#include <IOKit/storage/IODVDMedia.h> + +#include "ScanController.h" + +#define _(a) NSLocalizedString(a,nil) + +@implementation ScanController + +- (void) TranslateStrings +{ + [fSelectString setStringValue: _( @"Select a DVD:" )]; + [fDetectedCell setTitle: _( @"Detected volume" )]; + [fFolderCell setTitle: _( @"DVD Folder / Image" )]; + [fBrowseButton setTitle: _( @"Browse" )]; + [fCancelButton setTitle: _( @"Cancel" )]; + [fOpenButton setTitle: _( @"Open" )]; +} + +- (void) SetHandle: (hb_handle_t *) handle +{ + fHandle = handle; + fLastCheck = 0; + + [self TranslateStrings]; + + [fStatusField setStringValue: @""]; +} + +- (void) DetectDrives: (NSNotification *) notification +{ + if( [fMatrix isEnabled] == NO ) + { + /* We're scanning */ + return; + } + if( hb_get_date() < fLastCheck + 1000 ) + { + /* Don't check more than every second */ + return; + } + fLastCheck = hb_get_date(); + + /* Scan DVD drives (stolen from VLC) */ + io_object_t next_media; + mach_port_t master_port; + kern_return_t kern_result; + io_iterator_t media_iterator; + CFMutableDictionaryRef classes_to_match; + + kern_result = IOMasterPort( MACH_PORT_NULL, &master_port ); + if( kern_result != KERN_SUCCESS ) + { + return; + } + + classes_to_match = IOServiceMatching( kIODVDMediaClass ); + if( classes_to_match == NULL ) + { + return; + } + + CFDictionarySetValue( classes_to_match, CFSTR( kIOMediaEjectableKey ), + kCFBooleanTrue ); + + kern_result = IOServiceGetMatchingServices( master_port, + classes_to_match, &media_iterator ); + if( kern_result != KERN_SUCCESS ) + { + return; + } + + NSMutableArray * drivesList; + drivesList = [NSMutableArray arrayWithCapacity: 1]; + + next_media = IOIteratorNext( media_iterator ); + if( next_media ) + { + char psz_buf[0x32]; + size_t dev_path_length; + CFTypeRef str_bsd_path; + do + { + str_bsd_path = + IORegistryEntryCreateCFProperty( next_media, + CFSTR( kIOBSDNameKey ), + kCFAllocatorDefault, + 0 ); + if( str_bsd_path == NULL ) + { + IOObjectRelease( next_media ); + continue; + } + + snprintf( psz_buf, sizeof(psz_buf), "%s%c", _PATH_DEV, 'r' ); + dev_path_length = strlen( psz_buf ); + + if( CFStringGetCString( (CFStringRef) str_bsd_path, + (char*)&psz_buf + dev_path_length, + sizeof(psz_buf) - dev_path_length, + kCFStringEncodingASCII ) ) + { + [drivesList addObject: + [NSString stringWithCString: psz_buf]]; + } + + CFRelease( str_bsd_path ); + + IOObjectRelease( next_media ); + + } while( ( next_media = IOIteratorNext( media_iterator ) ) ); + } + + IOObjectRelease( media_iterator ); + + [fDetectedPopUp removeAllItems]; + for( unsigned i = 0; i < [drivesList count]; i++ ) + { + [[fDetectedPopUp menu] addItemWithTitle: + [drivesList objectAtIndex: i] action: nil + keyEquivalent: @""]; + } + [self MatrixChanged: self]; +} + +- (void) EnableUI: (bool) b +{ + [fMatrix setEnabled: b]; + [fDetectedCell setEnabled: b]; + [fDetectedPopUp setEnabled: b]; + [fFolderCell setEnabled: b]; + [fFolderField setEnabled: b]; + [fBrowseButton setEnabled: b]; + [fOpenButton setEnabled: b]; + + if( b ) + { + [self MatrixChanged: nil]; + } +} + +- (void) UpdateUI: (hb_state_t *) s +{ + switch( s->state ) + { +#define p s->param.scanning + case HB_STATE_SCANNING: + [fStatusField setStringValue: [NSString stringWithFormat: + _( @"Scanning title %d of %d..." ), + p.title_cur, p.title_count]]; + [fIndicator setDoubleValue: 100.0 * ( p.title_cur - 1 ) / + p.title_count]; + break; +#undef p + + case HB_STATE_SCANDONE: + [self EnableUI: YES]; + [fIndicator setDoubleValue: 0.0]; + + if( hb_list_count( hb_get_titles( fHandle ) ) ) + { + /* Success */ + [fStatusField setStringValue: @""]; + [NSApp abortModal]; + } + else + { + [fStatusField setStringValue: + _( @"No valid title found." )]; + } + break; + } +} + +- (IBAction) MatrixChanged: (id) sender +{ + /* Do we have detected drives */ + if( [fDetectedPopUp numberOfItems] > 0 ) + { + [fDetectedCell setEnabled: YES]; + } + else + { + [fMatrix selectCell: fFolderCell]; + [fDetectedCell setEnabled: NO]; + } + + /* Enable controls related to the current choice */ + bool foo; + foo = ( [fMatrix selectedRow] == 0 ); + [fDetectedPopUp setEnabled: foo]; + [fFolderField setEnabled: !foo]; + [fBrowseButton setEnabled: !foo]; +} + +/* Browse: + Remove the current sheet (the scan panel) and show an OpenPanel. + Because we can't open the new sheet before the other one is + completely gone, we use performSelectorOnMainThread so it will be + done right afterwards */ +- (IBAction) Browse: (id) sender +{ + [NSApp stopModal]; + [self performSelectorOnMainThread: @selector( Browse2: ) + withObject: nil waitUntilDone: NO]; +} +- (void) Browse2: (id) sender +{ + NSOpenPanel * panel; + + panel = [NSOpenPanel openPanel]; + [panel setAllowsMultipleSelection: NO]; + [panel setCanChooseFiles: YES]; + [panel setCanChooseDirectories: YES ]; + + [panel beginSheetForDirectory: nil file: nil types: nil + modalForWindow: [NSApp mainWindow] modalDelegate: self + didEndSelector: @selector( BrowseDone:returnCode:contextInfo: ) + contextInfo: nil]; +} + +/* Get the folder and switch sheets again. Use the same trick as + above */ +- (void) BrowseDone: (NSOpenPanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + if( returnCode == NSOKButton ) + { + [fFolderField setStringValue: + [[sheet filenames] objectAtIndex: 0]]; + [self Open: nil]; + } + + [self performSelectorOnMainThread: @selector( BrowseDone2: ) + withObject: nil waitUntilDone: NO]; +} +- (void) BrowseDone2: (id) sender +{ + [NSApp beginSheet: fPanel modalForWindow: fWindow + modalDelegate: nil didEndSelector: nil contextInfo: nil]; + [NSApp runModalForWindow: fWindow]; + [NSApp endSheet: fPanel]; + [fPanel orderOut: self]; +} + +- (IBAction) Open: (id) sender +{ + NSString * path; + + [self EnableUI: NO]; + [fStatusField setStringValue: _( @"Opening..." )]; + + path = [fMatrix selectedRow] ? [fFolderField stringValue] : + [fDetectedPopUp titleOfSelectedItem]; + hb_scan( fHandle, [path UTF8String], 0 ); +} + +- (IBAction) Cancel: (id) sender +{ + [NSApp stopModal]; +} + +@end diff --git a/macosx/TargetSizeField.h b/macosx/TargetSizeField.h deleted file mode 100644 index d9396ee3a..000000000 --- a/macosx/TargetSizeField.h +++ /dev/null @@ -1,24 +0,0 @@ -/* $Id: TargetSizeField.h,v 1.3 2004/01/28 14:41:31 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include <Cocoa/Cocoa.h> - -#include "HandBrake.h" - -@interface HBTargetSizeField : NSTextField - -{ - HBTitle * fTitle; - IBOutlet NSPopUpButton * fRipFormatPopUp; - IBOutlet NSTextField * fRipCustomField; - IBOutlet NSPopUpButton * fRipLang2PopUp; - IBOutlet NSPopUpButton * fRipAudBitPopUp; -} - -- (void) SetHBTitle: (HBTitle *) title; -- (void) UpdateBitrate; - -@end diff --git a/macosx/TargetSizeField.mm b/macosx/TargetSizeField.mm deleted file mode 100644 index e113a4bf1..000000000 --- a/macosx/TargetSizeField.mm +++ /dev/null @@ -1,48 +0,0 @@ -/* $Id: TargetSizeField.mm,v 1.4 2004/01/28 14:41:31 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: <http://handbrake.m0k.org/>. - It may be used under the terms of the GNU General Public License. */ - -#include "TargetSizeField.h" - -@implementation HBTargetSizeField - -- (void) textDidBeginEditing: (NSNotification *) notification -{ - [self UpdateBitrate]; - [super textDidBeginEditing: notification]; -} - -- (void) textDidEndEditing: (NSNotification *) notification -{ - [self UpdateBitrate]; - [super textDidEndEditing: notification]; -} - -- (void) textDidChange: (NSNotification *) notification -{ - [self UpdateBitrate]; - [super textDidChange: notification]; -} - -- (void) SetHBTitle: (HBTitle*) title -{ - fTitle = title; -} - -- (void) UpdateBitrate -{ - int size = [self intValue]; - int format = [fRipFormatPopUp indexOfSelectedItem]; - int muxer = ( format == 0 ) ? HB_MUX_MP4 : ( ( format == 1 ) ? - HB_MUX_OGM : HB_MUX_AVI ); - int audioCount = ( [fRipLang2PopUp selectedItem] == - [fRipLang2PopUp lastItem] ) ? 1 : 2; - int audioBitrate = [[fRipAudBitPopUp titleOfSelectedItem] intValue]; - - [fRipCustomField setIntValue: HBGetBitrateForSize( fTitle, size, - muxer, audioCount, audioBitrate )]; -} - -@end diff --git a/macosx/genstrings.sh b/macosx/genstrings.sh index 38da1de92..3c3215777 100755 --- a/macosx/genstrings.sh +++ b/macosx/genstrings.sh @@ -1,6 +1,6 @@ #! /bin/sh rm -f genstrings.tmp -cat Controller.mm | grep -v "^#define.*_(" | \ +cat *.mm | grep -v "^#define.*_(" | \ sed 's/_( \(@"[^"]*"\) )/NSLocalizedString( \1, nil )/g' > \ genstrings.tmp genstrings genstrings.tmp diff --git a/macosx/i18n/Localizable.strings b/macosx/i18n/Localizable.strings Binary files differindex cbad7b524..d2415f302 100644 --- a/macosx/i18n/Localizable.strings +++ b/macosx/i18n/Localizable.strings diff --git a/macosx/i18n/fr.strings b/macosx/i18n/fr.strings Binary files differindex c1218f28c..a2841c40e 100644 --- a/macosx/i18n/fr.strings +++ b/macosx/i18n/fr.strings diff --git a/macosx/main.mm b/macosx/main.mm index bd649f8ba..78f659e03 100644 --- a/macosx/main.mm +++ b/macosx/main.mm @@ -1,10 +1,10 @@ -/* $Id: main.mm,v 1.1.1.1 2003/11/03 12:03:51 titer Exp $ +/* $Id: main.mm,v 1.2 2004/10/26 20:49:41 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. It may be used under the terms of the GNU General Public License. */ -#import <Cocoa/Cocoa.h> +#include <Cocoa/Cocoa.h> int main( int argc, const char ** argv ) { diff --git a/test/test.c b/test/test.c index 67b9450a9..3f250bc6c 100644 --- a/test/test.c +++ b/test/test.c @@ -1,4 +1,4 @@ -/* $Id: test.c,v 1.28 2004/03/22 19:18:57 titer Exp $ +/* $Id: test.c,v 1.81 2005/10/15 18:05:03 titer Exp $ This file is part of the HandBrake source code. Homepage: <http://handbrake.m0k.org/>. @@ -7,91 +7,446 @@ #include <signal.h> #include <getopt.h> -#include "HandBrake.h" +#include "hb.h" /* Options */ -static int verbose = 0; +static int debug = HB_DEBUG_NONE; +static int update = 0; static char * input = NULL; static char * output = NULL; static char * format = NULL; static int titleindex = 1; static int twoPass = 0; static int deinterlace = 0; -static int vcodec = HB_CODEC_FFMPEG; +static int grayscale = 0; +static int vcodec = HB_VCODEC_FFMPEG; static char * audios = NULL; +static int sub = 0; static int width = 0; -static int top = 0; -static int bottom = 0; -static int left = 0; -static int right = 0; -static int autocrop = 0; +static int height = 0; +static int crop[4] = { -1,-1,-1,-1 }; static int cpu = 0; -static int vbitrate = 1024; +static int vrate = 0; +static int arate = 0; +static float vquality = -1.0; +static int vbitrate = 0; static int size = 0; -static int abitrate = 128; +static int abitrate = 0; static int mux = 0; static int acodec = 0; +static int chapter_start = 0; +static int chapter_end = 0; /* Exit cleanly on Ctrl-C */ static volatile int die = 0; static void SigHandler( int ); /* Utils */ +static void ShowCommands(); static void ShowHelp(); static int ParseOptions( int argc, char ** argv ); static int CheckOptions( int argc, char ** argv ); - -/* libhb callbacks */ -static void Scanning( void * data, int title, int titleCount ); -static void ScanDone( void * data, HBList * titleList ); -static void Encoding( void * data, float position, int pass, - int passCount, float frameRate, - float avgFrameRate, int remainingTime ); -static void RipDone( void * data, int result ); +static int HandleEvents( hb_handle_t * h ); int main( int argc, char ** argv ) { - HBHandle * h; - HBCallbacks callbacks; - - fprintf( stderr, "HandBrake " HB_VERSION - " - http://handbrake.m0k.org/\n" ); + hb_handle_t * h; + int build; + char * version; + /* Parse command line */ if( ParseOptions( argc, argv ) || CheckOptions( argc, argv ) ) { return 1; } - /* Exit ASAP on Ctrl-C */ - signal( SIGINT, SigHandler ); - /* Init libhb */ - h = HBInit( verbose, cpu ); + h = hb_init( debug, update ); + + /* Show version */ + fprintf( stderr, "HandBrake %s (%d) - http://handbrake.m0k.org/\n", + hb_get_version( h ), hb_get_build( h ) ); + + /* Check for update */ + if( update ) + { + if( ( build = hb_check_update( h, &version ) ) > -1 ) + { + fprintf( stderr, "You are using an old version of " + "HandBrake.\nLatest is %s (build %d).\n", version, + build ); + } + else + { + fprintf( stderr, "Your version of HandBrake is up to " + "date.\n" ); + } + hb_close( &h ); + return 0; + } - /* Set libhb callbacks */ - callbacks.data = h; - callbacks.scanning = Scanning; - callbacks.scanDone = ScanDone; - callbacks.encoding = Encoding; - callbacks.ripDone = RipDone; - HBSetCallbacks( h, callbacks ); + /* Geeky */ + fprintf( stderr, "%d CPU%s detected\n", hb_get_cpu_count(), + hb_get_cpu_count( h ) > 1 ? "s" : "" ); + if( cpu ) + { + fprintf( stderr, "Forcing %d CPU%s\n", cpu, + cpu > 1 ? "s" : "" ); + hb_set_cpu_count( h, cpu ); + } + + /* Exit ASAP on Ctrl-C */ + signal( SIGINT, SigHandler ); /* Feed libhb with a DVD to scan */ fprintf( stderr, "Opening %s...\n", input ); - HBScanDVD( h, input, titleindex ); + hb_scan( h, input, titleindex ); /* Wait... */ while( !die ) { - HBSnooze( 500000 ); +#if !defined(SYS_BEOS) + fd_set fds; + struct timeval tv; + int ret; + char buf[257]; + + tv.tv_sec = 0; + tv.tv_usec = 100000; + + FD_ZERO( &fds ); + FD_SET( STDIN_FILENO, &fds ); + ret = select( STDIN_FILENO + 1, &fds, NULL, NULL, &tv ); + + if( ret > 0 ) + { + int size = 0; + + while( size < 256 && + read( STDIN_FILENO, &buf[size], 1 ) > 0 ) + { + if( buf[size] == '\n' ) + { + break; + } + size++; + } + + if( size >= 256 || buf[size] == '\n' ) + { + switch( buf[0] ) + { + case 'q': + die = 1; + break; + case 'p': + hb_pause( h ); + break; + case 'r': + hb_resume( h ); + break; + case 'h': + ShowCommands(); + break; + } + } + } +#else + hb_snooze( 200 ); +#endif + + HandleEvents( h ); } /* Clean up */ - HBClose( &h ); + hb_close( &h ); + if( input ) free( input ); + if( output ) free( output ); + if( format ) free( format ); + if( audios ) free( audios ); + + fprintf( stderr, "HandBrake has exited.\n" ); + + return 0; +} + +static void ShowCommands() +{ + fprintf( stderr, "Commands:\n" ); + fprintf( stderr, " [h]elp Show this message\n" ); + fprintf( stderr, " [q]uit Exit HBTest\n" ); + fprintf( stderr, " [p]ause Pause encoding\n" ); + fprintf( stderr, " [r]esume Resume encoding\n" ); +} + +static void PrintTitleInfo( hb_title_t * title ) +{ + hb_chapter_t * chapter; + hb_audio_t * audio; + hb_subtitle_t * subtitle; + int i; + + fprintf( stderr, "+ title %d:\n", title->index ); + fprintf( stderr, " + vts %d, ttn %d, cells %d->%d (%d blocks)\n", + title->vts, title->ttn, title->cell_start, title->cell_end, + title->block_count ); + fprintf( stderr, " + duration: %02d:%02d:%02d\n", + title->hours, title->minutes, title->seconds ); + fprintf( stderr, " + size: %dx%d, aspect: %.2f, %.3f fps\n", + title->width, title->height, + (float) title->aspect / HB_ASPECT_BASE, + (float) title->rate / title->rate_base ); + fprintf( stderr, " + autocrop: %d/%d/%d/%d\n", title->crop[0], + title->crop[1], title->crop[2], title->crop[3] ); + fprintf( stderr, " + chapters:\n" ); + for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) + { + chapter = hb_list_item( title->list_chapter, i ); + fprintf( stderr, " + %d: cells %d->%d, %d blocks, duration " + "%02d:%02d:%02d\n", chapter->index, + chapter->cell_start, chapter->cell_end, + chapter->block_count, chapter->hours, chapter->minutes, + chapter->seconds ); + } + fprintf( stderr, " + audio tracks:\n" ); + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + audio = hb_list_item( title->list_audio, i ); + if( audio->codec & HB_ACODEC_AC3 ) + { + fprintf( stderr, " + %x, %s, %dHz, %dbps\n", audio->id, + audio->lang, audio->rate, audio->bitrate ); + } + else + { + fprintf( stderr, " + %x, %s\n", audio->id, audio->lang ); + } + } + fprintf( stderr, " + subtitle tracks:\n" ); + for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + { + subtitle = hb_list_item( title->list_subtitle, i ); + fprintf( stderr, " + %x, %s\n", subtitle->id, subtitle->lang ); + } +} + +static int HandleEvents( hb_handle_t * h ) +{ + hb_state_t s; + hb_get_state( h, &s ); + switch( s.state ) + { + case HB_STATE_IDLE: + /* Nothing to do */ + break; + +#define p s.param.scanning + case HB_STATE_SCANNING: + /* Show what title is currently being scanned */ + fprintf( stderr, "Scanning title %d", p.title_cur ); + if( !titleindex ) + fprintf( stderr, " of %d", p.title_count ); + fprintf( stderr, "...\n" ); + break; +#undef p + + case HB_STATE_SCANDONE: + { + hb_list_t * list; + hb_title_t * title; + hb_job_t * job; + + list = hb_get_titles( h ); + + if( !hb_list_count( list ) ) + { + /* No valid title, stop right there */ + fprintf( stderr, "No title found.\n" ); + die = 1; + break; + } + if( !titleindex ) + { + /* Scan-only mode, print infos and exit */ + int i; + for( i = 0; i < hb_list_count( list ); i++ ) + { + title = hb_list_item( list, i ); + PrintTitleInfo( title ); + } + die = 1; + break; + } + + /* Set job settings */ + title = hb_list_item( list, 0 ); + job = title->job; + + PrintTitleInfo( title ); + + if( chapter_start && chapter_end ) + { + job->chapter_start = MAX( job->chapter_start, + chapter_start ); + job->chapter_end = MIN( job->chapter_end, + chapter_end ); + job->chapter_end = MAX( job->chapter_start, + job->chapter_end ); + } + + if( crop[0] >= 0 && crop[1] >= 0 && + crop[2] >= 0 && crop[3] >= 0 ) + { + memcpy( job->crop, crop, 4 * sizeof( int ) ); + } + + job->deinterlace = deinterlace; + job->grayscale = grayscale; + + if( width && height ) + { + job->width = width; + job->height = height; + } + else if( width ) + { + job->width = width; + hb_fix_aspect( job, HB_KEEP_WIDTH ); + } + else if( height ) + { + job->height = height; + hb_fix_aspect( job, HB_KEEP_HEIGHT ); + } + else + { + hb_fix_aspect( job, HB_KEEP_WIDTH ); + } + + if( vquality >= 0.0 && vquality <= 1.0 ) + { + job->vquality = vquality; + job->vbitrate = 0; + } + else if( vbitrate ) + { + job->vquality = -1.0; + job->vbitrate = vbitrate; + } + if( vcodec ) + { + job->vcodec = vcodec; + } + if( vrate ) + { + job->vrate = 27000000; + job->vrate_base = vrate; + } + if( arate ) + { + job->arate = arate; + } + + if( audios ) + { + if( strcasecmp( audios, "none" ) ) + { + int audio_count = 0; + char * tmp = audios; + while( *tmp ) + { + if( *tmp < '0' || *tmp > '9' ) + { + /* Skip non numeric char */ + tmp++; + continue; + } + job->audios[audio_count++] = + strtol( tmp, &tmp, 0 ) - 1; + } + job->audios[audio_count] = -1; + } + else + { + job->audios[0] = -1; + } + } + if( abitrate ) + { + job->abitrate = abitrate; + } + if( acodec ) + { + job->acodec = acodec; + } + + if( size ) + { + job->vbitrate = hb_calc_bitrate( job, size ); + fprintf( stderr, "Calculated bitrate: %d kbps\n", + job->vbitrate ); + } + + if( sub ) + { + job->subtitle = sub - 1; + } + + if( job->mux ) + { + job->mux = mux; + } + job->file = strdup( output ); + + if( twoPass ) + { + job->pass = 1; + hb_add( h, job ); + job->pass = 2; + hb_add( h, job ); + } + else + { + job->pass = 0; + hb_add( h, job ); + } + hb_start( h ); + break; + } - fprintf( stderr, "HandBrake has exited cleanly.\n" ); +#define p s.param.working + case HB_STATE_WORKING: + fprintf( stderr, "\rEncoding: task %d of %d, %.2f %%", + p.job_cur, p.job_count, 100.0 * p.progress ); + if( p.seconds > -1 ) + { + fprintf( stderr, " (%.2f fps, avg %.2f fps, ETA " + "%02dh%02dm%02ds)", p.rate_cur, p.rate_avg, + p.hours, p.minutes, p.seconds ); + } + break; +#undef p +#define p s.param.workdone + case HB_STATE_WORKDONE: + /* Print error if any, then exit */ + switch( p.error ) + { + case HB_ERROR_NONE: + fprintf( stderr, "\nRip done!\n" ); + break; + case HB_ERROR_CANCELED: + fprintf( stderr, "\nRip canceled.\n" ); + break; + default: + fprintf( stderr, "\nRip failed (error %x).\n", + p.error ); + } + die = 1; + break; +#undef p + } return 0; } @@ -103,16 +458,16 @@ void SigHandler( int i_signal ) { if( die == 0 ) { - i_die_date = HBGetDate(); + die = 1; + i_die_date = hb_get_date(); fprintf( stderr, "Signal %d received, terminating - do it " "again in case it gets stuck\n", i_signal ); } - else if( i_die_date + 500000 < HBGetDate() ) + else if( i_die_date + 500 < hb_get_date() ) { fprintf( stderr, "Dying badly, files might remain in your /tmp\n" ); exit( 1 ); } - die = 1; } /**************************************************************************** @@ -120,39 +475,63 @@ void SigHandler( int i_signal ) ****************************************************************************/ static void ShowHelp() { + int i; + fprintf( stderr, "Syntax: HBTest [options] -i <device> -o <file>\n" "\n" - " -h, --help Print help\n" - " -v, --verbose Be verbose\n" - " -C, --cpu Set CPU count (default: autodetected)\n" + " -h, --help Print help\n" + " -u, --update Check for updates and exit\n" + " -v, --verbose Be verbose\n" + " -C, --cpu Set CPU count (default: autodetected)\n" "\n" - " -f, --format <string> Set output format (avi/mp4/ogm, default:\n" - " autodetected)\n" - " -i, --input <string> Set input device\n" - " -o, --output <string> Set output file name\n" + " -f, --format <string> Set output format (avi/mp4/ogm, default:\n" + " autodetected from file name)\n" + " -i, --input <string> Set input device\n" + " -o, --output <string> Set output file name\n" "\n" - " --scan Only scan the device\n" - " -t, --title <number> Select a title to encode (0 to scan only,\n" - " default: 1)\n" - " -a, --audio <string> Select audio channel(s) (none for no audio,\n" - " default: first one)\n" - " --noaudio Disable audio\n" + " -t, --title <number> Select a title to encode (0 to scan only,\n" + " default: 1)\n" + " -c, --chapters <string> Select chapters (e.g. \"1-3\" for chapters\n" + " 1 to 3, or \"3\" for chapter 3 only,\n" + " default: all chapters)\n" + " -a, --audio <string> Select audio channel(s) (\"none\" for no \n" + " audio, default: first one)\n" "\n" - " -c, --codec <string> Set video library encoder (ffmpeg/xvid/x264,\n" - " default: ffmpeg)\n" - " -2, --two-pass Use two-pass mode\n" - " -d, --deinterlace Deinterlace video\n" + " -s, --subtitle <number> Select subtitle (default: none)\n" + " -e, --encoder <string> Set video library encoder (ffmpeg/xvid/x264,\n" + " default: ffmpeg)\n" + " -E, --aencoder <string> Set audio encoder (faac/lame/vorbis/ac3, ac3\n" + " meaning passthrough, default: guessed)\n" + " -2, --two-pass Use two-pass mode\n" + " -d, --deinterlace Deinterlace video\n" + " -g, --grayscale Grayscale encoding\n" "\n" - " -b, --vb <kb/s> Set video bitrate (default: 1024)\n" - " -s, --size <MB> Set target size instead of bitrate\n" - " -B, --ab <kb/s> Set audio bitrate (default: 128)\n" - " -w, --width <number> Set picture width\n" - " --crop <T:B:L:R> Set cropping values\n" - " --autocrop Use autodetected cropping values\n" ); + " -r, --rate Set video framerate (" ); + for( i = 0; i < hb_video_rates_count; i++ ) + { + fprintf( stderr, hb_video_rates[i].string ); + if( i != hb_video_rates_count - 1 ) + fprintf( stderr, "/" ); + } + fprintf( stderr, ")\n" + " -R, --arate Set audio samplerate (" ); + for( i = 0; i < hb_audio_rates_count; i++ ) + { + fprintf( stderr, hb_audio_rates[i].string ); + if( i != hb_audio_rates_count - 1 ) + fprintf( stderr, "/" ); + } + fprintf( stderr, ")\n" + " -b, --vb <kb/s> Set video bitrate (default: 1000)\n" + " -q, --quality <float> Set video quality (0.0..1.0)\n" + " -S, --size <MB> Set target size\n" + " -B, --ab <kb/s> Set audio bitrate (default: 128)\n" + " -w, --width <number> Set picture width\n" + " -l, --height <number> Set picture height\n" + " --crop <T:B:L:R> Set cropping values (default: autocrop)\n" ); } - /**************************************************************************** * ParseOptions: ****************************************************************************/ @@ -163,6 +542,7 @@ static int ParseOptions( int argc, char ** argv ) static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, + { "update", no_argument, NULL, 'u' }, { "verbose", no_argument, NULL, 'v' }, { "cpu", required_argument, NULL, 'C' }, @@ -170,21 +550,26 @@ static int ParseOptions( int argc, char ** argv ) { "input", required_argument, NULL, 'i' }, { "output", required_argument, NULL, 'o' }, - { "scan", no_argument, NULL, 'S' }, { "title", required_argument, NULL, 't' }, + { "chapters", required_argument, NULL, 'c' }, { "audio", required_argument, NULL, 'a' }, - { "noaudio", no_argument, NULL, 'a' }, + { "subtitle", required_argument, NULL, 's' }, - { "codec", required_argument, NULL, 'c' }, + { "encoder", required_argument, NULL, 'e' }, + { "aencoder", required_argument, NULL, 'E' }, { "two-pass", no_argument, NULL, '2' }, { "deinterlace", no_argument, NULL, 'd' }, + { "grayscale", no_argument, NULL, 'g' }, { "width", required_argument, NULL, 'w' }, + { "height", required_argument, NULL, 'l' }, { "crop", required_argument, NULL, 'n' }, - { "autocrop", no_argument, NULL, 'z' }, { "vb", required_argument, NULL, 'b' }, - { "size", required_argument, NULL, 's' }, + { "quality", required_argument, NULL, 'q' }, + { "size", required_argument, NULL, 'S' }, { "ab", required_argument, NULL, 'B' }, + { "rate", required_argument, NULL, 'r' }, + { "arate", required_argument, NULL, 'R' }, { 0, 0, 0, 0 } }; @@ -192,7 +577,8 @@ static int ParseOptions( int argc, char ** argv ) int option_index = 0; int c; - c = getopt_long( argc, argv, "hvC:f:i:o:St:a:c:2dw:n:zb:s:B:", + c = getopt_long( argc, argv, + "hvuC:f:i:o:t:c:a:s:e:E:2dgw:l:n:b:q:S:B:r:R:", long_options, &option_index ); if( c < 0 ) { @@ -204,8 +590,11 @@ static int ParseOptions( int argc, char ** argv ) case 'h': ShowHelp(); exit( 0 ); + case 'u': + update = 1; + break; case 'v': - verbose = 1; + debug = HB_DEBUG_ALL; break; case 'C': cpu = atoi( optarg ); @@ -221,14 +610,35 @@ static int ParseOptions( int argc, char ** argv ) output = strdup( optarg ); break; - case 'S': - titleindex = 0; - break; case 't': titleindex = atoi( optarg ); break; + case 'c': + { + int start, end; + if( sscanf( optarg, "%d-%d", &start, &end ) == 2 ) + { + chapter_start = start; + chapter_end = end; + } + else if( sscanf( optarg, "%d", &start ) == 1 ) + { + chapter_start = start; + chapter_end = chapter_start; + } + else + { + fprintf( stderr, "chapters: invalid syntax (%s)\n", + optarg ); + return -1; + } + break; + } case 'a': - audios = strdup( optarg ? optarg : "none" ); + audios = strdup( optarg ); + break; + case 's': + sub = atoi( optarg ); break; case '2': @@ -237,18 +647,21 @@ static int ParseOptions( int argc, char ** argv ) case 'd': deinterlace = 1; break; - case 'c': + case 'g': + grayscale = 1; + break; + case 'e': if( !strcasecmp( optarg, "ffmpeg" ) ) { - vcodec = HB_CODEC_FFMPEG; + vcodec = HB_VCODEC_FFMPEG; } else if( !strcasecmp( optarg, "xvid" ) ) { - vcodec = HB_CODEC_XVID; + vcodec = HB_VCODEC_XVID; } else if( !strcasecmp( optarg, "x264" ) ) { - vcodec = HB_CODEC_X264; + vcodec = HB_VCODEC_X264; } else { @@ -256,42 +669,78 @@ static int ParseOptions( int argc, char ** argv ) return -1; } break; + case 'E': + if( !strcasecmp( optarg, "ac3" ) ) + { + acodec = HB_ACODEC_AC3; + } + else if( !strcasecmp( optarg, "lame" ) ) + { + acodec = HB_ACODEC_LAME; + } + break; case 'w': width = atoi( optarg ); break; + case 'l': + height = atoi( optarg ); + break; case 'n': { - char * crop = strdup( optarg ); - char * _2be3 = crop; - - if( *crop ) + int i; + char * tmp = optarg; + for( i = 0; i < 4; i++ ) { - top = strtol( crop, &crop, 0 ); crop++; + if( !*tmp ) + break; + crop[i] = strtol( tmp, &tmp, 0 ); + tmp++; } - if( *crop ) + break; + } + case 'r': + { + int i; + vrate = 0; + for( i = 0; i < hb_video_rates_count; i++ ) { - bottom = strtol( crop, &crop, 0 ); crop++; + if( !strcmp( optarg, hb_video_rates[i].string ) ) + { + vrate = hb_video_rates[i].rate; + break; + } } - if( *crop ) + if( !vrate ) { - left = strtol( crop, &crop, 0 ); crop++; + fprintf( stderr, "invalid framerate %s\n", optarg ); } - if( *crop ) + break; + } + case 'R': + { + int i; + arate = 0; + for( i = 0; i < hb_audio_rates_count; i++ ) { - right = strtol( crop, &crop, 0 ); crop++; + if( !strcmp( optarg, hb_audio_rates[i].string ) ) + { + arate = hb_audio_rates[i].rate; + break; + } + } + if( !arate ) + { + fprintf( stderr, "invalid framerate %s\n", optarg ); } - - free( _2be3 ); break; } - case 'z': - autocrop = 1; - break; - case 'b': vbitrate = atoi( optarg ); break; - case 's': + case 'q': + vquality = atof( optarg ); + break; + case 'S': size = atoi( optarg ); break; case 'B': @@ -309,6 +758,11 @@ static int ParseOptions( int argc, char ** argv ) static int CheckOptions( int argc, char ** argv ) { + if( update ) + { + return 0; + } + if( input == NULL || *input == '\0' ) { fprintf( stderr, "Missing input device. Run %s --help for " @@ -328,7 +782,8 @@ static int CheckOptions( int argc, char ** argv ) if( !format ) { - char *p = strrchr( output, '.' ); + char * p = strrchr( output, '.' ); + /* autodetect */ if( p && !strcasecmp( p, ".avi" ) ) { @@ -343,12 +798,11 @@ static int CheckOptions( int argc, char ** argv ) { mux = HB_MUX_OGM; } - else { fprintf( stderr, "Output format couldn't be guessed " - "from file name, please use --format.\n" ); - return 1; + "from file name, using default.\n" ); + return 0; } } else if( !strcasecmp( format, "avi" ) ) @@ -370,145 +824,24 @@ static int CheckOptions( int argc, char ** argv ) "choices are avi, mp4 and ogm\n.", format ); return 1; } - if( mux == HB_MUX_MP4 ) - { - acodec = HB_CODEC_AAC; - } - else if( mux == HB_MUX_AVI ) - { - acodec = HB_CODEC_MP3; - } - else if( mux == HB_MUX_OGM ) - { - acodec = HB_CODEC_VORBIS; - } - } - - return 0; -} -static void Scanning( void * data, int title, int titleCount ) -{ - if( titleindex ) - { - fprintf( stderr, "Scanning title %d...\n", title ); - } - else - { - fprintf( stderr, "Scanning title %d/%d...\n", title, titleCount ); - } -} - -static void ScanDone( void * data, HBList * titleList ) -{ - HBHandle * h = (HBHandle*) data; - HBAudio * audio; - HBTitle * title; - - if( !titleList ) - { - fprintf( stderr, "No title found. Invalid device?\n" ); - die = 1; - return; - } - if( !titleindex ) - { - die = 1; - return; - } - - title = HBListItemAt( titleList, 0 ); - title->file = strdup( output ); - title->twoPass = twoPass; - title->deinterlace = deinterlace; - if( width ) - { - title->outWidth = width; - } - if( autocrop ) - { - title->topCrop = title->autoTopCrop; - title->bottomCrop = title->autoBottomCrop; - title->leftCrop = title->autoLeftCrop; - title->rightCrop = title->autoRightCrop; - } - else - { - title->topCrop = top; - title->bottomCrop = bottom; - title->leftCrop = left; - title->rightCrop = right; - } - fprintf( stderr, "Cropping: T=%d,B=%d,L=%d,R=%d\n", - title->topCrop, title->bottomCrop, - title->leftCrop, title->rightCrop ); - title->bitrate = vbitrate; - title->codec = vcodec; - title->mux = mux; - - if( audios == NULL ) - { - audio = HBListItemAt( title->audioList, 0 ); - audio->outBitrate = abitrate; - audio->outCodec = acodec; - HBListAdd( title->ripAudioList, audio ); - } - else if( strcasecmp( audios, "none" ) ) - { - char *tmp = audios; - - while( *tmp ) + if( !acodec ) { - int i; - - if( *tmp < '0' || *tmp > '9' ) + if( mux == HB_MUX_MP4 ) { - /* Skip non numeric char */ - tmp++; - continue; + acodec = HB_ACODEC_FAAC; + } + else if( mux == HB_MUX_AVI ) + { + acodec = HB_ACODEC_LAME; + } + else if( mux == HB_MUX_OGM ) + { + acodec = HB_ACODEC_VORBIS; } - - i = strtol( tmp, &tmp, 0 ); - audio = HBListItemAt( title->audioList, i - 1 ); - audio->outBitrate = abitrate; - audio->outCodec = acodec; - HBListAdd( title->ripAudioList, audio ); } } - if( size ) - { - title->bitrate = HBGetBitrateForSize( title, size, title->mux, - HBListCount( title->ripAudioList ), abitrate ); - fprintf( stderr, "Calculated bitrate: %d kbps\n", title->bitrate ); - } - HBStartRip( h, title ); -} - -static void Encoding( void * data, float position, int pass, - int passCount, float frameRate, - float avgFrameRate, int remainingTime ) -{ - fprintf( stderr, "%6.2f %% (pass: %d/%d, cur/avg speed: " - "%5.2f/%5.2f fps, %02d:%02d:%02d remaining)\n", - 100.0 * position, pass, passCount, frameRate, avgFrameRate, - remainingTime / 3600, ( remainingTime / 60 ) % 60, - remainingTime % 60 ); -} - -static void RipDone( void * data, int result ) -{ - switch( result ) - { - case HB_SUCCESS: - fprintf( stderr, "Rip done!\n" ); - break; - case HB_CANCELED: - fprintf( stderr, "Rip canceled.\n" ); - break; - default: - fprintf( stderr, "Rip failed (error %x).\n", result ); - } - die = 1; + return 0; } diff --git a/wx/hb32x32.xpm b/wx/hb32x32.xpm new file mode 100644 index 000000000..baa88bca4 --- /dev/null +++ b/wx/hb32x32.xpm @@ -0,0 +1,295 @@ +/* XPM */ +static char *hb_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 257 2", +" c #00044C", +". c #180F3C", +"X c #150C6A", +"o c #171465", +"O c #4E0A0D", +"+ c #470D15", +"@ c #1D1D3E", +"# c #670501", +"$ c #5E080A", +"% c #10320A", +"& c #003D04", +"* c #770105", +"= c #0F3412", +"- c #511412", +"; c #431733", +": c #29281F", +"> c #880001", +", c #33261E", +"< c #442017", +"1 c #930000", +"2 c #372C16", +"3 c #6C1501", +"4 c #9B0200", +"5 c #52250F", +"6 c #631D13", +"7 c #542225", +"8 c #432C2A", +"9 c #005603", +"0 c #413416", +"q c #75124B", +"w c #81161A", +"e c #A6070B", +"r c #2D4034", +"t c #3C3837", +"y c #144F2E", +"u c #443B1C", +"i c #961219", +"p c #8F161C", +"a c #015C2A", +"s c #473B23", +"d c #393E41", +"f c #901B11", +"g c #56362E", +"h c #195629", +"j c #4A3A3C", +"k c #4F3E1F", +"l c #6D311F", +"z c #514118", +"x c #3E3B71", +"c c #45452D", +"v c #403E62", +"b c #792F18", +"n c #006B27", +"m c #3C4652", +"M c #5B4215", +"N c #424648", +"B c #52452C", +"V c #634117", +"C c #096B33", +"Z c #545004", +"A c #00732E", +"S c #57482A", +"D c #146D1C", +"F c #524A2F", +"G c #007D02", +"H c #23623A", +"J c #41552E", +"K c #644916", +"L c #5F4A22", +"P c #5D4C28", +"I c #B92312", +"U c #644C1E", +"Y c #007C2F", +"T c #59512B", +"R c #157139", +"E c #5F4C37", +"W c #2D654D", +"Q c #58523E", +"! c #2E6744", +"~ c #724D16", +"^ c #515350", +"/ c #6E501C", +"( c #675229", +") c #684865", +"_ c #0F832E", +"` c #42634F", +"' c #485B71", +"] c #009500", +"[ c #685A22", +"{ c #755523", +"} c #535B62", +"| c #76561E", +" . c #16823A", +".. c #357337", +"X. c #CE2F03", +"o. c #725824", +"O. c #3C6B54", +"+. c #575C5E", +"@. c #71592A", +"#. c #15882C", +"$. c #7F571A", +"%. c #2B7B49", +"&. c #68595B", +"*. c #5E5E5C", +"=. c #7C5B1B", +"-. c #80514C", +";. c #00A100", +":. c #66623F", +">. c #357853", +",. c #7B620E", +"<. c #0E942C", +"1. c #6A5F4F", +"2. c #636449", +"3. c #7F5D25", +"4. c #845159", +"5. c #8F5337", +"6. c #7C6026", +"7. c #64635C", +"8. c #984D48", +"9. c #357E52", +"0. c #7D612D", +"q. c #4E7061", +"w. c #89601C", +"e. c #717103", +"r. c #626667", +"t. c #7C6334", +"y. c #7C633A", +"u. c #786442", +"i. c #746354", +"p. c #6C6469", +"a. c #856525", +"s. c #89661F", +"d. c #636B72", +"f. c #836933", +"g. c #72732F", +"h. c #86692F", +"j. c #716B5E", +"k. c #766863", +"l. c #806754", +"z. c #5F6F84", +"x. c #877302", +"c. c #527C63", +"v. c #6A6E6E", +"b. c #5C795F", +"n. c #637085", +"m. c #BC4675", +"M. c #946A26", +"N. c #597B6C", +"B. c #79714B", +"V. c #956B1F", +"C. c #8B6E2C", +"Z. c #916C2A", +"A. c #D64A27", +"S. c #925F75", +"D. c #1BAB2D", +"F. c #C14A74", +"G. c #84743B", +"H. c #717678", +"J. c #907239", +"K. c #8C6B6C", +"L. c #867452", +"P. c #757773", +"I. c #6E7882", +"U. c #87745A", +"Y. c #8C7644", +"T. c #89830E", +"R. c #867A48", +"E. c #808329", +"W. c #7F7A5E", +"Q. c #6C7B8D", +"!. c #A17522", +"~. c #9A7730", +"^. c #9F762A", +"/. c #817A75", +"(. c #6A7F99", +"). c #88891E", +"_. c #E45A2B", +"`. c #20BF2A", +"'. c #798189", +"]. c #BD6D43", +"[. c #A07F35", +"{. c #81827E", +"}. c #AA7D2A", +"|. c #8A8074", +" X c #AE7E25", +".X c #987D8D", +"XX c #AE8430", +"oX c #AB8838", +"OX c #868B8D", +"+X c #998677", +"@X c #948A7E", +"#X c #9D8D58", +"$X c #7D90AE", +"%X c #A79430", +"&X c #AC8E4A", +"*X c #B19517", +"=X c #BC8C2F", +"-X c #819A86", +";X c #7F92B7", +":X c #7995B8", +">X c #F76D38", +",X c #A08E78", +"<X c #998F8C", +"1X c #A09B42", +"2X c #929491", +"3X c #9C966D", +"4X c #919499", +"5X c #9E9476", +"6X c #809F91", +"7X c #D48829", +"8X c #FE628E", +"9X c #FA7832", +"0X c #8A99B8", +"qX c #859DBA", +"wX c #999B98", +"eX c #74B486", +"rX c #91A29B", +"tX c #A8A263", +"yX c #999FA5", +"uX c #CC9B31", +"iX c #CCA504", +"pX c #D8887F", +"aX c #FA8728", +"sX c #E18971", +"dX c #C99E42", +"fX c #C4A23B", +"gX c #CD9F3C", +"hX c #A7A9A6", +"jX c #9EA9C3", +"kX c #99ACC3", +"lX c #FB9C1A", +"zX c #DCA645", +"xX c #CFA39A", +"cX c #FAAA05", +"vX c #BAB971", +"bX c #F29C75", +"nX c #DAAD5E", +"mX c #A9B7CB", +"MX c #B1B9C1", +"NX c #FFB904", +"BX c #FBA873", +"VX c #E7BE37", +"CX c #B3C4BD", +"ZX c #B8C4D4", +"AX c #D1BFB4", +"SX c #F1B49D", +"DX c #FBBF48", +"FX c #FECC00", +"GX c #C5CACD", +"HX c #FCBE8D", +"JX c #CDCFCB", +"KX c #C8D2DD", +"LX c #C0DACB", +"PX c #FBD5C2", +"IX c #F7F698", +"UX c gray100", +"YX c None", +/* pixels */ +"YXYXYXS.F.S.YXYXYXYXYXYXYXYXYX{.YXYXYXYXYXYXYXYXYXYXYXYX4XYXYXYX", +"YXYXYXm.8Xm.YXYXYXYXYXYXYXYXW.1XYXYXYXYXYXYXYXMXYXYXYX} YXYXYXYX", +"YXYXYX.Xq ) YXYXYXYXYXYXYXH.g.3XYXYXYXYXYXYXYXYXd.YXYXr YXYXYXYX", +"YXYXYX{.x v j.,X/.YXYX` G 9 & = b.YXYXYXYXYXYXYXq.6XrXO.YXO.yXYX", +"YXYX/.+X/.AX+Xj.E YXYX'.G ;.;.G ] ..YXYXYXYXH >.6XC ! 9.C q.YXYX", +"YXYX1.U.Q U.l.i.|.YXYXYX-X% n D b.YXYXYXYXYXYXR A R n n O.LXYXYX", +"YXYX/.+Xl.5.b &.YXYXYXYXYXT.YXwX/.YXYXYXYXYXYX6X_ <.A Y #.h +.MX", +"YXYXYXYX-.X.X.8 H.v.H.H.2.E.2.T *X%XYXYXYXYXN.O.C D._ `.A y N.CX", +"YXYXYXYXYX8 . <XGXyXwXwXT.c vXQ 2.FX#XYXYX6X%.D.A <.D. .a ` YXYX", +"YXYXYXYX+.k. +.<Xv.p.*.Z t N +.x.iX5XYXYXYXv.q.#.<.<.#._ a c.LX", +"YXYXYXd.P.<Xo @ &.j 8 , e.j t s 5 7 YXYXr.u.uXgXQ J D _ .eXYXYX", +"YXYXYX7 xXp ; X 1 e p ,.V w g IX- $ p.U.gX[.V.^.gXXX&XY.:.6XYXYX", +"YXYXK.8.xX# - X p i w e.+ $ B IXtX6 < { ~.( ~.0.^.=XF }.h.&XYXYX", +"YXYX4.sXpX1 > > * * * > > 1 > l tXIXB.P [.J.=.gXP [.XX0.J.J.{.YX", +"YXYXk.bXpXI 1 4 4 1 1 e I e 1 > f B.R.f.M t.6.oX[.}.=XB XX=XN YX", +"YXYXYX].PX>X>X1 A.I A.>X_._.e 3 x.0 o.t.Z.C.Y.$.zX( f.dXt.y.U.YX", +"YXYXYX+XzXBXaXA.>X>X>X>XaX9XA.SX7Xk @.( J.V.f.XXf.J.dX| 6.o.o.YX", +"YXYXYXYXW.nXDXlXaX9XlXlXcXcXHXnXK s Z.Z.0.3.Z.P X XP ^.[.Y.h.YX", +"YXYXYXYXYXYX5XfXFXNXFXFXFXVXG.k L =X( @.s.a. XZ.^.XX=.o.V.~.s YX", +"YXYXYXYXYXYXYXYX7.[ R.R.T d.P.=.$.f.( !.!.=.w.Z.( a.uXs.s.6.L.YX", +"YXYXYXYXYXYXYXYXYXI.wXOXI.YX1.| s s.XX{ [email protected].=X3.=.K =.6.U.YX", +"YXYXYXYXYXYXYXYXYXYXH.P.YXYXd.S { Z.oXB h. X!.( w.k | / Xs.YXYX", +"YXYXYXYXYXYXYXYXYXYXv.H.YXYX*.o.$.k 0.=Xf.Z.XXs | U uX0.w.S YXYX", +"YXYXYXYXYXYXYXYXYXYXH.H.YXYXP./ K =Xf.~ ~.T 0.f. X6.| U s.L.YXYX", +"YXYXYXYXYXYXYXYXYXYXH.{.YXYXYXS / ~ @.| t.C.!.0.w.L 0.( G.YXYXYX", +"YXYXYXYXZXmXkXkXmXYXv.4X+.YXYXL.K M.o.t.3.3.a.s h.C.}.XX'.YXYXYX", +"YXYXkX:X;X;X;X;Xn.m hX4Xr.r.YX{.3.: [email protected] C.f.~ @.0.2 kXYXYXYX", +"mXqX;XqX:X$Xz.+.H.4XGX<X{.4XwXd d ^.k @.L ~ L z S ~.: (.jXYXYXYX", +"0X$X;X$X:X;X} H.<X{.H.p.v.H.4X<X' P | $.k U { o.K Q ;X0XZXYXYXYX", +"mX;X$X;X;X;X$Xn.Q.'.I.I.I.n.Q.:X$X;X*.Q P 2 B } z.;XqXZXYXYXYXYX", +"YXZX0X;X$X;X;X;X;X;X:X;X;X;X;X;X$X$X0XkXjXmXmXmXZXKXYXYXYXYXYXYX", +"YXYXYXGXmXjXjX0X$XqX;X$XjXjXmXMXmXKXYXYXYXYXYXYXYXYXYXYXYXYXYXYX" +}; diff --git a/wx/hbWizard.cpp b/wx/hbWizard.cpp new file mode 100644 index 000000000..c9473067c --- /dev/null +++ b/wx/hbWizard.cpp @@ -0,0 +1,1259 @@ +/***************************************************************************** + * wxHB: + ***************************************************************************** + * Copyright (C) + * $Id: hbWizard.cpp,v 1.4 2005/03/17 19:22:47 titer Exp $ + * + * Authors: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include "wxHB.h" +#include "hbWizard.h" + +#include "hb32x32.xpm" + +/* All IDs + * CB: ComboBox + * BT: Button + * RD: Radio + * NB: NoteBook + */ +enum +{ + /* Source page */ + ID_SOURCE_RD_DRIVE = wxID_HIGHEST, + ID_SOURCE_RD_DIR, + ID_SOURCE_BT_DIR, + ID_SOURCE_CB_DRIVE, + ID_SOURCE_CB_DIR, + + ID_SOURCE_BT_ABOUT, + ID_SOURCE_BT_PREFERENCES, + + /* Settings page */ + ID_SETTINGS_CB_TITLE = wxID_HIGHEST, + ID_SETTINGS_CB_CHAPTER_START, + ID_SETTINGS_CB_CHAPTER_END, + ID_SETTINGS_CB_AUDIO_LANGUAGE, + ID_SETTINGS_CB_AUDIO_QUALITY, + ID_SETTINGS_CB_SUBTITLE_LANGUAGE, + ID_SETTINGS_CB_VIDEO_QUALITY, + ID_SETTINGS_CB_OUTPUT_FILE, + ID_SETTINGS_CB_OUTPUT_SIZE, + ID_SETTINGS_CB_OUTPUT_BITRATE, + ID_SETTINGS_SC_OUTPUT_FILE_COUNT, + + ID_SETTINGS_RD_OUTPUT_SIZE, + ID_SETTINGS_RD_OUTPUT_BITRATE, + + ID_SETTINGS_CB_VIDEO_CODEC, + ID_SETTINGS_CB_VIDEO_FPS, + ID_SETTINGS_CH_VIDEO_DEINTERLACE, + ID_SETTINGS_CH_VIDEO_CROP, + ID_SETTINGS_SC_VIDEO_CROP_LEFT, + ID_SETTINGS_SC_VIDEO_CROP_TOP, + ID_SETTINGS_SC_VIDEO_CROP_RIGHT, + ID_SETTINGS_SC_VIDEO_CROP_BOTTOM, + ID_SETTINGS_SC_VIDEO_WIDTH, + ID_SETTINGS_SC_VIDEO_HEIGHT, + + ID_SETTINGS_CB_AUDIO_SAMPLERATE, + + ID_SETTINGS_CB_CPU, + ID_SETTINGS_CB_PRIORITY, + + ID_SETTINGS_BT_FILE, + + ID_SETTINGS_NB, + + /* */ + //ID_ALL_FIXME, +}; + +class hbImage: public wxControl +{ +public: + hbImage( wxWindow *parent ) : + wxControl( parent, -1, wxDefaultPosition, wxSize(128,128), + wxBORDER_NONE ) + { + } + + void OnPaint(wxPaintEvent &event) + { + wxPaintDC dc(this); + dc.SetBrush( wxBrush(*wxGREEN, wxSOLID) ); + dc.DrawText( wxU("Solid green"), 10, 10 ); + } + +private: + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE( hbImage, wxControl ) + EVT_PAINT( hbImage::OnPaint ) +END_EVENT_TABLE() + +/***************************************************************************** + * hbWizard + *****************************************************************************/ +static void hbWizardPageHeaders( wxWizardPageSimple *page, + char *psz_title, + char *psz_description, + wxSizer *sizerC ) +{ + wxBoxSizer *sizerH = new wxBoxSizer(wxHORIZONTAL); + + wxStaticBitmap *bm = new wxStaticBitmap( page, wxID_ANY, + wxBitmap(hb_xpm) ); + wxBoxSizer *sizerV = new wxBoxSizer(wxVERTICAL); + + + wxStaticText *title = new wxStaticText( page, -1, wxU(psz_title) ); + wxFont font = title->GetFont(); + font.SetPointSize(14); + title->SetFont( font ); + + sizerV->Add( title, 0, wxALIGN_CENTER|wxALL, 5 ); + + sizerV->Add( new wxStaticLine(page, -1), 0, wxEXPAND|wxALL, 5 ); + + wxStaticText *text = new wxStaticText( page, -1, + wxU( psz_description ) ); + sizerV->Add( text, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 ); + + //sizerV->Add( 0, 1, 1, wxALL ); + + sizerV->Add( sizerC, 1, wxEXPAND|wxALIGN_CENTER|wxALL, 5 ); + + + /* Add bmp */ + sizerH->Add( bm, 0, wxALL|wxALIGN_CENTER, 5 ); + /* Add sizer */ + sizerH->Add( sizerV, 1, wxEXPAND|wxALIGN_CENTER|wxALL, 5 ); + + /* */ + page->SetSizerAndFit( sizerH ); + + /* Needed ? */ + page->SetAutoLayout( TRUE ); + page->Layout(); +} + +/***************************************************************************** + * hbWizardPageSource: + *****************************************************************************/ +class hbWizardPageSource: public wxWizardPageSimple +{ +public: + hbWizardPageSource( wxWizard *p_wizard ); + virtual ~hbWizardPageSource(); + + + void OnRadio( wxCommandEvent &event ); + void OnBrowseDir( wxCommandEvent &event ); + void OnTextDirChange( wxCommandEvent &event ); + void OnTextDriveChange( wxCommandEvent &event ); + void OnPageChanging( wxWizardEvent &event ); + +private: + + wxDirDialog *dlgDir; + wxComboBox *comboDir; + wxComboBox *comboDrive; + wxButton *buttonDir; + + DECLARE_EVENT_TABLE() +}; + + +hbWizardPageSource::hbWizardPageSource( wxWizard *p_wizard ) : + wxWizardPageSimple(p_wizard) +{ + wxRadioButton *radio[2]; + wxFlexGridSizer *sizerDrive; + wxFlexGridSizer *sizerDir; + wxBoxSizer *sizerH; + wxButton *button; + + /* Create radio and subpanel */ + radio[0] = new wxRadioButton( this, ID_SOURCE_RD_DRIVE, + wxU("DVD drive" ) ); + radio[1] = new wxRadioButton( this, ID_SOURCE_RD_DIR, + wxU("DVD directory" ) ); + + /* - Create DRIVE row */ + sizerDrive = new wxFlexGridSizer( 1, 1, 20 ); + /* combo */ + wxArrayString &sD = *g_hbApp->GetSystemDrive(); + comboDrive = new wxComboBox( this, ID_SOURCE_CB_DRIVE, sD[0], + wxDefaultPosition, wxDefaultSize, + sD ); + sizerDrive->Add( comboDrive, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL ); + + /* - Create DIR row */ + sizerDir = new wxFlexGridSizer( 2, 1, 20 ); + /* combo */ + comboDir = new wxComboBox( this, ID_SOURCE_CB_DIR, wxU("") ); + sizerDir->Add( comboDir, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL ); + /* button */ + buttonDir = new wxButton( this, ID_SOURCE_BT_DIR, wxU("Browse...")); + sizerDir->Add( buttonDir, + 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL ); + + /* - Hop in the main */ + wxFlexGridSizer *sizerChoice = new wxFlexGridSizer( 2, 2, 20 ); + sizerChoice->Add( radio[0], + 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + sizerChoice->Add( sizerDrive, 1, wxEXPAND|wxALIGN_LEFT| + wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + sizerChoice->Add( radio[1], + 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + sizerChoice->Add( sizerDir, 1, wxEXPAND|wxALIGN_LEFT| + wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + + wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL ); + sizer->Add( sizerChoice, 1, + wxEXPAND|wxALIGN_CENTER|wxALL, 5 ); + + sizer->Add( 0, 0 ); + + sizerH = new wxBoxSizer( wxHORIZONTAL ); + sizerH->Add( 0, 0, 1 ); + button = new wxButton( this, ID_SOURCE_BT_ABOUT, wxU("About") ); + button->Enable(FALSE); + sizerH->Add( button, 0, wxALL|wxALIGN_RIGHT, 5 ); + button = new wxButton( this, ID_SOURCE_BT_PREFERENCES, wxU("Preferences")); + button->Enable(FALSE); + sizerH->Add( button, 0, wxALL|wxALIGN_RIGHT, 5 ); + + sizer->Add( sizerH, 0, wxALIGN_BOTTOM|wxEXPAND, 5 ); + + /* */ +#if 0 + hbImage *img = new hbImage( this ); + sizer->Add( img ); +#endif + + + hbWizardPageHeaders( this, "Source", + "Select the DVD (drive or a directory)", sizer ); + + comboDir->Enable( FALSE ); + buttonDir->Enable( FALSE ); + + //SetAutoLayout( TRUE ); + //Layout(); + + /* */ + dlgDir = NULL; +} + +hbWizardPageSource::~hbWizardPageSource() +{ +} + +void hbWizardPageSource::OnRadio( wxCommandEvent &event ) +{ + if( event.GetId() == ID_SOURCE_RD_DRIVE ) + { + comboDrive->Enable( TRUE ); + + comboDir->Enable( FALSE ); + buttonDir->Enable( FALSE ); + } + else + { + comboDir->Enable( TRUE ); + buttonDir->Enable( TRUE ); + + comboDrive->Enable( FALSE ); + } +} + +void hbWizardPageSource::OnBrowseDir( wxCommandEvent &event ) +{ + if( dlgDir == NULL ) + dlgDir = new wxDirDialog( this, wxU( "Choose a directory"), + wxGetCwd() ); + + if( dlgDir->ShowModal() == wxID_OK ) + { + const wxChar *p = dlgDir->GetPath(); + + comboDir->SetValue( p ); + } +} + +void hbWizardPageSource::OnTextDirChange( wxCommandEvent &event ) +{ +} +void hbWizardPageSource::OnTextDriveChange( wxCommandEvent &event ) +{ +} + +void hbWizardPageSource::OnPageChanging( wxWizardEvent &event ) +{ + wxRadioButton *rdDrive = (wxRadioButton*)FindWindow( ID_SOURCE_RD_DRIVE ); + wxString sDevice; + + if( rdDrive->GetValue() ) + { + wxComboBox *cbDrive = (wxComboBox*)FindWindow( ID_SOURCE_CB_DRIVE ); + /* Get the drive value */ + sDevice = cbDrive->GetValue(); + } + else + { + wxComboBox *cbDir = (wxComboBox*)FindWindow( ID_SOURCE_CB_DIR ); + sDevice = cbDir->GetValue(); + + if( sDevice.IsEmpty() ) + { + hbError( this, wxU("You have to give a directory name") ); + event.Veto(); + return; + } + } + + if( g_hbApp->Scan( sDevice ) < 0 ) + { + event.Veto(); + } +} + + + +BEGIN_EVENT_TABLE( hbWizardPageSource, wxWizardPageSimple ) + EVT_RADIOBUTTON( ID_SOURCE_RD_DRIVE, hbWizardPageSource::OnRadio ) + EVT_RADIOBUTTON( ID_SOURCE_RD_DIR, hbWizardPageSource::OnRadio ) + + EVT_BUTTON( ID_SOURCE_BT_DIR, hbWizardPageSource::OnBrowseDir ) + + EVT_TEXT( ID_SOURCE_CB_DIR, hbWizardPageSource::OnTextDirChange ) + EVT_TEXT( ID_SOURCE_CB_DRIVE, hbWizardPageSource::OnTextDriveChange ) + + EVT_WIZARD_PAGE_CHANGING( -1, hbWizardPageSource::OnPageChanging ) +END_EVENT_TABLE() + + +/***************************************************************************** + * hbWizardPageSettings: + *****************************************************************************/ +static wxPanel *PanelSettingsGeneral( wxWindow *p_parent ) +{ + wxPanel *panel = new wxPanel( p_parent, -1, + wxDefaultPosition, wxSize(200, 200)); + wxBoxSizer *sizerV = new wxBoxSizer( wxVERTICAL ); + wxGridSizer *sizerG; + wxBoxSizer *sizerS; + wxStaticBox *ibox; + wxStaticBoxSizer *sbox; + wxFlexGridSizer *sizerF; + wxComboBox *combo; + wxButton *button; + wxRadioButton *radio; + wxSpinCtrl *spin; + + wxArrayString aQ; + + /* Selection (title/chapter) */ + ibox = new wxStaticBox( panel, -1, wxU("Selection") ); + sbox = new wxStaticBoxSizer( ibox, wxHORIZONTAL); + + sbox->Add( new wxStaticText( panel, -1, wxU("Title") ), + 0, wxALL, 5 ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_TITLE, wxU(""), + wxDefaultPosition, wxDefaultSize, 0, NULL, + wxCB_READONLY ); + + sbox->Add( combo, 1, wxEXPAND|wxALL, 5 ); + //sbox->Add( 0, 0, 1 ); + + sbox->Add( new wxStaticText( panel, -1, wxU( "Chapters" ) ), + 0, wxALL, 5 ); + + combo = new wxComboBox( panel, ID_SETTINGS_CB_CHAPTER_START, wxU(""), + wxDefaultPosition, wxDefaultSize, 0, NULL, + wxCB_READONLY ); + sbox->Add( combo, 0, wxEXPAND|wxALL, 5 ); + + sbox->Add( new wxStaticText( panel, -1, wxU( "to" ) ), + 0, wxALL, 5 ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_CHAPTER_END, wxU(""), + wxDefaultPosition, wxDefaultSize, 0, NULL, + wxCB_READONLY ); + + sbox->Add( combo, 0, wxEXPAND|wxALL, 5 ); + + sizerV->Add( sbox, 1, wxEXPAND|wxALL, 5 ); + + /* Sizer for audio + video box */ + sizerG = new wxGridSizer( 1, 2, 10, 10 ); + + /* Audio */ + ibox = new wxStaticBox( panel, -1, wxU("Audio") ); + sbox = new wxStaticBoxSizer( ibox, wxHORIZONTAL); + + sizerF = new wxFlexGridSizer( 2, 2, 20 ); + sizerF->Add( new wxStaticText( panel, -1, wxU( "Language" ) ), + 0, wxALL|wxALIGN_LEFT, 5 ); + //sbox->Add( 0, 0, 1 ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_AUDIO_LANGUAGE, wxU(""), + wxDefaultPosition, wxDefaultSize, 0, NULL, + wxCB_READONLY ); + sizerF->Add( combo, 1, wxEXPAND|wxALL|wxALIGN_RIGHT, 5 ); + + sizerF->Add( new wxStaticText( panel, -1, wxU( "Quality" ) ), + 0, wxALL|wxALIGN_LEFT, 5 ); + //sbox->Add( 0, 0, 1 ); + + aQ.Clear(); + aQ.Add( wxU("Low - 64 kb/s") ); + aQ.Add( wxU("Normal - 128 kb/s") ); + aQ.Add( wxU("High - 160 kb/s") ); + aQ.Add( wxU("Extra - 192 kb/s") ); + + combo = new wxComboBox( panel, ID_SETTINGS_CB_AUDIO_QUALITY, aQ[2], + wxDefaultPosition, wxDefaultSize, + aQ, wxCB_READONLY ); + sizerF->Add( combo, 1, wxEXPAND|wxALL|wxALIGN_RIGHT, 5 ); + + sbox->Add( sizerF, 1, wxEXPAND|wxALL, 0 ); + //sizerV->Add( sbox, 0, wxALL, 5 ); + sizerG->Add( sbox, 1, wxEXPAND|wxALL, 0 ); + + /* Video */ + ibox = new wxStaticBox( panel, -1, wxU("Video") ); + sbox = new wxStaticBoxSizer( ibox, wxHORIZONTAL); + + sizerF = new wxFlexGridSizer( 2, 2, 20 ); + + sizerF->Add( new wxStaticText( panel, -1, wxU( "Quality" ) ), + 0, wxALL|wxALIGN_LEFT, 5 ); + + aQ.Clear(); + aQ.Add( wxU("Low (fast)") ); + aQ.Add( wxU("Normal") ); + aQ.Add( wxU("High (slow)") ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_VIDEO_QUALITY, aQ[2], + wxDefaultPosition, wxDefaultSize, + aQ, wxCB_READONLY ); + sizerF->Add( combo, 1, wxEXPAND|wxALL|wxALIGN_RIGHT, 5 ); + + sizerF->Add( new wxStaticText( panel, -1, wxU( "Subtitle" ) ), + 0, wxALL|wxALIGN_LEFT, 5 ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_SUBTITLE_LANGUAGE, wxU(""), + wxDefaultPosition, wxDefaultSize, 0, NULL, + wxCB_READONLY ); + sizerF->Add( combo, 1, wxEXPAND|wxALL|wxALIGN_RIGHT, 5 ); + + sbox->Add( sizerF, 0, wxALL, 5 ); + + sizerG->Add( sbox, 1, wxEXPAND|wxALL, 0 ); + + sizerV->Add( sizerG, 1, wxEXPAND|wxALL, 5 ); + + /* Output */ + ibox = new wxStaticBox( panel, -1, wxU("Output") ); + sbox = new wxStaticBoxSizer( ibox, wxVERTICAL); + + sizerF = new wxFlexGridSizer( 3, 1, 20 ); + sizerF->Add( new wxStaticText( panel, -1, wxU("File") ), + 0, wxALL|wxALIGN_LEFT, 5 ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_OUTPUT_FILE, wxU("") ); + + sizerF->Add( combo, 1, wxEXPAND|wxALIGN_RIGHT| + wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + button = new wxButton( panel, ID_SETTINGS_BT_FILE, wxU("Browse...")); + sizerF->Add( button, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL, 5 ); + sbox->Add( sizerF, 0, wxEXPAND|wxALL, 5 ); + + + sizerS = new wxBoxSizer( wxHORIZONTAL ); + + sizerF = new wxFlexGridSizer( 2, 2, 20 ); + + aQ.Clear(); + aQ.Add( wxU("800") ); aQ.Add( wxU("700") ); + aQ.Add( wxU("650") ); aQ.Add( wxU("350") ); + aQ.Add( wxU("250") ); aQ.Add( wxU("200") ); + aQ.Add( wxU("150") ); + radio = new wxRadioButton( panel, ID_SETTINGS_RD_OUTPUT_SIZE, wxU("Size") ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_OUTPUT_SIZE, wxU(""), + wxDefaultPosition, wxDefaultSize, aQ ); + sizerF->Add( radio, 0, wxALL|wxALIGN_LEFT ); + sizerF->Add( combo, 1, wxEXPAND|wxALL|wxALIGN_RIGHT ); + radio->SetValue( FALSE ); + combo->Enable( FALSE ); + + aQ.Clear(); + aQ.Add( wxU("2500") ); aQ.Add( wxU("2000") ); + aQ.Add( wxU("1500") ); aQ.Add( wxU("1000") ); + aQ.Add( wxU("800") ); aQ.Add( wxU("500") ); + aQ.Add( wxU("300") ); + radio = new wxRadioButton( panel, ID_SETTINGS_RD_OUTPUT_BITRATE, + wxU("Bitrate" ) ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_OUTPUT_BITRATE, aQ[3], + wxDefaultPosition, wxDefaultSize, aQ ); + sizerF->Add( radio, 0, wxALL|wxALIGN_LEFT ); + sizerF->Add( combo, 1, wxEXPAND|wxALL|wxALIGN_RIGHT ); + radio->SetValue( TRUE ); + combo->Enable( TRUE ); + + sizerS->Add( sizerF, 0, wxALL|wxALIGN_CENTER_VERTICAL ); + + + wxBoxSizer *sizerSS = new wxBoxSizer( wxHORIZONTAL ); + sizerSS->Add( new wxStaticText( panel, -1, wxU( "x" ) ), 0, wxALL, 5 ); + spin = new wxSpinCtrl( panel, ID_SETTINGS_SC_OUTPUT_FILE_COUNT, wxU("1"), + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, 1, 5, 1 ); + spin->Enable( FALSE ); + sizerSS->Add( spin, 0, wxALL, 5 ); + + sizerS->Add( sizerSS, 0, wxALL|wxALIGN_CENTER_VERTICAL ); + + sbox->Add( sizerS, 1, wxEXPAND|wxALL, 5 ); + + sizerV->Add( sbox, 1, wxEXPAND|wxALL, 5 ); + + panel->SetSizerAndFit( sizerV ); + + return panel; +} + +static wxPanel *PanelSettingsVideo( wxWindow *p_parent ) +{ + wxPanel *panel = new wxPanel( p_parent, -1, + wxDefaultPosition, wxSize(200, 200)); + wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 5, 20 ); + wxBoxSizer *sizer2; + wxBoxSizer *sizer3; + wxArrayString aS; + wxComboBox *combo; + wxCheckBox *check; + wxSpinCtrl *spin; + int i; + + + /* Codec */ + sizer->Add( new wxStaticText( panel, -1, wxU("Codec") ), + 1, wxEXPAND|wxALL|wxALIGN_LEFT, 5 ); + aS.Clear(); + aS.Add( wxU("FFmpeg") ); + aS.Add( wxU("XviD") ); + aS.Add( wxU("x264") ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_VIDEO_CODEC, aS[0], + wxDefaultPosition, wxDefaultSize, + aS, wxCB_READONLY ); + sizer->Add( combo, 0, wxALL|wxALIGN_RIGHT, 5 ); + + /* FPS */ + sizer->Add( new wxStaticText( panel, -1, wxU("Fps") ), + 1, wxEXPAND|wxALL|wxALIGN_LEFT, 5 ); + aS.Clear(); + for( i = 0; i < hb_video_rates_count; i++ ) + aS.Add( wxU(hb_video_rates[i].string) ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_VIDEO_FPS, wxU(""), + wxDefaultPosition, wxDefaultSize, + aS, wxCB_READONLY ); + sizer->Add( combo, 0, wxALL|wxALIGN_RIGHT, 5 ); + + + /* Deinterlace */ + check = new wxCheckBox( panel, ID_SETTINGS_CH_VIDEO_DEINTERLACE, + wxU("Deinterlace") ); + check->SetValue( FALSE ); + + sizer->Add( check, 1, wxEXPAND|wxALL|wxALIGN_LEFT, 5 ); + sizer->Add( 0, 0, 0 ); + + /* Crop */ + check = new wxCheckBox( panel, ID_SETTINGS_CH_VIDEO_CROP, wxU("Crop") ); + check->SetValue( FALSE ); + sizer->Add( check, 0, wxTOP|wxBOTTOM| + wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 ); +#if 0 + sizer2 = new wxBoxSizer( wxVERTICAL ); + radio = new wxRadioButton( panel, ID_SETTINGS_RD_VIDEO_AUTOCROP, + wxU("Autocrop" ) ); + radio->SetValue( TRUE ); + sizer2->Add( radio, 0, wxTOP|wxBOTTOM| + wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 ); + radio = new wxRadioButton( panel, ID_SETTINGS_RD_VIDEO_CUSTOMCROP, + wxU("Custom crop" ) ); + radio->SetValue( FALSE ); + sizer2->Add( radio, 0, wxTOP|wxBOTTOM| + wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 ); + sizer->Add( sizer2, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5 ); +#endif + + sizer2 = new wxBoxSizer( wxVERTICAL); + spin = new wxSpinCtrl( panel, ID_SETTINGS_SC_VIDEO_CROP_TOP, wxU(""), + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, 0, 2048, 2 ); + spin->Enable( FALSE ); + sizer2->Add( spin, 0, wxALL|wxALIGN_CENTER, 2 ); + sizer3 = new wxBoxSizer( wxHORIZONTAL); + spin = new wxSpinCtrl( panel, ID_SETTINGS_SC_VIDEO_CROP_LEFT, wxU(""), + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, 0, 2048, 2 ); + spin->Enable( FALSE ); + sizer3->Add( spin, 0, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 2 ); + spin = new wxSpinCtrl( panel, ID_SETTINGS_SC_VIDEO_CROP_RIGHT, wxU(""), + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, 0, 2048, 2 ); + spin->Enable( FALSE ); + sizer3->Add( spin, 0, wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 2 ); + sizer2->Add( sizer3, 0, wxALL|wxALIGN_CENTER ); + spin = new wxSpinCtrl( panel, ID_SETTINGS_SC_VIDEO_CROP_BOTTOM, wxU(""), + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, 0, 2048, 2 ); + spin->Enable( FALSE ); + sizer2->Add( spin, 0, wxALL|wxALIGN_CENTER, 2 ); + sizer->Add( sizer2, 0, wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + + /* Size */ + sizer->Add( new wxStaticText( panel, -1, wxU("Size") ), + 0, wxALL|wxALIGN_LEFT, 5 ); + sizer2 = new wxBoxSizer( wxHORIZONTAL ); + spin = new wxSpinCtrl( panel, ID_SETTINGS_SC_VIDEO_WIDTH, wxU(""), + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, 0, 2048, 2 ); + spin->Enable( FALSE ); + sizer2->Add( spin, 0, wxALL, 5 ); + sizer2->Add( new wxStaticText( panel, -1, wxU("x") ), 0, wxALL, 5 ); + spin = new wxSpinCtrl( panel, ID_SETTINGS_SC_VIDEO_HEIGHT, wxU(""), + wxDefaultPosition, wxDefaultSize, + wxSP_ARROW_KEYS, 0, 2048, 2 ); + spin->Enable( FALSE ); + sizer2->Add( spin, 0, wxALL, 5 ); + + sizer->Add( sizer2, 0, wxALL|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5 ); + +#if 0 + sizer->Add( new wxStaticText( panel, -1, wxU("Autocrop: []\n" + "Crop: [] [] [] []\n" + "2 pass: []\n" + "Width: []\n" + "Height: []\n" + "Preview [..]" ) ), + 0, wxALL, 5 ); +#endif + panel->SetSizerAndFit( sizer ); + panel->SetAutoLayout( TRUE ); + panel->Layout(); + + return panel; +} + +static wxPanel *PanelSettingsAudio( wxWindow *p_parent ) +{ + wxPanel *panel = new wxPanel( p_parent, -1, + wxDefaultPosition, wxSize(200, 200)); + wxFlexGridSizer * sizer = new wxFlexGridSizer( 2, 1, 20 ); + wxArrayString aS; + wxComboBox *combo; + unsigned int i; + +#if 0 + /* TODO in the right way (there is a few problem with file type) */ + /* Codec */ + sizer->Add( new wxStaticText( panel, -1, wxU("Codec") ), + 0, wxALL|wxALIGN_LEFT, 5 ); + aS.Clear(); + aS.Add( "Faac" ); + aS.Add( "Lame" ); + aS.Add( "Vorbis" ); + aS.Add( "Ac3" ); + aS.Add( "Mpga" ); + aS.Add( "LPCM" ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_VIDEO_CODEC, aS[0], + wxDefaultPosition, wxDefaultSize, + aS, wxCB_READONLY ); + sizer->Add( combo, 1, wxEXPAND|wxALL|wxALIGN_RIGHT, 5 ); +#endif + sizer->Add( new wxStaticText( panel, -1, wxU("Samplerate") ), + 1, wxEXPAND|wxALL|wxALIGN_LEFT, 5 ); + aS.Clear(); + for( i = 0; i < hb_audio_rates_count; i++ ) + aS.Add( wxString::Format( wxU("%d"), hb_audio_rates[i].rate ) ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_AUDIO_SAMPLERATE, wxU(""), + wxDefaultPosition, wxDefaultSize, + aS, wxCB_READONLY ); + sizer->Add( combo, 0, wxALL|wxALIGN_RIGHT, 5 ); + + + panel->SetSizerAndFit( sizer ); + + return panel; +} + +static wxPanel *PanelSettingsOthers( wxWindow *p_parent ) +{ + wxPanel *panel = new wxPanel( p_parent, -1, + wxDefaultPosition, wxSize(200, 200)); + + wxBoxSizer *sizer_row = new wxBoxSizer( wxVERTICAL ); + wxFlexGridSizer *sizer = new wxFlexGridSizer( 2, 2, 20 ); + wxComboBox *combo; + wxArrayString aS; + int i; + int i_count; + + + /* CPU */ + sizer->Add( new wxStaticText( panel, -1, wxU( "CPU" ) ), + 1, wxEXPAND|wxALL|wxALIGN_LEFT ); + + i_count = g_hbApp->GetSystemCpuCount(); + aS.Clear(); + for( i = 0; i < i_count; i++ ) + aS.Add( wxString::Format( wxU("%d"), i+1 ) ); + + combo = new wxComboBox( panel, ID_SETTINGS_CB_CPU, + aS[g_hbApp->GetDefaultCpuCount()-1], + wxDefaultPosition, wxDefaultSize, + aS, wxCB_READONLY ); + sizer->Add( combo, 0, wxALL|wxALIGN_RIGHT ); + + /* Priority */ + sizer->Add( new wxStaticText( panel, -1, wxU( "Priority" ) ), + 1, wxEXPAND|wxALL|wxALIGN_LEFT ); + + aS.Clear(); + aS.Add( wxU("Highest") ); + aS.Add( wxU("Above Normal") ); + aS.Add( wxU("Normal") ); + aS.Add( wxU("Below Normal") ); + aS.Add( wxU("Lowest") ); + combo = new wxComboBox( panel, ID_SETTINGS_CB_PRIORITY, + aS[4-g_hbApp->GetDefaultPriority()], + wxDefaultPosition, wxDefaultSize, + aS, wxCB_READONLY ); + sizer->Add( combo, 0, wxALL|wxALIGN_RIGHT ); + combo->Enable( FALSE ); /* Marche pas pr le moment */ + + sizer_row->Add( sizer, 0, wxEXPAND|wxALL, 5 ); + + panel->SetSizerAndFit( sizer_row ); + + return panel; +} + + +class hbWizardPageSettings: public wxWizardPageSimple +{ +public: + hbWizardPageSettings( wxWizard *p_wizard ); + virtual ~hbWizardPageSettings(); + + void OnBrowse( wxCommandEvent &event ); + void OnTitle( wxCommandEvent &event ); + void OnChapter( wxCommandEvent &event ); + void OnRadio( wxCommandEvent &event ); + void OnAudio( wxCommandEvent &event ); + + void SetTitle( int i_title = -1 ); + void OnPageChanging( wxWizardEvent &event ); + void OnPageChanged( wxWizardEvent &event ); + +private: + DECLARE_EVENT_TABLE() + wxFileDialog *dlgFile; +}; + +hbWizardPageSettings::hbWizardPageSettings( wxWizard *p_wizard ) : + wxWizardPageSimple(p_wizard) +{ + wxNotebook *nb = new wxNotebook( this, ID_SETTINGS_NB ); + wxNotebookSizer *sizerN = new wxNotebookSizer( nb ); + + /* General settings */ + nb->AddPage( PanelSettingsGeneral(nb), wxU("General"), TRUE ); + + /* Advanced */ + nb->AddPage( PanelSettingsVideo(nb), wxU("Advanced Video"), FALSE ); + + /* Advanced */ + nb->AddPage( PanelSettingsAudio(nb), wxU("Advanced Audio"), FALSE ); + + /* Others */ + nb->AddPage( PanelSettingsOthers(nb), wxU("Others"), FALSE ); + + + hbWizardPageHeaders( this, "Settings", "Set your settings ;).", + sizerN ); + + /* */ + dlgFile = NULL; +} + +hbWizardPageSettings::~hbWizardPageSettings() +{ +} + +void hbWizardPageSettings::SetTitle( int i_title ) +{ + wxArrayString &aT = *g_hbApp->GetTitles(); + wxArrayString *p_array; + wxComboBox *title; + wxComboBox *chp; + wxComboBox *lg; + wxComboBox *fps; + wxComboBox *arate; + wxString sL; + bool bSetDefault = false; + int i; + + /* Update title */ + title = (wxComboBox*)FindWindow( ID_SETTINGS_CB_TITLE ); + if( i_title < 0 ) + { + title->Clear(); + title->Append( aT ); + + i_title = g_hbApp->GetDefaultTitle(); + title->SetValue( aT[i_title] ); + bSetDefault = true; + } + + g_hbApp->SetTitle( i_title ); + + + /* Update chapter start/end */ + chp = (wxComboBox*)FindWindow( ID_SETTINGS_CB_CHAPTER_START ); + chp->Clear(); + for( i = 0; i < g_hbApp->GetChaptersCount(); i++ ) + chp->Append( wxString::Format( wxU("%d"), i+1 ) ); + chp->SetValue( wxU("1") ); + + chp = (wxComboBox*)FindWindow( ID_SETTINGS_CB_CHAPTER_END ); + chp->Clear(); + for( i = 0; i < g_hbApp->GetChaptersCount(); i++ ) + chp->Append( wxString::Format( wxU("%d"), i+1 ) ); + chp->SetValue( wxString::Format( wxU("%d"), g_hbApp->GetChaptersCount() ) ); + + /* Update Audio language */ + lg = (wxComboBox*)FindWindow( ID_SETTINGS_CB_AUDIO_LANGUAGE ); + sL = lg->GetValue(); + lg->Clear(); + p_array = g_hbApp->GetTracksAudio(); + lg->Append( *p_array ); + + if( bSetDefault || p_array->Index(sL) == wxNOT_FOUND ) + { + sL = g_hbApp->GetDefaultAudio(); + if( p_array->Index( sL ) == wxNOT_FOUND ) + sL = (*p_array)[0]; + } + lg->SetValue( sL ); + g_hbApp->SetTrackAudio( p_array->Index(sL) );/* Needed for audio settings */ + + lg = (wxComboBox*)FindWindow( ID_SETTINGS_CB_SUBTITLE_LANGUAGE ); + sL = lg->GetValue(); + lg->Clear(); + p_array = g_hbApp->GetTracksSubtitle(); + lg->Append( *p_array ); + + if( bSetDefault || p_array->Index(sL) == wxNOT_FOUND ) + { + sL = g_hbApp->GetDefaultSubtitle(); + if( p_array->Index( sL ) == wxNOT_FOUND ) + sL = p_array->Last(); + } + lg->SetValue( sL ); + + if( bSetDefault || g_hbApp->GetDefaultVideoRateBase() != 0 ) + { + int i_base = g_hbApp->GetDefaultVideoRateBase(); + + if( i_base == 0 || !bSetDefault ) + i_base = g_hbApp->GetVideoRateBase(); + + fps = (wxComboBox*)FindWindow( ID_SETTINGS_CB_VIDEO_FPS ); + for( i = 0; i < hb_video_rates_count; i++ ) + { + if( hb_video_rates[i].rate == i_base ) + { + fps->SetSelection( i ); + break; + } + } + } + + if( bSetDefault || g_hbApp->GetDefaultAudioSamplerate() != 0 ) + { + int i_rate = g_hbApp->GetDefaultAudioSamplerate(); + + if( i_rate == 0 || !bSetDefault ) + i_rate = g_hbApp->GetAudioSamplerate(); + if( i_rate == 0 ) + i_rate = 44100; + + arate = (wxComboBox*)FindWindow( ID_SETTINGS_CB_AUDIO_SAMPLERATE ); + arate->SetValue( wxString::Format( wxU("%d"), i_rate ) ); + } + + /* Set auto crop values and width size */ + if( bSetDefault ) + { + wxSpinCtrl *spin; + int crop[4]; + int i_width, i_height; + + g_hbApp->GetVideoAutocrop( crop ); + g_hbApp->GetVideoSize( &i_width, &i_height ); + + /* Crop */ + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_TOP ); + spin->SetValue( crop[0] ); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_BOTTOM ); + spin->SetValue( crop[1] ); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_LEFT ); + spin->SetValue( crop[2] ); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_RIGHT ); + spin->SetValue( crop[3] ); + + /* Size */ + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_WIDTH ); + spin->SetValue( i_width - (crop[2]+crop[3]) ); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_HEIGHT ); + spin->SetValue( i_height - (crop[0]+crop[1]) ); + } +} + + +void hbWizardPageSettings::OnTitle( wxCommandEvent &event ) +{ + SetTitle( event.GetSelection() ); +} + +void hbWizardPageSettings::OnChapter( wxCommandEvent &event ) +{ + wxComboBox *start = (wxComboBox*)FindWindow( ID_SETTINGS_CB_CHAPTER_START ); + wxComboBox *end = (wxComboBox*)FindWindow( ID_SETTINGS_CB_CHAPTER_END ); + + if( event.GetId() == ID_SETTINGS_CB_CHAPTER_START ) + { + if( start->GetSelection() > end->GetSelection() ) + end->SetSelection( start->GetSelection() ); + } + else + { + if( end->GetSelection() < start->GetSelection() ) + start->SetSelection( end->GetSelection() ); + } +} + +void hbWizardPageSettings::OnBrowse( wxCommandEvent &event ) +{ + if( dlgFile == NULL ) + dlgFile = new wxFileDialog( this, wxU( "Choose a file"), + wxGetCwd() ); + + if( dlgFile->ShowModal() == wxID_OK ) + { + const wxChar *p = dlgFile->GetPath(); + wxComboBox *file = (wxComboBox*)FindWindow(ID_SETTINGS_CB_OUTPUT_FILE); + file->SetValue( p ); + } +} + +void hbWizardPageSettings::OnRadio( wxCommandEvent &event ) +{ + wxRadioButton *rSize = + (wxRadioButton*)FindWindow( ID_SETTINGS_RD_OUTPUT_SIZE ); + wxRadioButton *rBitrate = + (wxRadioButton*)FindWindow( ID_SETTINGS_RD_OUTPUT_BITRATE ); + wxComboBox *cSize = + (wxComboBox*)FindWindow( ID_SETTINGS_CB_OUTPUT_SIZE ); + wxComboBox *cBitrate = + (wxComboBox*)FindWindow( ID_SETTINGS_CB_OUTPUT_BITRATE ); + + if( event.GetId() == ID_SETTINGS_RD_OUTPUT_SIZE ) + { + /* FIXME is that needed ?? */ + rBitrate->SetValue(FALSE); + cBitrate->Enable(FALSE); + cSize->Enable(TRUE); + } + else + { + rSize->SetValue(FALSE); + cSize->Enable(FALSE); + cBitrate->Enable(TRUE); + } +} +void hbWizardPageSettings::OnAudio( wxCommandEvent &event ) +{ + if( g_hbApp->GetDefaultAudioSamplerate() == 0 ) + { + int i_rate = g_hbApp->GetAudioSamplerate(); + wxComboBox *arate = + (wxComboBox*)FindWindow( ID_SETTINGS_CB_AUDIO_SAMPLERATE ); + + if( i_rate == 0 ) i_rate = 44100; + arate->SetValue( wxString::Format( wxU("%d"), i_rate ) ); + } +} + +void hbWizardPageSettings::OnPageChanging( wxWizardEvent &event ) +{ + wxComboBox *cFile; + wxComboBox *cChap; + wxComboBox *cLang; + wxComboBox *cQ; + wxComboBox *cCombo; + wxCheckBox *cCheck; + wxRadioButton *rSize; + wxSpinCtrl *spin; + int i_bitrate_audio; + int crop[4]; + int i_width, i_height; + + wxString sFile; + + if( !event.GetDirection() ) + return; + + /* We need to validate params and start encoding */ + + /* Get and Check validity of parameters */ + cFile = (wxComboBox*)FindWindow( ID_SETTINGS_CB_OUTPUT_FILE ); + sFile = cFile->GetValue(); + if( sFile.IsEmpty() ) + { + hbError( this, wxU("You have to give a output file name") ); + event.Veto(); + return; + } + g_hbApp->SetOutputFile( sFile ); + + /* Chapter start/end */ + cChap = (wxComboBox*)FindWindow( ID_SETTINGS_CB_CHAPTER_START ); + g_hbApp->SetChapterStart( cChap->GetSelection() + 1 ); + + cChap = (wxComboBox*)FindWindow( ID_SETTINGS_CB_CHAPTER_END ); + g_hbApp->SetChapterEnd( cChap->GetSelection() + 1 ); + + /* Audio */ + cLang = (wxComboBox*)FindWindow( ID_SETTINGS_CB_AUDIO_LANGUAGE ); + g_hbApp->SetTrackAudio( cLang->GetSelection(), 0 ); + /* FIXME find a better way */ + cQ = (wxComboBox*)FindWindow( ID_SETTINGS_CB_AUDIO_QUALITY ); + sscanf( cQ->GetValue().ToAscii(), "%*s - %d kb/s", &i_bitrate_audio ); + g_hbApp->SetAudioBitrate( i_bitrate_audio ); + + long arate; + cCombo = (wxComboBox*)FindWindow( ID_SETTINGS_CB_AUDIO_SAMPLERATE ); + cCombo->GetValue().ToLong( &arate ); + g_hbApp->SetAudioSamplerate( arate ); + + /* Subs */ + cLang = (wxComboBox*)FindWindow( ID_SETTINGS_CB_SUBTITLE_LANGUAGE ); + g_hbApp->SetTrackSubtitle( cLang->GetSelection() ); + + /* Video/Quality */ + cQ = (wxComboBox*)FindWindow( ID_SETTINGS_CB_VIDEO_QUALITY ); + if( cQ->GetSelection() == 3 ) + g_hbApp->SetVideoPass( 2 ); + else + g_hbApp->SetVideoPass( 1 ); + /* Video codec */ + cCombo = (wxComboBox*)FindWindow( ID_SETTINGS_CB_VIDEO_CODEC ); + g_hbApp->SetVideoCodec( cCombo->GetValue() ); + /* Video fps */ + cCombo = (wxComboBox*)FindWindow( ID_SETTINGS_CB_VIDEO_FPS ); + g_hbApp->SetVideoRateBase( hb_video_rates[cCombo->GetSelection()].rate ); + /* Deinterlace */ + cCheck = (wxCheckBox*)FindWindow( ID_SETTINGS_CH_VIDEO_DEINTERLACE ); + g_hbApp->SetVideoDeinterlace( cCheck->GetValue() ); + /* Crop */ + cCheck = (wxCheckBox*)FindWindow( ID_SETTINGS_CH_VIDEO_CROP ); + if( cCheck->GetValue() ) + { + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_TOP ); + crop[0] = spin->GetValue(); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_BOTTOM ); + crop[1] = spin->GetValue(); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_LEFT ); + crop[2] = spin->GetValue(); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_CROP_RIGHT ); + crop[3] = spin->GetValue(); + g_hbApp->SetVideoCrop( crop ); + } + else + { + g_hbApp->SetVideoCrop( NULL ); + } + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_WIDTH ); + i_width = spin->GetValue(); + spin = (wxSpinCtrl*)FindWindow( ID_SETTINGS_SC_VIDEO_HEIGHT ); + i_height = spin->GetValue(); + g_hbApp->SetVideoSize( i_width, i_height ); + + + rSize = (wxRadioButton*)FindWindow( ID_SETTINGS_RD_OUTPUT_SIZE ); + if( rSize->GetValue() ) + { + wxComboBox *cSize = + (wxComboBox*)FindWindow( ID_SETTINGS_CB_OUTPUT_SIZE ); + long i_size; + + cSize->GetValue().ToLong( &i_size ); + if( i_size <= 0 ) + { + hbError( this, wxU("Invalide file size") ); + event.Veto(); + return; + } + g_hbApp->SetTotalSize( i_size ); + } + else + { + wxComboBox *cBitrate = + (wxComboBox*)FindWindow( ID_SETTINGS_CB_OUTPUT_BITRATE ); + long i_bitrate; + + cBitrate->GetValue().ToLong( &i_bitrate ); + if( i_bitrate<= 0 ) + { + hbError( this, wxU("Invalid total bitrate") ); + event.Veto(); + return; + } + else if( i_bitrate <= i_bitrate_audio ) + { + hbError( this, wxU("Incompatible total bitrate with audio bitrate") ); + event.Veto(); + return; + } + g_hbApp->SetTotalBitrate( i_bitrate ); + } + + /* Other settings */ + /* CPU */ + cCombo = (wxComboBox*)FindWindow( ID_SETTINGS_CB_CPU ); + g_hbApp->SetCpuCount( cCombo->GetSelection() ); + + cCombo = (wxComboBox*)FindWindow( ID_SETTINGS_CB_PRIORITY ); + g_hbApp->SetPriority( cCombo->GetSelection() ); + + /* TODO finish */ + + /* Start the encode (TODO) */ + if( g_hbApp->Encode() < 0 ) + { + event.Veto(); /* Wrong */ + return; + } +} +void hbWizardPageSettings::OnPageChanged( wxWizardEvent &event ) +{ + /* Initialise avec le titre par d�faut */ + SetTitle(); +} + +BEGIN_EVENT_TABLE( hbWizardPageSettings, wxWizardPageSimple ) + EVT_BUTTON( ID_SETTINGS_BT_FILE, hbWizardPageSettings::OnBrowse ) + EVT_COMBOBOX( ID_SETTINGS_CB_TITLE, hbWizardPageSettings::OnTitle ) + EVT_COMBOBOX( ID_SETTINGS_CB_CHAPTER_START,hbWizardPageSettings::OnChapter) + EVT_COMBOBOX( ID_SETTINGS_CB_CHAPTER_END, hbWizardPageSettings::OnChapter ) + EVT_COMBOBOX( ID_SETTINGS_CB_AUDIO_LANGUAGE, hbWizardPageSettings::OnAudio ) + EVT_WIZARD_PAGE_CHANGING( -1, hbWizardPageSettings::OnPageChanging ) + EVT_WIZARD_PAGE_CHANGED( -1, hbWizardPageSettings::OnPageChanged ) + EVT_RADIOBUTTON( ID_SETTINGS_RD_OUTPUT_SIZE, hbWizardPageSettings::OnRadio) + EVT_RADIOBUTTON( ID_SETTINGS_RD_OUTPUT_BITRATE, hbWizardPageSettings::OnRadio) +END_EVENT_TABLE() + + +/***************************************************************************** + * hbWizardPageEncode: + *****************************************************************************/ +class hbWizardPageEncode: public wxWizardPageSimple +{ +public: + hbWizardPageEncode( wxWizard *p_wizard ); + virtual ~hbWizardPageEncode(); + +private: + //DECLARE_EVENT_TABLE() +}; + +hbWizardPageEncode::hbWizardPageEncode( wxWizard *p_wizard ) : + wxWizardPageSimple(p_wizard) +{ + wxBoxSizer *sizer; + sizer = new wxBoxSizer( wxVERTICAL ); +#if 0 + wxGauge * gauge; + sizer->Add( new wxStaticText( this, -1, wxU("Progess: x%%" ) ) ); + + gauge = new wxGauge( this, -1, 100 ); + gauge->SetValue( 50 ); + + sizer->Add( gauge ); +#endif + + + hbWizardPageHeaders( this, "Success", + "The encode is finished", + sizer ); + +} + +hbWizardPageEncode::~hbWizardPageEncode() +{ +} + +/**************************************************************************** + * hbWizard: + ****************************************************************************/ +hbWizard::hbWizard( wxWindow *p_parent) : + wxWizard( p_parent, -1, wxU("HandBrake"), wxNullBitmap, wxDefaultPosition) +{ + page1 = new hbWizardPageSource( this ); + page2 = new hbWizardPageSettings( this ); + page3 = new hbWizardPageEncode( this ); + + wxWizardPageSimple::Chain( page1, page2 ); + wxWizardPageSimple::Chain( page2, page3 ); + + //SetPageSize( wxSize( 500, 400 ) ); + FitToPage( page1 ); + FitToPage( page2 ); + FitToPage( page3 ); +} + +hbWizard::~hbWizard() +{ + Destroy(); + /* Is that ok */ + delete page1; + delete page2; + delete page3; +} + +void hbWizard::Run() +{ + fprintf( stderr, "hbWizard::Run\n" ); + + RunWizard( page1 ); +} + diff --git a/wx/hbWizard.h b/wx/hbWizard.h new file mode 100644 index 000000000..a66413abe --- /dev/null +++ b/wx/hbWizard.h @@ -0,0 +1,43 @@ +/***************************************************************************** + * wizard.h: + ***************************************************************************** + * Copyright (C) + * $Id: hbWizard.h,v 1.1 2005/01/16 15:59:21 titer Exp $ + * + * Authors: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +class hbWizardPageSource; +class hbWizardPageSettings; +class hbWizardPageEncode; + +class hbWizard: public wxWizard +{ +public: + hbWizard( wxWindow *p_parent ); + virtual ~hbWizard(); + + void Run(); + +private: + int i_essai; + hbWizardPageSource *page1; + hbWizardPageSettings *page2; + hbWizardPageEncode *page3; + + //DECLARE_EVENT_TABLE() +}; diff --git a/wx/wxHB.cpp b/wx/wxHB.cpp new file mode 100644 index 000000000..b336290dd --- /dev/null +++ b/wx/wxHB.cpp @@ -0,0 +1,684 @@ +/***************************************************************************** + * wxHB: + ***************************************************************************** + * Copyright (C) + * $Id: wxHB.cpp,v 1.8 2005/03/26 23:04:17 titer Exp $ + * + * Authors: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include "wxHB.h" +#include "hbWizard.h" + +#ifdef SYS_CYGWIN +# include <windows.h> +#endif + +/**************************************************************************** + * Definitions / Variables + ****************************************************************************/ +class hbApp *g_hbApp = NULL; + +IMPLEMENT_APP( hbApp ) + +/**************************************************************************** + * Helpers class + ****************************************************************************/ +class hbAppTimer: public wxTimer +{ +public: + hbAppTimer() + { + Start( 50, wxTIMER_CONTINUOUS ); + } + virtual void Notify() + { + g_hbApp->Update(); + } +}; + +class hbAppProgress: public wxDialog +{ +public: + hbAppProgress( wxWindow *parent, wxString title, wxString msg ) : + wxDialog( parent, -1, title, wxDefaultPosition, wxSize( 250, 300), + wxDEFAULT_DIALOG_STYLE ) + { + /* Create widgets */ + txt = new wxStaticText( this, -1, msg ); + gauge = new wxGauge( this, -1, 100 ); + button = new wxButton( this, wxID_CANCEL, wxU("Cancel") ); + + /* Add evrything in a sizer */ + wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL ); + sizer->Add( txt, 1, wxEXPAND|wxALIGN_CENTER|wxALL, 5 ); + + wxBoxSizer *sizerH = new wxBoxSizer( wxHORIZONTAL ); + sizerH->Add( gauge, 1, wxALIGN_CENTER|wxALL, 5 ); + sizer->Add( sizerH, 0, wxALIGN_CENTER|wxALL, 5 ); + + sizer->Add( button, 0, wxALIGN_CENTER_HORIZONTAL| + wxALIGN_BOTTOM|wxALL, 5 ); + //SetSizerAndFit( sizer ); + SetSizer( sizer ); + } + + void SetProgress( int i_percent, wxString msg ) + { + gauge->SetValue( i_percent ); + txt->SetLabel( msg ); + } + + void OnClose( wxCloseEvent &event ) + { + EndModal( wxID_CANCEL ); + } + +private: + wxStaticText *txt; + wxGauge *gauge; + wxButton *button; + + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE( hbAppProgress, wxDialog ) + EVT_CLOSE( hbAppProgress::OnClose ) +END_EVENT_TABLE() + +/**************************************************************************** + * hbApp class + ****************************************************************************/ + +/* OnInit: Call at the very start and put every in place + */ +bool hbApp::OnInit() +{ + /* Export hbApp */ + g_hbApp = this; + + + /* Init all variables */ + isEnd = false; + + progress = NULL; + + i_title = -1; + titles = NULL; + title = NULL; + + audios = NULL; + subs = NULL; + + systemDrive = NULL; + + /* Start HB */ + if( Init() ) + return false; + + /* Start out timer */ + timer = new hbAppTimer(); + + /* Create and Start the wizard */ + wizard = new hbWizard( NULL ); + wizard->Run(); + + /* Special hack FIXME */ + isEnd = true; + + return true; +} + +/* OnExit: + */ +int hbApp::OnExit() +{ + delete timer; + delete wizard; + + /* End hb */ + End(); + + /* Delete others FIXME */ + + return 0; +} + +/* Init: + */ +int hbApp::Init() +{ + /* Create a hb instance */ + hbHandle = hb_init( HB_DEBUG_NONE, 1 ); + if( hbHandle == NULL ) + return -1; + + return 0; +} +/* Scan: + */ +int hbApp::Scan( wxString sDevice ) +{ + if( sDevice.IsEmpty() ) + return -1; + + /* Reset state */ + i_title = -1; + if( titles ) delete titles; titles = NULL; + if( audios ) delete audios; audios = NULL; + if( subs ) delete subs; subs = NULL; + title = NULL; + + /* Append a \ if needed */ + if( sDevice.Length() == 2 && sDevice.Last() == ':' ) + sDevice.Append( '\\' ); + + /* Launch the scan (all titles) */ + hb_scan( hbHandle, sDevice.ToAscii(), 0 ); + + /* Create a progress report */ + progress = new hbAppProgress( wizard, wxU("Scanning..."), wxU("Opening ")+sDevice); + progress->ShowModal(); + + if( !hb_list_count( hb_get_titles( hbHandle ) ) ) + { + hbError( wizard, wxU("Scanning failed") ); + return -1; + } + + /* FIXME test if the scan is complete */ + + + return 0; +} +/* Encode: + */ +int hbApp::Encode() +{ + hb_state_t s; + + /* Maybe check a few things like: + * - compatible muxer and codecs */ + + /* Start the encoding */ + hb_add( hbHandle, title->job ); + hb_start( hbHandle ); + + /* FIXME use the wizard instead */ + /* Create a progress report */ + progress = new hbAppProgress( wizard, wxU("Encoding..."), wxU("0%")); + progress->ShowModal(); + + hb_get_state( hbHandle, &s ); + if( s.param.workdone.error != HB_ERROR_NONE ) + { + hb_stop( hbHandle ); /* FIXME to a proper handling */ + hbError( wizard, wxU("Encoding failed/stopped") ); + return -1; + } + + /* bad */ + return 0; +} + +/* End: + */ +void hbApp::End() +{ + hb_close( &hbHandle ); +} + + +wxArrayString *hbApp::GetTitles() +{ + hb_list_t *list; + int i_count; + int i; + + if( titles ) + return titles; + + /* Create the title list */ + list = hb_get_titles( hbHandle ); + + i_count = hb_list_count( list ); + if( i_count <= 0 ) + return NULL; + + titles = new wxArrayString(); + for( i = 0; i < i_count; i++ ) + { + hb_title_t *t = (hb_title_t*)hb_list_item( list, i ); + wxString name = wxString::Format( wxU("%d - %d:%02d:%02d"), + t->index, + t->hours, t->minutes, t->seconds ); + titles->Add( name ); + } + + return titles; +} + +void hbApp::SetTitle( int _i_title ) +{ + int i; + + if( i_title == _i_title ) + return; + + i_title = _i_title; + title = (hb_title_t*)hb_list_item( hb_get_titles( hbHandle ), i_title ); + if( audios ) delete audios; audios = NULL; + if( subs ) delete subs; subs = NULL; + + for( i = 0; i < 8; i++ ) + title->job->audios[i] = -1; + title->job->subtitle = -1; +} + +int hbApp::GetDefaultTitle() +{ + hb_list_t *list; + int i_best = -1; + int i_best_length = 0; + int i; + + list = hb_get_titles( hbHandle ); + for( i = 0; i < hb_list_count( list ); i++ ) + { + hb_title_t *t = (hb_title_t*)hb_list_item( list, i ); + int i_length = t->hours * 3600 + t->minutes*60 + t->seconds; + + if( i_best < 0 || i_length > i_best_length ) + { + i_best = i; + i_best_length = i_length; + } + } + + return i_best; +} + + + +int hbApp::GetChaptersCount() +{ + if( i_title < 0 ) + return 0; + + return hb_list_count( title->list_chapter ); +} + +void hbApp::SetChapterStart( int i_chapter ) +{ + title->job->chapter_start = i_chapter; +} + +void hbApp::SetChapterEnd( int i_chapter ) +{ + title->job->chapter_end = i_chapter; +} + +wxArrayString *hbApp::GetTracksAudio() +{ + int i; + if( audios ) + return audios; + + audios = new wxArrayString(); + for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + { + hb_audio_t *a = (hb_audio_t*)hb_list_item( title->list_audio, i ); + + audios->Add( wxU(a->lang) ); + } + audios->Add( wxU("None") ); + + return audios; +} +void hbApp::SetTrackAudio( int i_track, int i_pos ) +{ + if( i_pos >= 0 && i_pos < hb_list_count( title->list_audio ) ) + title->job->audios[i_pos] = i_track; + else + title->job->audios[i_pos] = -1; +} + +wxArrayString *hbApp::GetTracksSubtitle() +{ + int i; + + if( subs ) + return subs; + + subs = new wxArrayString(); + for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + { + hb_subtitle_t *s = + (hb_subtitle_t*)hb_list_item( title->list_subtitle, i ); + + subs->Add( wxU(s->lang) ); + } + subs->Add( wxU("None") ); + + return subs; +} + +void hbApp::SetTrackSubtitle( int i_track ) +{ + if( i_track >= 0 && i_track < hb_list_count( title->list_subtitle ) ) + title->job->subtitle = i_track; + else + title->job->subtitle = -1; +} + +void hbApp::SetOutputFile( wxString sFile ) +{ + char *psz; + + title->job->file = strdup( sFile.ToAscii() ); /* FIXME do we need strdup ? */ + + psz = strrchr( title->job->file, '.' ); + if( psz == NULL ) + title->job->mux = HB_MUX_AVI; /* By default, FIXME */ + else if( !strcasecmp( psz, ".avi" ) ) + title->job->mux = HB_MUX_AVI; + else if( !strcasecmp( psz, ".mp4" ) || !strcasecmp( psz, ".mov") ) + title->job->mux = HB_MUX_MP4; + else if( !strcasecmp( psz, ".ogg" ) || !strcasecmp( psz, ".ogm") ) + title->job->mux = HB_MUX_OGM; + else + title->job->mux = HB_MUX_AVI; /* By default */ + + /* Fix acodec value */ + switch( title->job->mux ) + { + case HB_MUX_AVI: + title->job->acodec = HB_ACODEC_LAME; + break; + case HB_MUX_MP4: + title->job->acodec = HB_ACODEC_FAAC; + break; + case HB_MUX_OGM: + title->job->acodec = HB_ACODEC_VORBIS; + break; + } +} + +void hbApp::SetAudioBitrate( int i_bitrate ) +{ + int i_old = title->job->abitrate; + + title->job->abitrate = i_bitrate; + + if( title->job->vbitrate > 0 ) + title->job->vbitrate = title->job->vbitrate + (i_old - i_bitrate); +} + +void hbApp::SetTotalBitrate( int i_bitrate ) +{ + title->job->vbitrate = i_bitrate - title->job->abitrate; + + if( title->job->vbitrate <= 0 ) + title->job->vbitrate = 1; +} + +void hbApp::SetTotalSize( int i_size ) +{ + /* XXX */ +} + +void hbApp::SetVideoPass( int i_pass ) +{ + /* FIXME is 0 or 1 valid for 1 pass ? */ + if( i_pass <= 1 ) + title->job->pass = 0; + else if( i_pass == 2 ) + title->job->pass = 2; +} + +void hbApp::SetVideoCodec( wxString sCodec ) +{ + if( sCodec.Lower() == wxU("ffmpeg") ) + title->job->vcodec = HB_VCODEC_FFMPEG; + else if( sCodec.Lower() == wxU("xvid") ) + title->job->vcodec = HB_VCODEC_XVID; + else if( sCodec.Lower() == wxU("x264") ) + title->job->vcodec = HB_VCODEC_XVID; +} + +void hbApp::SetVideoDeinterlace( bool b_deinterlace ) +{ + title->job->deinterlace = b_deinterlace ? 1 : 0; +} + +void hbApp::SetPriority( int i_priority ) +{ + /* Doesn't work :(( */ +#ifdef SYS_CYGWIN + switch( i_priority ) + { + case HB_PRIORITY_ABOVE_NORMAL: + i_priority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case HB_PRIORITY_BELOW_NORMAL: + i_priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case HB_PRIORITY_LOWEST: + i_priority = THREAD_PRIORITY_LOWEST; + break; + case HB_PRIORITY_HIGHEST: + i_priority = THREAD_PRIORITY_HIGHEST; + break; + + case HB_PRIORITY_NORMAL: + default: + i_priority = THREAD_PRIORITY_NORMAL; + break; + } + ::SetThreadPriority( GetCurrentThread(), i_priority ); +#else + /* TODO */ +#endif +} + +void hbApp::SetCpuCount( int i_cpu ) +{ + hb_set_cpu_count( hbHandle, i_cpu ); +} + +int hbApp::GetVideoRateBase() +{ + return title->rate_base; +} + +void hbApp::SetVideoRateBase( int i_base ) +{ + title->job->vrate_base = i_base; + title->job->vrate = HB_VIDEO_RATE_BASE; +} +void hbApp::GetVideoAutocrop( int crop[4] ) +{ + int i; + for( i = 0; i < 4; i++ ) + crop[i] = title->crop[i]; +} +void hbApp::SetVideoCrop( int crop[4] ) +{ + int i; + for( i = 0; i < 4; i++ ) + title->job->crop[i] = crop ? crop[i] : 0; +} +void hbApp::GetVideoSize( int *pi_width, int *pi_height ) +{ + *pi_width = title->width; + *pi_height = title->height; +} +void hbApp::SetVideoSize( int i_width, int i_height ) +{ + title->job->width = i_width; + title->job->height = i_height; +} + + +int hbApp::GetAudioSamplerate() +{ + int idx = title->job->audios[0]; + if( idx >= 0 && idx < hb_list_count( title->list_audio ) ) + { + hb_audio_t *a = (hb_audio_t*)hb_list_item( title->list_audio, 0 ); + return a->rate; + } + + /* FIXME not good */ + return title->job->arate; +} + +void hbApp::SetAudioSamplerate( int i_rate ) +{ + title->job->arate = i_rate; +} + +wxString hbApp::GetDefaultAudio() +{ + return wxU("English"); +} + +wxString hbApp::GetDefaultSubtitle() +{ + return wxU("None"); +} + +int hbApp::GetDefaultCpuCount() +{ + return GetSystemCpuCount(); +} + +int hbApp::GetDefaultPriority() +{ + return HB_PRIORITY_NORMAL; +} + +int hbApp::GetDefaultVideoRateBase() +{ + return 0; +} + +int hbApp::GetDefaultAudioSamplerate() +{ + return 0; +} + +/* Drive */ +wxArrayString *hbApp::GetSystemDrive() +{ + if( systemDrive ) + return systemDrive; + + systemDrive = new wxArrayString(); +#ifdef SYS_CYGWIN + char c; + for( c = 'A'; c <= 'Z'; c++ ) + { + char pszDrive[4]; + pszDrive[0] = c; + pszDrive[1] = ':'; + pszDrive[2] = '\\'; + pszDrive[3] = '\0'; + + if( GetDriveType( pszDrive ) == DRIVE_CDROM ) + systemDrive->Add( wxString::Format( wxU("%c:"), c ) ); + } +#else + /* TODO true detection */ + systemDrive->Add( wxU("/dev/dvd") ); + systemDrive->Add( wxU("/dev/cdrom") ); +#endif + + return systemDrive; +} + +int hbApp::GetSystemCpuCount() +{ + return hb_get_cpu_count(); +} + +void hbApp::Update() +{ + hb_state_t s; + + /* Special hack FIXME */ + if( isEnd ) + { + g_hbApp->ExitMainLoop(); + return; + } + + /* */ + hb_get_state( hbHandle, &s ); + switch( s.state ) + { + case HB_STATE_IDLE: + break; + + case HB_STATE_SCANNING: + { + int i_cur = s.param.scanning.title_cur; + int i_cnt = s.param.scanning.title_count; + + if( i_cnt > 0 ) + { + progress->SetProgress( 100*(i_cur-1)/i_cnt, + wxString::Format(wxU("Scanning title %d of %d."), + i_cur, i_cnt) ); + } + break; + } + + case HB_STATE_SCANDONE: + if( progress ) + { + progress->SetProgress( 100, wxU("Scanning complete.") ); + progress->Close( TRUE ); + //delete progress; + progress = NULL; + } + break; + + case HB_STATE_WORKING: + { + float f_progress = s.param.working.progress; + float f_rate_cur = s.param.working.rate_cur; + float f_rate_avg = s.param.working.rate_avg; + + progress->SetProgress( (int)(100 * f_progress), + wxString::Format(wxU("Encoding: %.2f %% (%.2f fps, avg %.2f fps)\n"), + 100.0 * f_progress, f_rate_cur, f_rate_avg )); + break; + } + + case HB_STATE_WORKDONE: + if( progress ) + { + progress->SetProgress( 100, wxU("Encoding complete.") ); + progress->Close( TRUE ); + //delete progress; + progress = NULL; + } + break; + } +} + diff --git a/wx/wxHB.h b/wx/wxHB.h new file mode 100644 index 000000000..c762305d7 --- /dev/null +++ b/wx/wxHB.h @@ -0,0 +1,170 @@ +/***************************************************************************** + * wxHB: + ***************************************************************************** + * Copyright (C) + * $Id: wxHB.h,v 1.2 2005/01/16 17:44:56 titer Exp $ + * + * Authors: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +#include "hb.h" + +#include <wx/wx.h> +#include <wx/wizard.h> +#include <wx/listctrl.h> +#include <wx/textctrl.h> +#include <wx/notebook.h> +#include <wx/spinctrl.h> +#include <wx/dnd.h> +#include <wx/treectrl.h> +#include <wx/gauge.h> +#include <wx/accel.h> +#include <wx/checkbox.h> +#include <wx/image.h> +#include <wx/wizard.h> + +#include "wx/file.h" +#include "wx/mstream.h" +#include "wx/wfstream.h" +#include <wx/statline.h> + +#if wxUSE_UNICODE +#define wxU(psz) wxString(psz, *wxConvCurrent) +#else +#define wxU(psz) psz +#endif + +/* Unique global variable: our App + * XXX: we could use wxGetApp() instead (but it is a bit longer ;) + */ +extern class hbApp *g_hbApp; + +/* */ +class hbAppTimer; +class hbAppProgress; +class hbWizard; + +/* */ +enum +{ + HB_PRIORITY_LOWEST = 0, + HB_PRIORITY_BELOW_NORMAL, + HB_PRIORITY_NORMAL, + HB_PRIORITY_ABOVE_NORMAL, + HB_PRIORITY_HIGHEST, +}; + +/* Our wxApp */ +class hbApp: public wxApp +{ +public: + virtual bool OnInit(); + virtual int OnExit(); + + /* HB related */ + int Init(); + int Scan( wxString sDevice ); + int Encode(); + void End(); + + /* */ + /* XXX: the wxArrayString aren't duplicated, so don't delete them */ + wxArrayString *GetTitles(); + void SetTitle( int i_title ); + + int GetChaptersCount(); + void SetChapterStart( int i_chapter ); + void SetChapterEnd( int i_chapter ); + + wxArrayString *GetTracksAudio(); + void SetTrackAudio( int i_track, int i_pos = 0 ); + + wxArrayString *GetTracksSubtitle(); + void SetTrackSubtitle( int i_track ); + + void SetOutputFile( wxString ); + void SetAudioBitrate( int ); + void SetTotalBitrate( int ); + void SetTotalSize( int ); + void SetVideoPass( int ); + void SetPriority( int ); + void SetVideoCodec( wxString ); + void SetVideoDeinterlace( bool ); + void SetCpuCount( int ); + + int GetVideoRateBase(); + void SetVideoRateBase( int ); + + int GetAudioSamplerate(); + void SetAudioSamplerate( int ); + + void GetVideoAutocrop( int crop[4] ); + void SetVideoCrop( int crop[4] ); + void GetVideoSize( int *pi_width, int *pi_height ); + void SetVideoSize( int i_width, int i_height ); + + + /* Get Default value (from config file or from logic) */ + int GetDefaultTitle(); + wxString GetDefaultAudio(); + wxString GetDefaultSubtitle(); + int GetDefaultCpuCount(); + int GetDefaultPriority(); + int GetDefaultVideoRateBase(); + int GetDefaultAudioSamplerate(); + + /* Drive */ + wxArrayString *GetSystemDrive(); + int GetSystemCpuCount(); + + + /* wx related */ + /* Called regulary by a timer + * FIXME derive hbApp from timer too instead ? */ + void Update(); + +private: + bool isEnd; + + hbAppTimer *timer; + hbWizard *wizard; + hbAppProgress *progress; + + hb_handle_t *hbHandle; + + /* */ + int i_title; + wxArrayString *titles; + hb_title_t *title; + + int i_chapters; + wxArrayString *audios; + wxArrayString *subs; + + /* System */ + wxArrayString *systemDrive; +}; + +static void hbError( wxWindow *p_parent, wxString sTitle ) +{ + wxMessageDialog *dlg = new wxMessageDialog( p_parent, + sTitle, + wxU("Error"), + wxOK|wxCENTRE|wxICON_ERROR ); + dlg->ShowModal(); + delete dlg; +} |