summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYING340
-rw-r--r--CREDITS116
-rw-r--r--HBAc3Decoder.cpp130
-rw-r--r--HBAc3Decoder.h29
-rw-r--r--HBApp.cpp68
-rw-r--r--HBApp.h23
-rw-r--r--HBAviMuxer.cpp332
-rw-r--r--HBAviMuxer.h149
-rw-r--r--HBCommon.cpp566
-rw-r--r--HBCommon.h146
-rw-r--r--HBDVDReader.cpp67
-rw-r--r--HBDVDReader.h23
-rw-r--r--HBFifo.cpp161
-rw-r--r--HBFifo.h61
-rw-r--r--HBManager.cpp319
-rw-r--r--HBManager.h55
-rw-r--r--HBMp3Encoder.cpp115
-rw-r--r--HBMp3Encoder.h30
-rw-r--r--HBMpeg2Decoder.cpp168
-rw-r--r--HBMpeg2Decoder.h27
-rw-r--r--HBMpeg4Encoder.cpp88
-rw-r--r--HBMpeg4Encoder.h27
-rw-r--r--HBMpegDemux.cpp244
-rw-r--r--HBMpegDemux.h38
-rw-r--r--HBPictureWin.cpp288
-rw-r--r--HBPictureWin.h52
-rw-r--r--HBThread.cpp49
-rw-r--r--HBThread.h26
-rw-r--r--HBWindow.cpp630
-rw-r--r--HBWindow.h62
-rw-r--r--HandBrake.cpp18
-rw-r--r--Jamfile14
-rw-r--r--NEWS15
33 files changed, 4476 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 000000000..d60c31a97
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/CREDITS b/CREDITS
new file mode 100644
index 000000000..b8dee5f5b
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,116 @@
+HandBrake uses a lot of cool libraries from the GNU/Linux world. Thank their authors !
+
+libdvdcss authors :
+
+Billy Biggs
+Stéphane Borel
+Håkan Hjort
+Samuel Hocevar
+Eugenio Jarosiewicz
+Jon Lech Johansen
+Markus Kuespert
+Pascal Levesque
+Steven M. Schultz
+David Siebörger
+Alex Strelnikov
+German Tischler
+Gildas Bazin
+
+libdvdread authors :
+
+Björn Englund
+Hâkan Hjort
+Billy Biggs
+Christian Wolff
+
+libdvdplay authors :
+
+Håkan Hjort
+Martin Norbäck
+Stéphane Borel
+
+mpeg2dec authors :
+
+Aaron Holtzman
+Michel Lespinasse
+Bruno Barreyra
+Gildas Bazin
+Alexander W. Chin
+Stephen Crowley
+Didier Gautheron
+Ryan C. Gordon
+Peter Gubanov
+Hâkan Hjort
+Nicolas Joly
+Gerd Knorr
+David I. Lehn
+Olie Lho
+Rick Niles
+Real Ouellet
+Bajusz Peter
+Franck Sicard
+Brion Vibber
+Martin Vogt
+Fredrik Vraalsen
+
+Ffmpeg authors :
+
+Fabrice Bellard
+Alex Beregszaszi
+Brian Foley
+Arpad Gereoffy
+Philip Gladstone
+Falk Hueffner
+Zdenek Kabelac
+Nick Kurshev
+Michael Niedermayer
+François Revol
+Dieter Shirley
+Juan J. Sierralta
+Lionel Ulmer
+
+a52dec authors :
+
+Aaron Holtzman
+Michel Lespinasse
+Gildas Bazin
+Billy Biggs
+Eduard Hasenleithner
+Håkan Hjort
+Charles M. Hannum
+Chris Hodges
+Michael Holzt
+Angelos Keromytis
+David I. Lehn
+Don Mahurin
+Jim Miller
+Takefumi Sayo
+Shoji Tokunaga
+
+lame authors :
+
+Mike Cheng
+Robert Hegemann
+Frank Klemm
+Alexander Leidinger
+Naoki Shibata
+Mark Taylor
+Takehiro Tominiga
+Iván Cavero Belaunde
+Gabriel Bouvigne
+Florian Bomers
+CISC
+John Dahlstrom
+John Dee
+Albert Faber
+Peter Gubanov
+Lars Magne Ingebrigtsen
+Yosi Markovich
+Zdenek Kabelac
+Iwasa Kazmi
+Guillaume Lessard
+Steve Lhomme
+Don Melton
+Viral Shah
+Acy Stapp
+Roel VdB
diff --git a/HBAc3Decoder.cpp b/HBAc3Decoder.cpp
new file mode 100644
index 000000000..81753d899
--- /dev/null
+++ b/HBAc3Decoder.cpp
@@ -0,0 +1,130 @@
+/* $Id: HBAc3Decoder.cpp,v 1.6 2003/08/24 15:03:41 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBAc3Decoder.h"
+#include "HBManager.h"
+#include "HBFifo.h"
+
+extern "C" {
+#include <a52dec/a52.h>
+}
+
+HBAc3Decoder::HBAc3Decoder( HBManager * manager, HBAudioInfo * audioInfo )
+ : HBThread( "ac3decoder" )
+{
+ fManager = manager;
+ fAudioInfo = audioInfo;
+
+ fAc3Buffer = NULL;
+ fAc3Frame = NULL;
+ fPosInAc3Buffer = 0;
+}
+
+void HBAc3Decoder::DoWork()
+{
+ /* Init liba52 */
+ a52_state_t * state = a52_init( 0 );
+ int inFlags = 0;
+ int outFlags = A52_STEREO;
+ float sampleLevel = 32768; /* lame wants samples from
+ -32768 to 32768 */
+
+ /* Max size for a A52 frame is 3840 bytes */
+ fAc3Frame = new HBBuffer( 3840 );
+
+ int frameSize;
+ HBBuffer * rawBuffer;
+ sample_t * samples;
+
+ /* Main loop */
+ while( !fDie )
+ {
+ fAc3Frame->fSize = 0;
+
+ /* Get a frame header (7 bytes) */
+ if( !( GetBytes( 7 ) ) )
+ {
+ continue;
+ }
+
+ /* Get the size of the current frame */
+ frameSize = a52_syncinfo( fAc3Frame->fData, &inFlags,
+ &fAudioInfo->fInSampleRate,
+ &fAudioInfo->fInBitrate );
+
+ if( !frameSize )
+ {
+ Log( "HBAc3Decoder : a52_syncinfo failed" );
+ fManager->Error();
+ break;
+ }
+
+ /* Get the whole frame */
+ if( !( GetBytes( (uint32_t) frameSize ) ) )
+ {
+ continue;
+ }
+
+ /* Feed liba52 */
+ a52_frame( state, fAc3Frame->fData, &outFlags, &sampleLevel, 0 );
+
+ /* 6 blocks per frame, 256 samples per block */
+ rawBuffer = new HBBuffer( 12 * 256 * sizeof( float ) );
+ for( int i = 0; i < 6; i++ )
+ {
+ /* Decode a block */
+ a52_block( state );
+
+ /* Get a pointer to the raw data */
+ samples = a52_samples( state );
+
+ /* Copy left channel data */
+ memcpy( (float*) rawBuffer->fData + i * 256,
+ samples,
+ 256 * sizeof( float ) );
+
+ /* Copy right channel data */
+ memcpy( (float*) rawBuffer->fData + ( 6 + i ) * 256,
+ samples + 256,
+ 256 * sizeof( float ) );
+ }
+
+ fAudioInfo->fRawFifo->Push( rawBuffer );
+ }
+
+ /* Clean up */
+ delete fAc3Frame;
+}
+
+/* GetBytes() : pops buffers from the AC3 fifo until fAc3Frame
+ contains <size> bytes */
+bool HBAc3Decoder::GetBytes( uint32_t size )
+{
+ while( fAc3Frame->fSize < size )
+ {
+ if( !fAc3Buffer )
+ {
+ if( !( fAc3Buffer = fAudioInfo->fAc3Fifo->Pop() ) )
+ {
+ return false;
+ }
+ fPosInAc3Buffer = 0;
+ }
+
+ int willCopy = MIN( size - fAc3Frame->fSize,
+ fAc3Buffer->fSize - fPosInAc3Buffer );
+ memcpy( fAc3Frame->fData + fAc3Frame->fSize,
+ fAc3Buffer->fData + fPosInAc3Buffer,
+ willCopy );
+ fAc3Frame->fSize += willCopy;
+ fPosInAc3Buffer += willCopy;
+
+ if( fAc3Buffer->fSize == fPosInAc3Buffer )
+ {
+ delete fAc3Buffer;
+ fAc3Buffer = NULL;
+ }
+ }
+
+ return true;
+}
diff --git a/HBAc3Decoder.h b/HBAc3Decoder.h
new file mode 100644
index 000000000..75e7553da
--- /dev/null
+++ b/HBAc3Decoder.h
@@ -0,0 +1,29 @@
+/* $Id: HBAc3Decoder.h,v 1.5 2003/08/24 15:03:41 titer Exp $ */
+
+#ifndef HB_AC3_DECODER_H
+#define HB_AC3_DECODER_H
+
+#include "HBThread.h"
+class HBAudioInfo;
+class HBBuffer;
+class HBManager;
+
+class HBAc3Decoder : public HBThread
+{
+ public:
+ HBAc3Decoder( HBManager * manager, HBAudioInfo * audioInfo );
+
+ private:
+ void DoWork();
+ bool GetBytes( uint32_t size );
+ void PushSilence();
+
+ HBManager * fManager;
+ HBAudioInfo * fAudioInfo;
+
+ HBBuffer * fAc3Buffer;
+ HBBuffer * fAc3Frame;
+ uint32_t fPosInAc3Buffer;
+};
+
+#endif
diff --git a/HBApp.cpp b/HBApp.cpp
new file mode 100644
index 000000000..142b16cb8
--- /dev/null
+++ b/HBApp.cpp
@@ -0,0 +1,68 @@
+/* $Id: HBApp.cpp,v 1.6 2003/08/24 20:25:49 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBApp.h"
+#include "HBWindow.h"
+#include "HBManager.h"
+
+/* Constructor */
+HBApp::HBApp()
+ : BApplication( "application/x-vnd.titer-handbrake" )
+{
+ /* Initializations */
+ fWindow = new HBWindow();
+ fManager = new HBManager( fWindow );
+
+ /* Tell the interface we now have a manager */
+ BMessage * message = new BMessage( MANAGER_CREATED );
+ message->AddPointer( "manager", fManager );
+ fWindow->PostMessage( message );
+ delete message;
+
+ /* Show the main window */
+ fWindow->Show();
+
+ /* Check the available DVDs */
+ Status( "Checking DVD volumes...", 0.0, ENABLE_DETECTING );
+ fManager->PostMessage( DETECT_VOLUMES );
+}
+
+void HBApp::MessageReceived( BMessage * message )
+{
+ switch( message->what )
+ {
+ case PRINT_MESSAGE:
+ {
+ /* See Log() in HBCommon.cpp */
+ char * string;
+ message->FindPointer( "string", (void**) &string );
+ fprintf( stderr, string );
+ free( string );
+ break;
+ }
+
+ case CHANGE_STATUS:
+ {
+ fWindow->PostMessage( message );
+ break;
+ }
+
+ default:
+ {
+ BApplication::MessageReceived( message );
+ }
+ }
+}
+
+bool HBApp::QuitRequested()
+{
+ if( fManager->Cancel() )
+ {
+ /* We have log messages waiting, quit only after having
+ displayed them */
+ PostMessage( B_QUIT_REQUESTED );
+ return false;
+ }
+
+ return true;
+}
diff --git a/HBApp.h b/HBApp.h
new file mode 100644
index 000000000..0e92a9dee
--- /dev/null
+++ b/HBApp.h
@@ -0,0 +1,23 @@
+/* $Id: HBApp.h,v 1.1.1.1 2003/06/24 13:43:48 titer Exp $ */
+
+#ifndef _HB_APP_H
+#define _HB_APP_H
+
+#include <Application.h>
+
+class HBWindow;
+class HBManager;
+
+class HBApp : public BApplication
+{
+ public:
+ HBApp();
+ virtual void MessageReceived( BMessage * message );
+ virtual bool QuitRequested();
+
+ private:
+ HBWindow * fWindow;
+ HBManager * fManager;
+};
+
+#endif
diff --git a/HBAviMuxer.cpp b/HBAviMuxer.cpp
new file mode 100644
index 000000000..8c5d42176
--- /dev/null
+++ b/HBAviMuxer.cpp
@@ -0,0 +1,332 @@
+/* $Id: HBAviMuxer.cpp,v 1.21 2003/08/24 13:34:18 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBAviMuxer.h"
+#include "HBManager.h"
+#include "HBFifo.h"
+
+#define AVIF_HASINDEX 0x10
+#define AVIIF_KEYFRAME 0x10
+
+HBAviMuxer::HBAviMuxer( HBManager * manager, HBTitleInfo * titleInfo,
+ HBAudioInfo * audio1Info, HBAudioInfo * audio2Info,
+ char * fileName )
+ : HBThread( "avimuxer" )
+{
+ fManager = manager;
+ fTitleInfo = titleInfo;
+ fAudio1Info = audio1Info;
+ fAudio2Info = audio2Info;
+ fFileName = strdup( fileName );
+
+ fRiffBytesCount = 2040;
+ fMoviBytesCount = 4;
+}
+
+void HBAviMuxer::DoWork()
+{
+ /* Open the destination file */
+ if( !( fFile = fopen( fFileName, "w" ) ) )
+ {
+ Log( "HBAviMuxer: fopen failed" );
+ fManager->Error();
+ return;
+ }
+
+ /* Initializations */
+ memset( &fMainHeader, 0, sizeof( AviMainHeader ) );
+ memset( &fVideoStreamHeader, 0, sizeof( AviStreamHeader ) );
+ memset( &fAudio1StreamHeader, 0, sizeof( AviStreamHeader ) );
+ memset( &fAudio2StreamHeader, 0, sizeof( AviStreamHeader ) );
+ memset( &fVideoStreamFormat, 0, sizeof( BitmapInfo ) );
+ memset( &fAudio1StreamFormat, 0, sizeof( WaveFormatEx ) );
+ memset( &fAudio2StreamFormat, 0, sizeof( WaveFormatEx ) );
+
+ /* Alloc an 1 MB index (to be realloced later if needed) */
+ fIndex = new HBBuffer( 1024 * 1024 );
+ sprintf( (char*) fIndex->fData, "idx1" );
+ fIndex->fSize = 8;
+
+ /* Main loop */
+ int video, audio1, audio2;
+ while( !fDie )
+ {
+ /* Find the most filled fifo */
+ video = fTitleInfo->fMpeg4Fifo->Size();
+ audio1 = ( !fAudio1Info->fId ) ? 0 : fAudio1Info->fMp3Fifo->Size();
+ audio2 = ( !fAudio2Info->fId ) ? 0 : fAudio2Info->fMp3Fifo->Size();
+
+ /* Nothing to get - wait a bit and try again */
+ if( !video && !audio1 && !audio2 )
+ {
+ snooze( 10000 );
+ continue;
+ }
+
+ /* Got something - mux it */
+ if( video >= MAX( audio1, audio2 ) )
+ {
+ AddVideoChunk();
+ }
+ else if( audio1 >= audio2 )
+ {
+ AddAudioChunk( 1 );
+ }
+ else
+ {
+ AddAudioChunk( 2 );
+ }
+ }
+
+ /* Write the index */
+ uint32_t size = fIndex->fSize - 8;
+ memcpy( fIndex->fData + 4, &size, 4 );
+ fseek( fFile, 0, SEEK_END );
+ fwrite( fIndex->fData, fIndex->fSize, 1, fFile );
+
+ /* Update the headers */
+ fRiffBytesCount += fIndex->fSize;
+ fMainHeader.Flags |= AVIF_HASINDEX;
+ UpdateMainHeader();
+
+ delete fIndex;
+
+ fclose( fFile );
+}
+
+bool HBAviMuxer::AddVideoChunk()
+{
+ HBBuffer * buffer = fTitleInfo->fMpeg4Fifo->Pop();
+ if( !buffer )
+ {
+ return false;
+ }
+
+ fRiffBytesCount += 8 + EVEN( buffer->fSize );
+ fMoviBytesCount += 8 + EVEN( buffer->fSize );
+
+ fMainHeader.MicroSecPerFrame = 1000000 * (uint64_t) fTitleInfo->fScale /
+ fTitleInfo->fRate;
+ fMainHeader.TotalFrames++;
+ fMainHeader.Width = fTitleInfo->fOutWidth;
+ fMainHeader.Height = fTitleInfo->fOutHeight;
+
+ fVideoStreamHeader.FourCC = FOURCC( "strh" );
+ fVideoStreamHeader.BytesCount = sizeof( AviStreamHeader ) - 8;
+ fVideoStreamHeader.Type = FOURCC( "vids" );
+ fVideoStreamHeader.Handler = FOURCC( "DIVX" );
+ fVideoStreamHeader.Scale = fTitleInfo->fScale;
+ fVideoStreamHeader.Rate = fTitleInfo->fRate;
+ fVideoStreamHeader.Length++;
+
+ fVideoStreamFormat.FourCC = FOURCC( "strf" );
+ fVideoStreamFormat.BytesCount = sizeof( BitmapInfo ) - 8;
+ fVideoStreamFormat.Size = sizeof( BitmapInfo ) - 8;
+ fVideoStreamFormat.Width = fTitleInfo->fOutWidth;
+ fVideoStreamFormat.Height = fTitleInfo->fOutHeight;
+ fVideoStreamFormat.Planes = 1;
+ fVideoStreamFormat.BitCount = 24;
+ fVideoStreamFormat.Compression = FOURCC( "DIVX" );;
+
+ UpdateMainHeader();
+
+ fseek( fFile, 0, SEEK_END );
+
+ /* Update the index */
+ if( fIndex->fSize + 16 > fIndex->fAllocSize )
+ {
+ /* Realloc if needed */
+ fIndex->ReAlloc( fIndex->fSize + 1024 * 1024 );
+ }
+
+ uint32_t flags = buffer->fKeyFrame ? AVIIF_KEYFRAME : 0;
+ uint32_t offset = ftell( fFile ) - 2044;
+ sprintf( (char*)fIndex->fData + fIndex->fSize, "00dc" );
+
+ memcpy( fIndex->fData + fIndex->fSize + 4, &flags, 4 );
+ memcpy( fIndex->fData + fIndex->fSize + 8, &offset, 4 );
+ memcpy( fIndex->fData + fIndex->fSize + 12, &buffer->fSize, 4 );
+ fIndex->fSize += 16;
+
+ /* Write the chunk */
+ fwrite( "00dc", 4, 1, fFile );
+ fwrite( &buffer->fSize, 4, 1, fFile );
+ fwrite( buffer->fData, buffer->fSize, 1, fFile );
+
+ /* Chunks must be 2-bytes aligned */
+ if( buffer->fSize & 1 )
+ {
+ fputc( 0, fFile );
+ }
+
+ delete buffer;
+
+ return true;
+}
+
+bool HBAviMuxer::AddAudioChunk( int which )
+{
+ HBAudioInfo * info;
+ AviStreamHeader * streamHeader;
+ WaveFormatEx * streamFormat;
+
+ if( which == 1 )
+ {
+ info = fAudio1Info;
+ streamHeader = &fAudio1StreamHeader;
+ streamFormat = &fAudio1StreamFormat;
+ }
+ else
+ {
+ info = fAudio2Info;
+ streamHeader = &fAudio2StreamHeader;
+ streamFormat = &fAudio2StreamFormat;
+ }
+
+ HBBuffer * buffer = info->fMp3Fifo->Pop();
+ if( !buffer )
+ {
+ return false;
+ }
+
+ fRiffBytesCount += 8 + EVEN( buffer->fSize );
+ fMoviBytesCount += 8 + EVEN( buffer->fSize );
+
+ streamHeader->FourCC = FOURCC( "strh" );
+ streamHeader->BytesCount = sizeof( AviStreamHeader ) - 8;
+ streamHeader->Type = FOURCC( "auds" );
+ streamHeader->InitialFrames = 1;
+ streamHeader->Scale = 1152;
+ streamHeader->Rate = info->fOutSampleRate;
+ streamHeader->Length++;
+ streamHeader->Quality = 0xFFFFFFFF;
+
+
+ streamFormat->FourCC = FOURCC( "strf" );
+ streamFormat->BytesCount = sizeof( WaveFormatEx ) - 8;
+ streamFormat->FormatTag = 0x55;
+ streamFormat->Channels = 2;
+ streamFormat->SamplesPerSec = info->fOutSampleRate;
+ streamFormat->AvgBytesPerSec = info->fOutBitrate * 1024 / 8;
+ streamFormat->BlockAlign = 1152;
+
+ /* stolen from libavformat/wav.c */
+ streamFormat->Size = 12;
+ streamFormat->Id = 1;
+ streamFormat->Flags = 2;
+ streamFormat->BlockSize = 1152;
+ streamFormat->FramesPerBlock = 1;
+ streamFormat->CodecDelay = 1393;
+
+ UpdateMainHeader();
+
+ fseek( fFile, 0, SEEK_END );
+
+ /* Update the index */
+ if( fIndex->fSize + 16 > fIndex->fAllocSize )
+ {
+ /* Realloc if needed */
+ fIndex->ReAlloc( fIndex->fSize + 1024 * 1024 );
+ }
+
+ uint32_t flags = buffer->fKeyFrame ? AVIIF_KEYFRAME : 0;
+ uint32_t offset = ftell( fFile ) - 2044;
+ sprintf( (char*)fIndex->fData + fIndex->fSize, "%02dwb", which );
+
+ memcpy( fIndex->fData + fIndex->fSize + 4, &flags, 4 );
+ memcpy( fIndex->fData + fIndex->fSize + 8, &offset, 4 );
+ memcpy( fIndex->fData + fIndex->fSize + 12, &buffer->fSize, 4 );
+ fIndex->fSize += 16;
+
+ /* Write the chunk */
+ fprintf( fFile, "%02dwb", which );
+ fwrite( &buffer->fSize, 4, 1, fFile );
+ fwrite( buffer->fData, buffer->fSize, 1, fFile );
+
+ /* Chunks must be 2-bytes aligned */
+ if( buffer->fSize & 1 )
+ {
+ fputc( 0, fFile );
+ }
+
+ delete buffer;
+
+ return true;
+}
+
+void HBAviMuxer::UpdateMainHeader()
+{
+ fMainHeader.FourCC = FOURCC( "avih" );
+ fMainHeader.BytesCount = sizeof( AviMainHeader ) - 8;
+ fMainHeader.Streams = 2;
+
+ fHdrlBytesCount = 4 + sizeof( AviMainHeader )
+ + 12 + sizeof( AviStreamHeader ) + sizeof( BitmapInfo );
+
+ if( fAudio1Info->fId )
+ {
+ fHdrlBytesCount += 12 + sizeof( AviStreamHeader ) + sizeof( WaveFormatEx );
+ }
+ if( fAudio2Info->fId )
+ {
+ fHdrlBytesCount += 12 + sizeof( AviStreamHeader ) + sizeof( WaveFormatEx );
+ }
+
+ fseek( fFile, 0, SEEK_SET );
+ fwrite( "RIFF", 4, 1, fFile );
+ fwrite( &fRiffBytesCount, 4, 1, fFile );
+ fwrite( "AVI ", 4, 1, fFile );
+ fwrite( "LIST", 4, 1, fFile );
+ fwrite( &fHdrlBytesCount, 4, 1, fFile );
+ fwrite( "hdrl", 4, 1, fFile );
+
+ fwrite( &fMainHeader, sizeof( AviMainHeader ), 1, fFile );
+
+ int strlSize;
+ strlSize = 4 + sizeof( AviStreamHeader ) + sizeof( BitmapInfo );
+ fwrite( "LIST", 4, 1, fFile );
+ fwrite( &strlSize, 4, 1, fFile );
+ fwrite( "strl", 4, 1, fFile );
+ fwrite( &fVideoStreamHeader, sizeof( AviStreamHeader ), 1, fFile );
+ fwrite( &fVideoStreamFormat, sizeof( fVideoStreamFormat ), 1, fFile );
+
+ if( fAudio1Info->fId )
+ {
+ strlSize = 4 + sizeof( AviStreamHeader ) + sizeof( WaveFormatEx );
+ fwrite( "LIST", 4, 1, fFile );
+ fwrite( &strlSize, 4, 1, fFile );
+ fwrite( "strl", 4, 1, fFile );
+ fwrite( &fAudio1StreamHeader, sizeof( AviStreamHeader ), 1, fFile );
+ fwrite( &fAudio1StreamFormat, sizeof( WaveFormatEx ), 1, fFile );
+ }
+
+ if( fAudio2Info->fId )
+ {
+ strlSize = 4 + sizeof( AviStreamHeader ) + sizeof( WaveFormatEx );
+ fwrite( "LIST", 4, 1, fFile );
+ fwrite( &strlSize, 4, 1, fFile );
+ fwrite( "strl", 4, 1, fFile );
+ fwrite( &fAudio2StreamHeader, sizeof( AviStreamHeader ), 1, fFile );
+ fwrite( &fAudio2StreamFormat, sizeof( WaveFormatEx ), 1, fFile );
+ }
+
+ /* a JUNK chunk to fill the free space.
+ size = 2048 -/
+ 12 ("RIFFxxxxAVI ") -
+ 8 (hdrl's "LIS1Txxxx") -
+ fHdrlBytesCount -
+ 8 ("JUNKxxxx") -
+ 12 ("LISTxxxxmovi) */
+ int junkSize = 2008 - fHdrlBytesCount;
+ fwrite( "JUNK", 4, 1, fFile );
+ fwrite( &junkSize, 4, 1, fFile );
+ for( uint32_t i = 0; i < 2008 - fHdrlBytesCount; i++ )
+ {
+ fputc( 0, fFile );
+ }
+
+ /* movi list */
+ fwrite( "LIST", 4, 1, fFile );
+ fwrite( &fMoviBytesCount, 4, 1, fFile );
+ fwrite( "movi", 4, 1, fFile );
+}
diff --git a/HBAviMuxer.h b/HBAviMuxer.h
new file mode 100644
index 000000000..55c2dc248
--- /dev/null
+++ b/HBAviMuxer.h
@@ -0,0 +1,149 @@
+/* $Id: HBAviMuxer.h,v 1.8 2003/08/23 16:20:59 titer Exp $ */
+
+#ifndef HB_AVI_MUXER_H
+#define HB_AVI_MUXER_H
+
+#include "HBThread.h"
+class HBManager;
+class HBFifo;
+class HBBuffer;
+class HBAudioInfo;
+class HBTitleInfo;
+
+#define FOURCC(a) \
+ ( ( a[3] << 24 ) | ( a[2] << 16 ) | ( a[1] << 8 ) | a[0] )
+
+/* Misc structures used in AVI headers */
+typedef struct __attribute__((__packed__)) BitmapInfo
+{
+ 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;
+ uint8_t Blue;
+ uint8_t Green;
+ uint8_t Red;
+ uint8_t Reserved;
+} BitmapInfo;
+
+typedef struct __attribute__((__packed__)) WaveFormatEx
+{
+ 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;
+} WaveFormatEx;
+
+typedef struct __attribute__((__packed__)) AviStreamHeader
+{
+ 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;
+} AviStreamHeader;
+
+typedef struct __attribute__((__packed__)) AviMainHeader
+{
+ 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];
+} AviMainHeader;
+
+typedef struct AviOldIndexEntry
+{
+ char StreamNb[2];
+ char Code[2];
+ uint32_t Flags;
+ uint32_t Offset;
+ uint32_t Size;
+} AviOldIndexEntry;
+
+class HBAviMuxer : public HBThread
+{
+ public:
+ HBAviMuxer( HBManager * manager, HBTitleInfo * titleInfo,
+ HBAudioInfo * audio1Info, HBAudioInfo * audio2Info,
+ char * fileName );
+
+ private:
+ void DoWork();
+ bool AddVideoChunk();
+ bool AddAudioChunk( int which );
+ void UpdateMainHeader();
+
+ HBManager * fManager;
+ HBTitleInfo * fTitleInfo;
+ HBAudioInfo * fAudio1Info;
+ HBAudioInfo * fAudio2Info;
+ char * fFileName;
+
+ FILE * fFile;
+
+ /* The main header */
+ AviMainHeader fMainHeader;
+
+ /* The video track */
+ AviStreamHeader fVideoStreamHeader;
+ BitmapInfo fVideoStreamFormat;
+
+ /* The audio tracks */
+ AviStreamHeader fAudio1StreamHeader;
+ WaveFormatEx fAudio1StreamFormat;
+ AviStreamHeader fAudio2StreamHeader;
+ WaveFormatEx fAudio2StreamFormat;
+
+ uint32_t fRiffBytesCount;
+ uint32_t fHdrlBytesCount;
+ uint32_t fMoviBytesCount;
+
+ HBBuffer * fIndex;
+
+};
+
+#endif
diff --git a/HBCommon.cpp b/HBCommon.cpp
new file mode 100644
index 000000000..e0e17a43b
--- /dev/null
+++ b/HBCommon.cpp
@@ -0,0 +1,566 @@
+/* $Id: HBCommon.cpp,v 1.5 2003/08/24 20:25:49 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBFifo.h"
+#include "HBMpegDemux.h"
+#include "HBPictureWin.h"
+#include "HBWindow.h"
+
+#include <Application.h>
+
+#include <dvdread/ifo_types.h>
+#include <dvdplay/dvdplay.h>
+#include <dvdplay/info.h>
+#include <dvdplay/state.h>
+#include <dvdplay/nav.h>
+
+extern "C" {
+#include <mpeg2dec/mpeg2.h>
+}
+
+void Log( char * log, ... )
+{
+ char * string = (char*) malloc( 1024 );
+
+ /* Show the time */
+ time_t _now = time( NULL );
+ struct tm * now = localtime( &_now );
+ sprintf( string, "[%02d:%02d:%02d] ",
+ now->tm_hour, now->tm_min, now->tm_sec );
+
+ /* Convert the message to a string */
+ va_list args;
+ va_start( args, log );
+ int ret = vsnprintf( string + 11, 1011, log, args );
+ va_end( args );
+
+ /* Add the end of line */
+ string[ret+11] = '\n';
+ string[ret+12] = '\0';
+
+ /* Send this to the be_app */
+ /* We do this so we are sure that only one message is printed
+ at a time */
+ BMessage * message = new BMessage( PRINT_MESSAGE );
+ message->AddPointer( "string", string );
+ be_app->PostMessage( message );
+ delete message;
+}
+
+void Status( char * text, float pos, int mode )
+{
+ char * textCopy = strdup( text );
+ BMessage * message = new BMessage( CHANGE_STATUS );
+ message->AddPointer( "text", textCopy );
+ message->AddFloat( "pos", pos );
+ message->AddInt32( "mode", mode );
+ be_app->PostMessage( message );
+ delete message;
+}
+
+/* Get a readable language description from the code */
+iso639_lang_t languages[] =
+{ { "Afar", "", "aa" },
+ { "Abkhazian", "", "ab" },
+ { "Afrikaans", "", "af" },
+ { "Albanian", "", "sq" },
+ { "Amharic", "", "am" },
+ { "Arabic", "", "ar" },
+ { "Armenian", "", "hy" },
+ { "Assamese", "", "as" },
+ { "Avestan", "", "ae" },
+ { "Aymara", "", "ay" },
+ { "Azerbaijani", "", "az" },
+ { "Bashkir", "", "ba" },
+ { "Basque", "", "eu" },
+ { "Belarusian", "", "be" },
+ { "Bengali", "", "bn" },
+ { "Bihari", "", "bh" },
+ { "Bislama", "", "bi" },
+ { "Bosnian", "", "bs" },
+ { "Breton", "", "br" },
+ { "Bulgarian", "", "bg" },
+ { "Burmese", "", "my" },
+ { "Catalan", "", "ca" },
+ { "Chamorro", "", "ch" },
+ { "Chechen", "", "ce" },
+ { "Chinese", "", "zh" },
+ { "Church Slavic", "", "cu" },
+ { "Chuvash", "", "cv" },
+ { "Cornish", "", "kw" },
+ { "Corsican", "", "co" },
+ { "Czech", "", "cs" },
+ { "Danish", "Dansk", "da" },
+ { "Dutch", "Nederlands", "nl" },
+ { "Dzongkha", "", "dz" },
+ { "English", "English", "en" },
+ { "Esperanto", "", "eo" },
+ { "Estonian", "", "et" },
+ { "Faroese", "", "fo" },
+ { "Fijian", "", "fj" },
+ { "Finnish", "Suomi", "fi" },
+ { "French", "Francais", "fr" },
+ { "Frisian", "", "fy" },
+ { "Georgian", "", "ka" },
+ { "German", "Deutsch", "de" },
+ { "Gaelic (Scots)", "", "gd" },
+ { "Irish", "", "ga" },
+ { "Gallegan", "", "gl" },
+ { "Manx", "", "gv" },
+ { "Greek, Modern ()", "", "el" },
+ { "Guarani", "", "gn" },
+ { "Gujarati", "", "gu" },
+ { "Hebrew", "", "he" },
+ { "Herero", "", "hz" },
+ { "Hindi", "", "hi" },
+ { "Hiri Motu", "", "ho" },
+ { "Hungarian", "Magyar", "hu" },
+ { "Icelandic", "Islenska", "is" },
+ { "Inuktitut", "", "iu" },
+ { "Interlingue", "", "ie" },
+ { "Interlingua", "", "ia" },
+ { "Indonesian", "", "id" },
+ { "Inupiaq", "", "ik" },
+ { "Italian", "Italiano", "it" },
+ { "Javanese", "", "jv" },
+ { "Japanese", "", "ja" },
+ { "Kalaallisut (Greenlandic)", "", "kl" },
+ { "Kannada", "", "kn" },
+ { "Kashmiri", "", "ks" },
+ { "Kazakh", "", "kk" },
+ { "Khmer", "", "km" },
+ { "Kikuyu", "", "ki" },
+ { "Kinyarwanda", "", "rw" },
+ { "Kirghiz", "", "ky" },
+ { "Komi", "", "kv" },
+ { "Korean", "", "ko" },
+ { "Kuanyama", "", "kj" },
+ { "Kurdish", "", "ku" },
+ { "Lao", "", "lo" },
+ { "Latin", "", "la" },
+ { "Latvian", "", "lv" },
+ { "Lingala", "", "ln" },
+ { "Lithuanian", "", "lt" },
+ { "Letzeburgesch", "", "lb" },
+ { "Macedonian", "", "mk" },
+ { "Marshall", "", "mh" },
+ { "Malayalam", "", "ml" },
+ { "Maori", "", "mi" },
+ { "Marathi", "", "mr" },
+ { "Malay", "", "ms" },
+ { "Malagasy", "", "mg" },
+ { "Maltese", "", "mt" },
+ { "Moldavian", "", "mo" },
+ { "Mongolian", "", "mn" },
+ { "Nauru", "", "na" },
+ { "Navajo", "", "nv" },
+ { "Ndebele, South", "", "nr" },
+ { "Ndebele, North", "", "nd" },
+ { "Ndonga", "", "ng" },
+ { "Nepali", "", "ne" },
+ { "Norwegian", "Norsk", "no" },
+ { "Norwegian Nynorsk", "", "nn" },
+ { "Norwegian Bokmål", "", "nb" },
+ { "Chichewa; Nyanja", "", "ny" },
+ { "Occitan (post 1500); Provençal", "", "oc" },
+ { "Oriya", "", "or" },
+ { "Oromo", "", "om" },
+ { "Ossetian; Ossetic", "", "os" },
+ { "Panjabi", "", "pa" },
+ { "Persian", "", "fa" },
+ { "Pali", "", "pi" },
+ { "Polish", "", "pl" },
+ { "Portuguese", "Portugues", "pt" },
+ { "Pushto", "", "ps" },
+ { "Quechua", "", "qu" },
+ { "Raeto-Romance", "", "rm" },
+ { "Romanian", "", "ro" },
+ { "Rundi", "", "rn" },
+ { "Russian", "", "ru" },
+ { "Sango", "", "sg" },
+ { "Sanskrit", "", "sa" },
+ { "Serbian", "", "sr" },
+ { "Croatian", "Hrvatski", "hr" },
+ { "Sinhalese", "", "si" },
+ { "Slovak", "", "sk" },
+ { "Slovenian", "", "sl" },
+ { "Northern Sami", "", "se" },
+ { "Samoan", "", "sm" },
+ { "Shona", "", "sn" },
+ { "Sindhi", "", "sd" },
+ { "Somali", "", "so" },
+ { "Sotho, Southern", "", "st" },
+ { "Spanish", "Espanol", "es" },
+ { "Sardinian", "", "sc" },
+ { "Swati", "", "ss" },
+ { "Sundanese", "", "su" },
+ { "Swahili", "", "sw" },
+ { "Swedish", "Svenska", "sv" },
+ { "Tahitian", "", "ty" },
+ { "Tamil", "", "ta" },
+ { "Tatar", "", "tt" },
+ { "Telugu", "", "te" },
+ { "Tajik", "", "tg" },
+ { "Tagalog", "", "tl" },
+ { "Thai", "", "th" },
+ { "Tibetan", "", "bo" },
+ { "Tigrinya", "", "ti" },
+ { "Tonga (Tonga Islands)", "", "to" },
+ { "Tswana", "", "tn" },
+ { "Tsonga", "", "ts" },
+ { "Turkish", "", "tr" },
+ { "Turkmen", "", "tk" },
+ { "Twi", "", "tw" },
+ { "Uighur", "", "ug" },
+ { "Ukrainian", "", "uk" },
+ { "Urdu", "", "ur" },
+ { "Uzbek", "", "uz" },
+ { "Vietnamese", "", "vi" },
+ { "Volapük", "", "vo" },
+ { "Welsh", "", "cy" },
+ { "Wolof", "", "wo" },
+ { "Xhosa", "", "xh" },
+ { "Yiddish", "", "yi" },
+ { "Yoruba", "", "yo" },
+ { "Zhuang", "", "za" },
+ { "Zulu", "", "zu" },
+ { NULL, NULL, NULL } };
+
+char * LanguageForCode( int code )
+{
+ char codeString[2];
+ codeString[0] = ( code >> 8 ) & 0xFF;
+ codeString[1] = code & 0xFF;
+
+ iso639_lang_t * lang;
+ for( lang = languages; lang->engName; lang++ )
+ {
+ if( !strncmp( lang->iso639_1, codeString, 2 ) )
+ {
+ if( *lang->nativeName )
+ return lang->nativeName;
+
+ return lang->engName;
+ }
+ }
+
+ return "Unknown";
+}
+
+HBVolumeInfo::HBVolumeInfo( char * name, char * device )
+ : BMenuItem( "", new BMessage( VOLUME_SELECTED ) )
+{
+ fInitOK = false;
+ fName = strdup( name );
+ fDevice = strdup( device );
+ fTitleList = new BList();
+
+ SetLabel( fName );
+
+ /* Open the device */
+ dvdplay_ptr vmg;
+ vmg = dvdplay_open( device, NULL, NULL );
+ if( !vmg )
+ {
+ Log( "VolumeInfo::DetectTitles: dvdplay_open() failed" );
+ return;
+ }
+
+ /* Detect titles */
+ HBTitleInfo * titleInfo;
+ for( int i = 0; i < dvdplay_title_nr( vmg ); i++ )
+ {
+ Log( "HBVolumeInfo : new title (%d)", i + 1 );
+
+ char statusText[128]; memset( statusText, 0, 128 );
+ snprintf( statusText, 128,
+ "Checking DVD volumes (%s, title %d)...",
+ fName, i + 1 );
+ Status( statusText, 0.0, ENABLE_DETECTING );
+
+ titleInfo = new HBTitleInfo( vmg, i + 1, device );
+
+ if( !titleInfo->InitCheck() )
+ {
+ delete titleInfo;
+ continue;
+ }
+
+ fTitleList->AddItem( titleInfo );
+ }
+
+ dvdplay_close( vmg );
+
+ if( fTitleList->CountItems() > 0 )
+ {
+ fInitOK = true;
+ }
+
+}
+
+HBVolumeInfo::~HBVolumeInfo()
+{
+ free( fName );
+ free( fDevice );
+
+ HBTitleInfo * titleInfo;
+ while( ( titleInfo = (HBTitleInfo*) fTitleList->ItemAt( 0 ) ) )
+ {
+ fTitleList->RemoveItem( titleInfo );
+ delete titleInfo;
+ }
+ delete fTitleList;
+}
+
+bool HBVolumeInfo::InitCheck()
+{
+ return fInitOK;
+}
+
+HBTitleInfo::HBTitleInfo( dvdplay_ptr vmg, int index, char * device )
+ : BMenuItem( "", new BMessage( TITLE_SELECTED ) )
+{
+ fInitOK = false;
+ fDevice = strdup( device );
+ fIndex = index;
+
+ fAudioInfoList1 = new BList();
+ fAudioInfoList2 = new BList();
+ fPSFifo = NULL;
+ fMpeg2Fifo = NULL;
+ fRawFifo = NULL;
+ fMpeg4Fifo = NULL;
+
+ dvdplay_start( vmg, fIndex );
+
+ /* Length */
+ fLength = dvdplay_title_time( vmg );
+
+ /* Discard titles under 60 seconds */
+ if( fLength < 60 )
+ {
+ Log( "HBTitleInfo : skipping title %d (length = %lld sec)",
+ index, fLength );
+ return;
+ }
+
+ char label[1024]; memset( label, 0, 1024 );
+ sprintf( label, "Title %d (%02lld:%02lld:%02lld)",
+ index, fLength / 3600, ( fLength % 3600 ) / 60,
+ fLength % 60 );
+ SetLabel( label );
+
+ /* Detect languages */
+ int audio_nr, audio;
+ dvdplay_audio_info( vmg, &audio_nr, &audio );
+
+ audio_attr_t * attr;
+ HBAudioInfo * audioInfo;
+ for( int i = 0; i < audio_nr; i++ )
+ {
+ int id = dvdplay_audio_id( vmg, i );
+ if( id > 0 )
+ {
+ Log( "HBTitleInfo : new language (%x)", id );
+ attr = dvdplay_audio_attr( vmg, i );
+ audioInfo = new HBAudioInfo( id, LanguageForCode( attr->lang_code ) );
+ fAudioInfoList1->AddItem( audioInfo );
+ }
+ }
+
+ /* Discard titles with no audio tracks */
+ if( !fAudioInfoList1->CountItems() )
+ {
+ Log( "HBTitleInfo : skipping title %d (no audio track)", index );
+ return;
+ }
+
+ /* Add a dummy 'None' language */
+ audioInfo = new HBAudioInfo( 0, "None" );
+ fAudioInfoList1->AddItem( audioInfo );
+
+ /* Duplicate the audio list */
+ for( int i = 0; i < fAudioInfoList1->CountItems(); i++ )
+ {
+ audioInfo = (HBAudioInfo*) fAudioInfoList1->ItemAt( i );
+ fAudioInfoList2->AddItem( new HBAudioInfo( audioInfo ) );
+ }
+
+ /* Decode a few pictures so the user can crop/resize it */
+ int titleFirst = dvdplay_title_first ( vmg );
+ int titleEnd = dvdplay_title_end( vmg );
+
+ /* Kludge : libdvdplay wants we to read a first block before seeking */
+ uint8_t dummyBuf[2048];
+ dvdplay_read( vmg, dummyBuf, 1 );
+
+ for( int i = 0; i < 10; i++ )
+ {
+ dvdplay_seek( vmg, ( i + 1 ) * ( titleEnd - titleFirst ) / 11 ) ;
+ if( !DecodeFrame( vmg, i ) )
+ {
+ Log( "HBTitleInfo::HBTitleInfo : could not decode frame %d", i );
+ return;
+ }
+ }
+
+ fPictureWin = new HBPictureWin( this );
+
+ fInitOK = true;
+}
+
+HBTitleInfo::~HBTitleInfo()
+{
+ HBAudioInfo * audioInfo;
+
+ while( ( audioInfo = (HBAudioInfo*) fAudioInfoList1->ItemAt( 0 ) ) )
+ {
+ fAudioInfoList1->RemoveItem( audioInfo );
+ delete audioInfo;
+ }
+ delete fAudioInfoList1;
+
+ while( ( audioInfo = (HBAudioInfo*) fAudioInfoList2->ItemAt( 0 ) ) )
+ {
+ fAudioInfoList2->RemoveItem( audioInfo );
+ delete audioInfo;
+ }
+ delete fAudioInfoList2;
+}
+
+bool HBTitleInfo::DecodeFrame( dvdplay_ptr vmg, int i )
+{
+ /* Init libmpeg2 */
+ mpeg2dec_t * handle = mpeg2_init();
+ const mpeg2_info_t * info = mpeg2_info( handle );
+ mpeg2_state_t state;
+
+ BList * esBufferList = NULL;
+ HBBuffer * psBuffer = NULL;
+ HBBuffer * esBuffer = NULL;
+
+ for( ;; )
+ {
+ state = mpeg2_parse( handle );
+
+ if( state == STATE_BUFFER )
+ {
+ /* Free the previous buffer */
+ if( esBuffer )
+ {
+ delete esBuffer;
+ esBuffer = NULL;
+ }
+
+ /* Get a new one */
+ while( !esBuffer )
+ {
+ while( !esBufferList )
+ {
+ psBuffer = new HBBuffer( DVD_VIDEO_LB_LEN );
+ if( dvdplay_read( vmg, psBuffer->fData, 1 ) != 1 )
+ {
+ Log( "dvdplay_read failed" );
+ }
+ esBufferList = PStoES( psBuffer );
+ }
+
+ esBuffer = (HBBuffer*) esBufferList->ItemAt( 0 );
+ esBufferList->RemoveItem( esBuffer );
+ if( !esBufferList->CountItems() )
+ {
+ delete esBufferList;
+ esBufferList = NULL;
+ }
+
+ if( esBuffer->fStreamId != 0xE0 )
+ {
+ delete esBuffer;
+ esBuffer = NULL;
+ }
+ }
+
+ /* Feed libmpeg2 */
+ mpeg2_buffer( handle, esBuffer->fData,
+ esBuffer->fData + esBuffer->fSize );
+ }
+ else if( state == STATE_SEQUENCE )
+ {
+ /* Get size & framerate info */
+ fInWidth = info->sequence->width;
+ fInHeight = info->sequence->height;
+ fPixelWidth = info->sequence->pixel_width;
+ fPixelHeight = info->sequence->pixel_height;
+ fPictures[i] = (uint8_t*) malloc( 3 * fInWidth * fInHeight / 2 );
+ fRate = 27000000;
+ fScale = info->sequence->frame_period;
+ }
+ else if( ( state == STATE_SLICE || state == STATE_END ) &&
+ ( info->display_fbuf ) &&
+ ( info->display_picture->flags & PIC_MASK_CODING_TYPE )
+ == PIC_FLAG_CODING_TYPE_I )
+ {
+ /* Copy it */
+ /* TODO : make libmpeg2 write directly in our buffer */
+ memcpy( fPictures[i],
+ info->display_fbuf->buf[0],
+ fInWidth * fInHeight );
+ memcpy( fPictures[i] + fInWidth * fInHeight,
+ info->display_fbuf->buf[1],
+ fInWidth * fInHeight / 4 );
+ memcpy( fPictures[i] + 5 * fInWidth * fInHeight / 4,
+ info->display_fbuf->buf[2],
+ fInWidth * fInHeight / 4 );
+ break;
+ }
+ else if( state == STATE_INVALID )
+ {
+ /* Reset libmpeg2 */
+ mpeg2_close( handle );
+ handle = mpeg2_init();
+ }
+ }
+
+ mpeg2_close( handle );
+
+ return true;
+}
+
+bool HBTitleInfo::InitCheck()
+{
+ return fInitOK;
+}
+
+/* Audio track */
+HBAudioInfo::HBAudioInfo( int id, char * description )
+ : BMenuItem( "", new BMessage( LANGUAGE_SELECTED ) )
+{
+ fId = id;
+ fOutSampleRate = 44100;
+
+ fAc3Fifo = NULL;
+ fRawFifo = NULL;
+ fMp3Fifo = NULL;
+
+ SetLabel( description );
+}
+
+HBAudioInfo::HBAudioInfo( HBAudioInfo * audioInfo )
+ : BMenuItem( "", new BMessage( LANGUAGE_SELECTED ) )
+{
+ fId = audioInfo->fId;
+ fInSampleRate = audioInfo->fInSampleRate;
+ fOutSampleRate = audioInfo->fOutSampleRate;
+ fInBitrate = audioInfo->fInBitrate;
+ fOutBitrate = audioInfo->fOutBitrate;
+
+ fAc3Fifo = NULL;
+ fRawFifo = NULL;
+ fMp3Fifo = NULL;
+
+ SetLabel( audioInfo->Label() );
+}
+
+HBAudioInfo::~HBAudioInfo()
+{
+}
diff --git a/HBCommon.h b/HBCommon.h
new file mode 100644
index 000000000..3e84c3dc5
--- /dev/null
+++ b/HBCommon.h
@@ -0,0 +1,146 @@
+/* $Id: HBCommon.h,v 1.9 2003/08/24 19:28:18 titer Exp $ */
+
+#ifndef _HB_COMMON_H
+#define _HB_COMMON_H
+
+/* standard headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+typedef uint8_t byte_t;
+
+/* BeOS headers */
+#include <Looper.h>
+#include <MenuItem.h>
+
+/* Internal headers */
+class HBFifo;
+class HBPictureWin;
+
+/* Misc structures */
+typedef struct dvdplay_s * dvdplay_ptr;
+typedef struct iso639_lang_t
+{
+ char * engName; /* Description in English */
+ char * nativeName; /* Description in native language */
+ char * iso639_1; /* ISO-639-1 (2 characters) code */
+} iso639_lang_t;
+
+/* BMessages */
+#define MANAGER_CREATED 'macr'
+#define PRINT_MESSAGE 'prme'
+#define DETECT_VOLUMES 'devo'
+#define START_CONVERT 'stac'
+#define STOP_CONVERT 'stoc'
+#define SUSPEND_CONVERT 'suco'
+#define RESUME_CONVERT 'reco'
+#define VOLUMES_DETECTED 'vode'
+#define REFRESH_VOLUMES 'revo'
+#define VIDEO_SLIDER 'visl'
+#define AUDIO_SLIDER 'ausl'
+#define PICTURE_WIN 'piwi'
+#define NOT_IMPLEMENTED 'noim'
+#define VOLUME_SELECTED 'vose'
+#define TITLE_SELECTED 'tise'
+#define LANGUAGE_SELECTED 'lase'
+#define CHANGE_STATUS 'chst'
+
+/* Handy macros */
+#define EVEN( a ) ( ( (a) & 0x1 ) ? ( (a) + 1 ) : (a) )
+#define MULTIPLE_16( a ) ( ( ( (a) % 16 ) < 8 ) ? ( (a) - ( (a) % 16 ) ) \
+ : ( (a) - ( (a) % 16 ) + 16 ) )
+
+/* Global prototypes */
+void Log( char * log, ... );
+void Status( char * text, float pos, int mode );
+char * LanguageForCode( int code );
+
+/* Possible modes in Status() */
+#define ENABLE_DETECTING 0x1
+#define ENABLE_READY 0x2
+#define ENABLE_ENCODING 0x4
+
+/* Classes */
+
+class HBAudioInfo : public BMenuItem
+{
+ public:
+ /* Common methods and members */
+ HBAudioInfo( int id, char * description );
+ HBAudioInfo( HBAudioInfo * audioInfo );
+ ~HBAudioInfo();
+
+ uint32_t fId;
+ HBFifo * fAc3Fifo;
+ HBFifo * fRawFifo;
+ HBFifo * fMp3Fifo;
+
+ int fInSampleRate;
+ int fOutSampleRate;
+ int fInBitrate;
+ int fOutBitrate;
+};
+
+class HBTitleInfo : public BMenuItem
+{
+ public:
+ HBTitleInfo( dvdplay_ptr vmg, int index, char * device );
+ ~HBTitleInfo();
+ bool InitCheck();
+
+ bool fInitOK;
+ char * fDevice;
+ int fIndex;
+ uint64_t fLength;
+
+ /* MPEG2-PS data */
+ HBFifo * fPSFifo;
+
+ /* Video info */
+ bool DecodeFrame( dvdplay_ptr vmg, int i );
+
+ HBFifo * fMpeg2Fifo;
+ HBFifo * fRawFifo;
+ HBFifo * fMpeg4Fifo;
+
+ /* Video input */
+ uint32_t fInWidth;
+ uint32_t fInHeight;
+ uint32_t fPixelWidth;
+ uint32_t fPixelHeight;
+ uint32_t fRate;
+ uint32_t fScale;
+
+ /* Video output */
+ bool fDeinterlace;
+ uint32_t fOutWidth;
+ uint32_t fOutHeight;
+ uint32_t fTopCrop;
+ uint32_t fBottomCrop;
+ uint32_t fLeftCrop;
+ uint32_t fRightCrop;
+ uint32_t fBitrate;
+
+ uint8_t * fPictures[10];
+ HBPictureWin * fPictureWin;
+
+ /* Audio infos */
+ BList * fAudioInfoList1;
+ BList * fAudioInfoList2;
+};
+
+class HBVolumeInfo : public BMenuItem
+{
+ public:
+ HBVolumeInfo( char * name, char * device );
+ ~HBVolumeInfo();
+ bool InitCheck();
+
+ bool fInitOK;
+ char * fName;
+ char * fDevice;
+ BList * fTitleList;
+};
+
+#endif
diff --git a/HBDVDReader.cpp b/HBDVDReader.cpp
new file mode 100644
index 000000000..2027da7e6
--- /dev/null
+++ b/HBDVDReader.cpp
@@ -0,0 +1,67 @@
+/* $Id: HBDVDReader.cpp,v 1.7 2003/08/12 20:10:50 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBDVDReader.h"
+#include "HBManager.h"
+#include "HBFifo.h"
+
+#include <Application.h>
+
+#include <dvdread/ifo_types.h>
+#include <dvdplay/dvdplay.h>
+#include <dvdplay/info.h>
+#include <dvdplay/state.h>
+#include <dvdplay/nav.h>
+
+HBDVDReader::HBDVDReader( HBManager * manager,
+ HBTitleInfo * titleInfo )
+ : HBThread( "dvdreader", B_NORMAL_PRIORITY )
+{
+ fManager = manager;
+ fTitleInfo = titleInfo;
+}
+
+void HBDVDReader::DoWork()
+{
+ /* Open the device */
+ dvdplay_ptr vmg;
+ vmg = dvdplay_open( fTitleInfo->fDevice, NULL, NULL );
+ if( !vmg )
+ {
+ Log( "HBDVDReader: dvdplay_open() failed" );
+ fManager->Error();
+ return;
+ }
+
+ /* Open the title */
+ dvdplay_start( vmg, fTitleInfo->fIndex );
+
+ /* Read */
+ HBBuffer * dvdBuffer;
+ int beginPosition = dvdplay_position( vmg );
+ int endPosition = dvdplay_title_end( vmg );
+ while( dvdplay_position( vmg ) < endPosition )
+ {
+ dvdBuffer = new HBBuffer( DVD_VIDEO_LB_LEN );
+ dvdBuffer->fPosition = (float) ( dvdplay_position( vmg ) - beginPosition ) /
+ (float) ( endPosition - beginPosition ) ;
+
+ if( dvdplay_read( vmg, dvdBuffer->fData, 1 ) < 0 )
+ {
+ Log( "HBDVDReader: could not dvdplay_read()" );
+ delete dvdBuffer;
+ fManager->Error();
+ break;
+ }
+ if( !( fTitleInfo->fPSFifo->Push( dvdBuffer ) ) )
+ {
+ break;
+ }
+ }
+
+ if( dvdplay_position( vmg ) == dvdplay_title_end( vmg ) )
+ fManager->Done();
+
+ /* Clean up */
+ dvdplay_close( vmg );
+}
diff --git a/HBDVDReader.h b/HBDVDReader.h
new file mode 100644
index 000000000..55db069a8
--- /dev/null
+++ b/HBDVDReader.h
@@ -0,0 +1,23 @@
+/* $Id: HBDVDReader.h,v 1.3 2003/08/12 20:10:50 titer Exp $ */
+
+#ifndef HB_DVD_READER_H
+#define HB_DVD_READER_H
+
+#include "HBThread.h"
+class HBManager;
+class HBTitleInfo;
+class HBFifo;
+
+class HBDVDReader : public HBThread
+{
+ public:
+ HBDVDReader( HBManager * manager, HBTitleInfo * titleInfo );
+
+ private:
+ void DoWork();
+
+ HBManager * fManager;
+ HBTitleInfo * fTitleInfo;
+};
+
+#endif
diff --git a/HBFifo.cpp b/HBFifo.cpp
new file mode 100644
index 000000000..fd79f734a
--- /dev/null
+++ b/HBFifo.cpp
@@ -0,0 +1,161 @@
+/* $Id: HBFifo.cpp,v 1.10 2003/08/24 13:27:41 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBFifo.h"
+
+#include <Locker.h>
+
+HBBuffer::HBBuffer( int size )
+{
+ fAllocSize = size;
+ fSize = size;
+ fKeyFrame = false;
+ fData = (uint8_t*) malloc( size );
+
+ if( !fData )
+ {
+ Log( "HBBuffer::HBBuffer() : malloc() failed, gonna crash soon" );
+ }
+}
+
+HBBuffer::~HBBuffer()
+{
+ free( fData );
+}
+
+void HBBuffer::ReAlloc( int size )
+{
+ realloc( fData, size );
+
+ if( !fData )
+ {
+ Log( "HBBuffer::ReAlloc() : realloc() failed, gonna crash soon" );
+ }
+
+ fAllocSize = size;
+}
+
+/* Constructor */
+HBFifo::HBFifo( int capacity )
+{
+ fCapacity = capacity;
+
+ fWhereToPush = 0;
+ fWhereToPop = 0;
+ fBuffers = (HBBuffer**) malloc( ( fCapacity + 1 ) * sizeof( void* ) );
+ fLocker = new BLocker();
+ fDie = false;
+}
+
+void HBFifo::Die()
+{
+ Lock();
+
+ /* Empty the fifo */
+ while( fWhereToPush != fWhereToPop )
+ {
+ HBBuffer * buffer = fBuffers[fWhereToPop];
+ fWhereToPop++;
+ fWhereToPop %= ( fCapacity + 1 );
+ delete buffer;
+ }
+
+ fDie = true;
+
+ Unlock();
+}
+
+HBFifo::~HBFifo()
+{
+ /* Empty the fifo */
+ while( fWhereToPush != fWhereToPop )
+ {
+ HBBuffer * buffer = fBuffers[fWhereToPop];
+ fWhereToPop++;
+ fWhereToPop %= ( fCapacity + 1 );
+ delete buffer;
+ }
+
+ /* Cleaning */
+ free( fBuffers );
+ delete fLocker;
+}
+
+/* Size() : returns how much the fifo is currently filled */
+int HBFifo::Size()
+{
+ return ( fCapacity + 1 + fWhereToPush - fWhereToPop ) %
+ ( fCapacity + 1 );
+}
+
+/* Capacity() : simply returns the fifo capacity... */
+int HBFifo::Capacity()
+{
+ return fCapacity;
+}
+
+/* Push() : add a packet to the fifo. If the fifo is full, it blocks
+ until the packet can be added. Returns true when it is successful,
+ or false if the fifo has been destroyed before we could add it */
+bool HBFifo::Push( HBBuffer * buffer )
+{
+ bool success = false;
+
+ while( !fDie )
+ {
+ Lock();
+ if( Size() < fCapacity )
+ {
+ fBuffers[fWhereToPush] = buffer;
+ fWhereToPush++;
+ fWhereToPush %= ( fCapacity + 1 );
+ Unlock();
+ success = true;
+ break;
+ }
+ Unlock();
+ snooze( 10000 );
+ }
+
+ if( !success )
+ {
+ delete buffer;
+ }
+
+ return success;
+}
+
+/* Pop() : get the first packet if the fifo. If the fifo is empty, it
+ blocks until a packet comes. Returns true when it is successful,
+ or false if the fifo has been destroyed before we could get a packet */
+HBBuffer * HBFifo::Pop()
+{
+ while( !fDie )
+ {
+ Lock();
+ if( fWhereToPush != fWhereToPop )
+ {
+ HBBuffer * buffer = fBuffers[fWhereToPop];
+ fWhereToPop++;
+ fWhereToPop %= ( fCapacity + 1 );
+ Unlock();
+ return buffer;
+ }
+ Unlock();
+ snooze( 10000 );
+ }
+
+ return NULL;
+}
+
+/* Lock() : private function */
+void HBFifo::Lock()
+{
+ fLocker->Lock();
+}
+
+/* Unlock() : private function */
+void HBFifo::Unlock()
+{
+ fLocker->Unlock();
+}
diff --git a/HBFifo.h b/HBFifo.h
new file mode 100644
index 000000000..a46d46158
--- /dev/null
+++ b/HBFifo.h
@@ -0,0 +1,61 @@
+/* $Id: HBFifo.h,v 1.9 2003/08/24 13:27:41 titer Exp $ */
+
+#ifndef _HB_FIFO_H
+#define _HB_FIFO_H
+
+#define DVD_DATA 0x01
+#define MPEG2_VIDEO 0x02
+#define RAW_VIDEO 0x04
+#define RAW2_VIDEO 0x08
+#define MPEG4_VIDEO 0x10
+#define AC3_AUDIO 0x20
+#define RAW_AUDIO 0x40
+#define MP3_AUDIO 0x80
+
+class BLocker;
+
+class HBBuffer
+{
+ public:
+ /* Common functions */
+ HBBuffer( int size );
+ ~HBBuffer();
+ void ReAlloc( int size );
+
+ /* Common members */
+ uint32_t fAllocSize;
+ uint32_t fSize;
+ uint8_t * fData;
+
+ /* Misc */
+ float fPosition;
+ uint32_t fStreamId;
+ bool fKeyFrame;
+ uint64_t fPTS;
+};
+
+class HBFifo
+{
+ public:
+ HBFifo( int capacity );
+ void Die();
+ ~HBFifo();
+
+ int Size();
+ int Capacity();
+ bool Push( HBBuffer * buffer );
+ HBBuffer * Pop();
+
+ private:
+ void Lock();
+ void Unlock();
+
+ int fCapacity;
+ int fWhereToPush;
+ int fWhereToPop;
+ HBBuffer ** fBuffers;
+ BLocker * fLocker;
+ volatile bool fDie;
+};
+
+#endif
diff --git a/HBManager.cpp b/HBManager.cpp
new file mode 100644
index 000000000..159d52348
--- /dev/null
+++ b/HBManager.cpp
@@ -0,0 +1,319 @@
+/* $Id: HBManager.cpp,v 1.27 2003/08/24 20:25:49 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBManager.h"
+#include "HBWindow.h"
+#include "HBFifo.h"
+#include "HBDVDReader.h"
+#include "HBMpegDemux.h"
+#include "HBMpeg2Decoder.h"
+#include "HBMpeg4Encoder.h"
+#include "HBAc3Decoder.h"
+#include "HBMp3Encoder.h"
+#include "HBAviMuxer.h"
+
+#include <Directory.h>
+#include <Drivers.h>
+#include <Path.h>
+#include <Query.h>
+#include <String.h>
+#include <VolumeRoster.h>
+
+#include <fs_info.h>
+#include <sys/ioctl.h>
+
+/* Public methods */
+
+HBManager::HBManager( HBWindow * window )
+ : BLooper( "manager" )
+{
+ fWindow = window;
+ fFifoList = new BList();
+ fThreadList = new BList();
+ fVolumeList = new BList();
+
+ Run();
+}
+
+HBManager::~HBManager()
+{
+ delete fFifoList;
+ delete fThreadList;
+ delete fVolumeList;
+}
+
+void HBManager::MessageReceived( BMessage * message )
+{
+ switch( message->what )
+ {
+ case DETECT_VOLUMES:
+ {
+ DetectVolumes();
+ break;
+ }
+
+ default:
+ BLooper::MessageReceived( message );
+ }
+}
+
+void HBManager::SetPosition( float position )
+{
+ if( position - fPosition < 0.0001 )
+ /* No need to be more precise ;) */
+ return;
+
+ fPosition = position;
+
+ char statusText[128]; memset( statusText, 0, 128 );
+ sprintf( statusText, "Encoding : %.2f %% - %.2f fps (average : %.2f fps)",
+ 100 * fPosition, fCurrentFrameRate, fAverageFrameRate );
+ Status( statusText, fPosition, ENABLE_ENCODING );
+}
+
+void HBManager::SetFrameRate( float current, float average )
+{
+ fCurrentFrameRate = current;
+ fAverageFrameRate = average;
+
+ char statusText[128]; memset( statusText, 0, 128 );
+ sprintf( statusText, "Encoding : %.2f %% - %.2f fps (average : %.2f fps)",
+ 100 * fPosition, fCurrentFrameRate, fAverageFrameRate );
+ Status( statusText, fPosition, ENABLE_ENCODING );
+}
+
+void HBManager::Start( HBVolumeInfo * volumeInfo,
+ HBTitleInfo * titleInfo,
+ HBAudioInfo * audio1Info,
+ HBAudioInfo * audio2Info,
+ char * file )
+{
+ fPosition = 0;
+ fCurrentFrameRate = 0;
+ fAverageFrameRate = 0;
+
+ /* Remember the fifos that should be freezed in Stop() */
+ fFifoList->AddItem( ( titleInfo->fPSFifo = new HBFifo( 1024 ) ) );
+ fFifoList->AddItem( ( titleInfo->fMpeg2Fifo = new HBFifo( 5 ) ) );
+ fFifoList->AddItem( ( titleInfo->fRawFifo = new HBFifo( 5 ) ) );
+ fFifoList->AddItem( ( titleInfo->fMpeg4Fifo = new HBFifo( 5 ) ) );
+
+ /* Create the threads */
+ fThreadList->AddItem( new HBDVDReader( this, titleInfo ) );
+ fThreadList->AddItem( new HBMpegDemux( this, titleInfo,
+ audio1Info, audio2Info ) );
+ fThreadList->AddItem( new HBMpeg2Decoder( this, titleInfo ) );
+ fThreadList->AddItem( new HBMpeg4Encoder( this, titleInfo ) );
+
+ if( audio1Info->fId )
+ {
+ fFifoList->AddItem( ( audio1Info->fAc3Fifo = new HBFifo( 5 ) ) );
+ fFifoList->AddItem( ( audio1Info->fRawFifo = new HBFifo( 5 ) ) );
+ fFifoList->AddItem( ( audio1Info->fMp3Fifo = new HBFifo( 5 ) ) );
+ fThreadList->AddItem( new HBAc3Decoder( this, audio1Info ) );
+ fThreadList->AddItem( new HBMp3Encoder( this, audio1Info ) );
+ }
+
+ if( audio2Info->fId )
+ {
+ fFifoList->AddItem( ( audio2Info->fAc3Fifo = new HBFifo( 5 ) ) );
+ fFifoList->AddItem( ( audio2Info->fRawFifo = new HBFifo( 5 ) ) );
+ fFifoList->AddItem( ( audio2Info->fMp3Fifo = new HBFifo( 5 ) ) );
+ fThreadList->AddItem( new HBAc3Decoder( this, audio2Info ) );
+ fThreadList->AddItem( new HBMp3Encoder( this, audio2Info ) );
+ }
+
+ fThreadList->AddItem( new HBAviMuxer( this, titleInfo, audio1Info,
+ audio2Info, file ) );
+
+ /* Run ! */
+ HBThread * thread;
+ for( int i = 0; i < fThreadList->CountItems(); i++ )
+ {
+ thread = (HBThread*) fThreadList->ItemAt( i );
+ thread->Run();
+ }
+}
+
+void HBManager::Suspend()
+{
+ HBThread * thread;
+ for( int i = 0; i < fThreadList->CountItems(); i++ )
+ {
+ thread = (HBThread*) fThreadList->ItemAt( i );
+ thread->Suspend();
+ }
+}
+
+void HBManager::Resume()
+{
+ HBThread * thread;
+ for( int i = 0; i < fThreadList->CountItems(); i++ )
+ {
+ thread = (HBThread*) fThreadList->ItemAt( i );
+ thread->Resume();
+ }
+}
+
+bool HBManager::Cancel()
+{
+ if( !( fFifoList->CountItems() ) )
+ /* Not running */
+ return false;
+
+ Status( "Cancelled.", 0.0, ENABLE_READY );
+ Stop();
+
+ return true;
+}
+
+/* Called by the DVD reader */
+void HBManager::Done()
+{
+ HBFifo * fifo = NULL;
+ for( int i = 0; i < fFifoList->CountItems(); i++ )
+ {
+ fifo = (HBFifo*) fFifoList->ItemAt( i );
+
+ /* Wait until all threads have finished */
+ while( fifo->Size() > 0 )
+ snooze( 5000 );
+ }
+
+ char statusText[128]; memset( statusText, 0, 128 );
+ sprintf( statusText, "Done (%.2f fps).", fAverageFrameRate );
+ Status( statusText, 1.0, ENABLE_READY );
+ Stop();
+}
+
+void HBManager::Error()
+{
+ Status( "An error occured.", 0.0, ENABLE_READY );
+ Stop();
+}
+
+/* Private */
+
+void HBManager::Stop()
+{
+ /* Freeze fifos */
+ for( int i = 0; i < fFifoList->CountItems(); i++ )
+ {
+ ((HBFifo*) fFifoList->ItemAt( i ))->Die();
+ }
+
+ /* Stop threads */
+ HBThread * thread;
+ while( ( thread = (HBThread*) fThreadList->ItemAt( 0 ) ) )
+ {
+ fThreadList->RemoveItem( thread );
+ delete thread;
+ }
+
+ /* Destroy fifos */
+ HBFifo * fifo;
+ while( ( fifo = (HBFifo*) fFifoList->ItemAt( 0 ) ) )
+ {
+ fFifoList->RemoveItem( fifo );
+ delete fifo;
+ }
+}
+
+void HBManager::DetectVolumes()
+{
+ /* Empty the current list */
+ HBVolumeInfo * volumeInfo;
+ while( ( volumeInfo = (HBVolumeInfo*) fVolumeList->ItemAt( 0 ) ) )
+ {
+ fVolumeList->RemoveItem( volumeInfo );
+ delete volumeInfo;
+ }
+
+ /* Detect the DVD drives by parsing mounted volumes */
+ 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 */
+
+ /* Try to open the device */
+ volumeInfo = new HBVolumeInfo( volumeName,
+ info.device_name );
+
+ if( !volumeInfo->InitCheck() )
+ {
+ delete volumeInfo;
+ continue;
+ }
+
+ fVolumeList->AddItem( volumeInfo );
+ }
+ 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.BUP" ) != B_OK )
+ {
+ delete query;
+ continue;
+ }
+
+ query->Fetch();
+
+ BEntry entry, parentEntry;
+ BPath path;
+ while( query->GetNextEntry( &entry ) != B_ENTRY_NOT_FOUND )
+ {
+ entry.GetParent( &parentEntry );
+ parentEntry.GetPath( &path );
+
+ /* Try to open the folder */
+ volumeInfo = new HBVolumeInfo( (char*) path.Path(),
+ (char*) path.Path() );
+
+ if( !volumeInfo->InitCheck() )
+ {
+ delete volumeInfo;
+ continue;
+ }
+
+ fVolumeList->AddItem( volumeInfo );
+ }
+
+ delete query;
+ }
+ }
+
+ /* Refresh the interface */
+ BMessage * message = new BMessage( VOLUMES_DETECTED );
+ message->AddPointer( "list", fVolumeList );
+ fWindow->PostMessage( message );
+ delete message;
+}
diff --git a/HBManager.h b/HBManager.h
new file mode 100644
index 000000000..c1cabca15
--- /dev/null
+++ b/HBManager.h
@@ -0,0 +1,55 @@
+/* $Id: HBManager.h,v 1.25 2003/08/24 13:55:18 titer Exp $ */
+
+#ifndef _HB_MANAGER_H
+#define _HB_MANAGER_H
+
+#include <Looper.h>
+
+class HBWindow;
+class HBPictureWin;
+class HBFifo;
+
+class HBManager : public BLooper
+{
+ public:
+ HBManager( HBWindow * window );
+ ~HBManager();
+ virtual void MessageReceived( BMessage * message );
+
+ /* Methods called by the interface */
+ void Start( HBVolumeInfo * volumeInfo,
+ HBTitleInfo * titleInfo,
+ HBAudioInfo * audio1Info,
+ HBAudioInfo * audio2Info,
+ char * file );
+ void Suspend();
+ void Resume();
+ bool Cancel();
+
+ /* Methods called by the working threads */
+ void SetPosition( float position );
+ void SetFrameRate( float current, float average );
+ void Done();
+ void Error();
+
+ private:
+ void Stop();
+ void DetectVolumes();
+
+ /* Interface */
+ HBWindow * fWindow;
+
+ /* Fifos & threads */
+ BList * fThreadList;
+ BList * fFifoList;
+
+ /* DVD infos */
+ BList * fVolumeList;
+
+ /* Status infos */
+ float fPosition;
+ float fCurrentFrameRate;
+ float fAverageFrameRate;
+};
+
+#endif
diff --git a/HBMp3Encoder.cpp b/HBMp3Encoder.cpp
new file mode 100644
index 000000000..8cddd7615
--- /dev/null
+++ b/HBMp3Encoder.cpp
@@ -0,0 +1,115 @@
+/* $Id: HBMp3Encoder.cpp,v 1.5 2003/08/24 20:50:49 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBMp3Encoder.h"
+#include "HBManager.h"
+#include "HBFifo.h"
+
+#include <lame/lame.h>
+
+HBMp3Encoder::HBMp3Encoder( HBManager * manager, HBAudioInfo * audioInfo )
+ : HBThread( "mp3encoder" )
+{
+ fManager = manager;
+ fAudioInfo = audioInfo;
+
+ fRawBuffer = NULL;
+}
+
+void HBMp3Encoder::DoWork()
+{
+ while( !fAudioInfo->fRawFifo->Size() )
+ {
+ snooze( 5000 );
+ }
+
+ /* The idea is to have exactly one mp3 frame (i.e. 1152 samples) by
+ output buffer. As we are resampling from fInSampleRate to
+ fOutSampleRate, we will give ( 1152 * fInSampleRate ) /
+ ( 2 * fOutSampleRate ) to libmp3lame so we are sure we will
+ never get more than 1 frame at a time */
+ uint32_t count = ( 1152 * fAudioInfo->fInSampleRate ) /
+ ( 2 * fAudioInfo->fOutSampleRate );
+ fLeftSamples = (float*) malloc( count * sizeof( float ) );
+ fRightSamples = (float*) malloc( count * sizeof( float ) );
+
+ /* Init libmp3lame */
+ lame_global_flags * globalFlags = lame_init();
+ lame_set_in_samplerate( globalFlags, fAudioInfo->fInSampleRate );
+ lame_set_out_samplerate( globalFlags, fAudioInfo->fOutSampleRate );
+ lame_set_brate( globalFlags, fAudioInfo->fOutBitrate );
+ lame_init_params( globalFlags );
+
+ HBBuffer * mp3Buffer;
+ int ret;
+ while( !fDie )
+ {
+ /* Get new samples */
+ if( !GetSamples( count ) )
+ {
+ break;
+ }
+
+ mp3Buffer = new HBBuffer( LAME_MAXMP3BUFFER );
+ ret = lame_encode_buffer_float( globalFlags,
+ fLeftSamples, fRightSamples,
+ count, mp3Buffer->fData,
+ mp3Buffer->fSize );
+
+ if( ret < 0 )
+ {
+ /* Something wrong happened */
+ Log( "HBMp3Encoder : lame_encode_buffer_float() failed (%d)", ret );
+ delete mp3Buffer;
+ fManager->Error();
+ break;
+ }
+ else if( !ret )
+ {
+ delete mp3Buffer;
+ }
+ else if( ret > 0 )
+ {
+ /* We got something, send it to the muxer */
+ mp3Buffer->fSize = ret;
+ mp3Buffer->fKeyFrame = true;
+ fAudioInfo->fMp3Fifo->Push( mp3Buffer );
+ }
+ }
+}
+
+bool HBMp3Encoder::GetSamples( uint32_t count )
+{
+ uint32_t samplesNb = 0;
+
+ while( samplesNb < count )
+ {
+ if( !fRawBuffer )
+ {
+ if( !( fRawBuffer = fAudioInfo->fRawFifo->Pop() ) )
+ {
+ return false;
+ }
+ fPosInBuffer = 0;
+ }
+
+ int willCopy = MIN( count - samplesNb, 6 * 256 - fPosInBuffer );
+ memcpy( fLeftSamples + samplesNb,
+ (float*) fRawBuffer->fData + fPosInBuffer,
+ willCopy * sizeof( float ) );
+ memcpy( fRightSamples + samplesNb,
+ (float*) fRawBuffer->fData + 6 * 256 + fPosInBuffer,
+ willCopy * sizeof( float ) );
+
+ samplesNb += willCopy;
+ fPosInBuffer += willCopy;
+
+ if( fPosInBuffer == 6 * 256 )
+ {
+ delete fRawBuffer;
+ fRawBuffer = NULL;
+ }
+ }
+
+ return true;
+}
diff --git a/HBMp3Encoder.h b/HBMp3Encoder.h
new file mode 100644
index 000000000..02e385224
--- /dev/null
+++ b/HBMp3Encoder.h
@@ -0,0 +1,30 @@
+/* $Id: HBMp3Encoder.h,v 1.3 2003/08/23 19:22:59 titer Exp $ */
+
+#ifndef HB_MP3_ENCODER_H
+#define HB_MP3_ENCODER_H
+
+#include "HBThread.h"
+class HBAudioInfo;
+class HBManager;
+class HBBuffer;
+class HBFifo;
+
+class HBMp3Encoder : public HBThread
+{
+ public:
+ HBMp3Encoder( HBManager * manager, HBAudioInfo * audioInfo );
+
+ private:
+ void DoWork();
+ bool GetSamples( uint32_t count );
+
+ HBManager * fManager;
+ HBAudioInfo * fAudioInfo;
+
+ HBBuffer * fRawBuffer;
+ uint32_t fPosInBuffer; /* in samples */
+ float * fLeftSamples;
+ float * fRightSamples;
+};
+
+#endif
diff --git a/HBMpeg2Decoder.cpp b/HBMpeg2Decoder.cpp
new file mode 100644
index 000000000..f65f2df6b
--- /dev/null
+++ b/HBMpeg2Decoder.cpp
@@ -0,0 +1,168 @@
+/* $Id: HBMpeg2Decoder.cpp,v 1.25 2003/08/23 19:38:47 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBManager.h"
+#include "HBMpeg2Decoder.h"
+#include "HBFifo.h"
+
+extern "C" {
+#include <mpeg2dec/mpeg2.h>
+}
+#include <ffmpeg/avcodec.h>
+
+HBMpeg2Decoder::HBMpeg2Decoder( HBManager * manager, HBTitleInfo * titleInfo )
+ : HBThread( "mpeg2decoder" )
+{
+ fManager = manager;
+ fTitleInfo = titleInfo;
+}
+
+void HBMpeg2Decoder::DoWork()
+{
+ /* Statistics */
+ uint32_t framesSinceLast = 0;
+ uint32_t framesSinceBegin = 0;
+ uint64_t lastTime = 0;
+ uint64_t beginTime = 0;
+
+ /* Init buffers */
+ HBBuffer * mpeg2Buffer = NULL;
+ HBBuffer * rawBuffer = NULL;
+ HBBuffer * deinterlacedBuffer = NULL;
+ HBBuffer * resizedBuffer = NULL;
+ AVPicture * rawPicture = (AVPicture*) malloc( sizeof( AVPicture ) );
+ AVPicture * deinterlacedPicture = (AVPicture*) malloc( sizeof( AVPicture ) );
+ AVPicture * resizedPicture = (AVPicture*) malloc( sizeof( AVPicture ) );
+
+ /* Init libmpeg2 */
+ mpeg2dec_t * handle = mpeg2_init();
+ const mpeg2_info_t * info = mpeg2_info( handle );
+
+ /* libavcodec */
+ ImgReSampleContext * resampleContext = NULL;
+
+ /* NTSC 3:2 pulldown kludge - UGLY ! */
+ if( fTitleInfo->fScale == 900900 )
+ {
+ fTitleInfo->fScale = 1125000;
+ }
+
+ /* Resizing & cropping initializations */
+ resampleContext = img_resample_full_init( fTitleInfo->fOutWidth, fTitleInfo->fOutHeight,
+ fTitleInfo->fInWidth, fTitleInfo->fInHeight,
+ fTitleInfo->fTopCrop, fTitleInfo->fBottomCrop,
+ fTitleInfo->fLeftCrop, fTitleInfo->fRightCrop );
+ rawBuffer = new HBBuffer( 3 * fTitleInfo->fInWidth * fTitleInfo->fInHeight / 2 );
+ deinterlacedBuffer = new HBBuffer( 3 * fTitleInfo->fInWidth * fTitleInfo->fInHeight / 2 );
+ avpicture_fill( rawPicture, rawBuffer->fData,
+ PIX_FMT_YUV420P, fTitleInfo->fInWidth, fTitleInfo->fInHeight );
+ avpicture_fill( deinterlacedPicture, deinterlacedBuffer->fData,
+ PIX_FMT_YUV420P, fTitleInfo->fInWidth, fTitleInfo->fInHeight );
+
+ /* Init statistics */
+ lastTime = system_time();
+ beginTime = system_time();
+
+ Log( "HBMpeg2Decoder : %dx%d -> %dx%d, %.2f fps",
+ fTitleInfo->fInWidth, fTitleInfo->fInHeight,
+ fTitleInfo->fOutWidth, fTitleInfo->fOutHeight,
+ (float) fTitleInfo->fRate / fTitleInfo->fScale );
+
+ /* Main loop */
+ mpeg2_state_t state;
+ for( ;; )
+ {
+ state = mpeg2_parse( handle );
+
+ if( state == STATE_BUFFER )
+ {
+ /* Free the previous buffer */
+ if( mpeg2Buffer )
+ delete mpeg2Buffer;
+
+ /* Get a new one */
+ if( !( mpeg2Buffer = fTitleInfo->fMpeg2Fifo->Pop() ) )
+ break;
+
+ /* Feed libmpeg2 */
+ mpeg2_buffer( handle, mpeg2Buffer->fData,
+ mpeg2Buffer->fData + mpeg2Buffer->fSize );
+ }
+ else if( ( state == STATE_SLICE || state == STATE_END ) &&
+ info->display_fbuf )
+ {
+ /* Got a raw picture */
+
+ /* Copy it */
+ /* TODO : make libmpeg2 write directly in our buffer */
+ memcpy( rawBuffer->fData,
+ info->display_fbuf->buf[0],
+ fTitleInfo->fInWidth * fTitleInfo->fInHeight );
+ memcpy( rawBuffer->fData + fTitleInfo->fInWidth * fTitleInfo->fInHeight,
+ info->display_fbuf->buf[1],
+ fTitleInfo->fInWidth * fTitleInfo->fInHeight / 4 );
+ memcpy( rawBuffer->fData + fTitleInfo->fInWidth * fTitleInfo->fInHeight +
+ fTitleInfo->fInWidth * fTitleInfo->fInHeight / 4,
+ info->display_fbuf->buf[2],
+ fTitleInfo->fInWidth * fTitleInfo->fInHeight / 4 );
+
+ resizedBuffer = new HBBuffer( 3 * fTitleInfo->fOutWidth * fTitleInfo->fOutHeight / 2 );
+ avpicture_fill( resizedPicture, resizedBuffer->fData, PIX_FMT_YUV420P,
+ fTitleInfo->fOutWidth, fTitleInfo->fOutHeight );
+
+ if( fTitleInfo->fDeinterlace )
+ {
+ avpicture_deinterlace( deinterlacedPicture, rawPicture, PIX_FMT_YUV420P,
+ fTitleInfo->fInWidth, fTitleInfo->fInHeight );
+ img_resample( resampleContext, resizedPicture,
+ deinterlacedPicture );
+ }
+ else
+ {
+ img_resample( resampleContext, resizedPicture, rawPicture );
+ }
+
+ /* Send it to the encoder */
+ if( !( fTitleInfo->fRawFifo->Push( resizedBuffer ) ) )
+ {
+ break;
+ }
+
+ /* Update GUI position */
+ fManager->SetPosition( mpeg2Buffer->fPosition );
+
+ /* Statistics every 0.5 second */
+ framesSinceLast++;
+ framesSinceBegin++;
+ if( system_time() - lastTime > 500000 )
+ {
+ fManager->SetFrameRate( 1000000 * (float) framesSinceLast /
+ (float) ( system_time() - lastTime ),
+ 1000000 * (float) framesSinceBegin /
+ (float) ( system_time() - beginTime ) );
+ lastTime = system_time();
+ framesSinceLast = 0;
+ }
+
+ }
+ else if( state == STATE_INVALID )
+ {
+ /* Shouldn't happen on a DVD */
+ Log( "HBMpeg2Decoder : STATE_INVALID" );
+ }
+ }
+
+ /* Close libmpeg2 */
+ mpeg2_close( handle );
+
+ /* Close libavcodec */
+ img_resample_close( resampleContext );
+
+ /* Free structures & buffers */
+ if( mpeg2Buffer ) delete mpeg2Buffer;
+ if( rawBuffer ) delete rawBuffer;
+ if( deinterlacedBuffer ) delete deinterlacedBuffer;
+ if( rawPicture ) free( rawPicture );
+ if( deinterlacedPicture ) free( deinterlacedPicture );
+ if( resizedPicture ) free( resizedPicture );
+}
diff --git a/HBMpeg2Decoder.h b/HBMpeg2Decoder.h
new file mode 100644
index 000000000..00e05dd57
--- /dev/null
+++ b/HBMpeg2Decoder.h
@@ -0,0 +1,27 @@
+/* $Id: HBMpeg2Decoder.h,v 1.9 2003/08/16 10:17:38 titer Exp $ */
+
+#ifndef _HB_MPEG2_DECODER_H
+#define _HB_MPEG2_DECODER_H
+
+#include "HBThread.h"
+class HBManager;
+class HBBuffer;
+class HBFifo;
+
+typedef struct mpeg2dec_s mpeg2dec_t;
+typedef struct AVPicture AVPicture;
+typedef struct ImgReSampleContext ImgReSampleContext;
+
+class HBMpeg2Decoder : public HBThread
+{
+ public:
+ HBMpeg2Decoder( HBManager * manager, HBTitleInfo * titleInfo );
+
+ private:
+ void DoWork();
+
+ HBManager * fManager;
+ HBTitleInfo * fTitleInfo;
+};
+
+#endif
diff --git a/HBMpeg4Encoder.cpp b/HBMpeg4Encoder.cpp
new file mode 100644
index 000000000..f8682330b
--- /dev/null
+++ b/HBMpeg4Encoder.cpp
@@ -0,0 +1,88 @@
+/* $Id: HBMpeg4Encoder.cpp,v 1.18 2003/08/23 19:38:47 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBMpeg4Encoder.h"
+#include "HBManager.h"
+#include "HBFifo.h"
+
+#include <ffmpeg/avcodec.h>
+
+HBMpeg4Encoder::HBMpeg4Encoder( HBManager * manager, HBTitleInfo * titleInfo )
+ : HBThread( "mpeg4encoder" )
+{
+ fManager = manager;
+ fTitleInfo = titleInfo;
+}
+
+void HBMpeg4Encoder::DoWork()
+{
+ /* Init libavcodec */
+ AVCodec * codec = avcodec_find_encoder( CODEC_ID_MPEG4 );
+ if( !codec )
+ {
+ Log( "HBMpeg4Encoder: avcodec_find_encoder() failed" );
+ fManager->Error();
+ return;
+ }
+
+#define WIDTH fTitleInfo->fOutWidth
+#define HEIGHT fTitleInfo->fOutHeight
+#define RATE fTitleInfo->fRate
+#define SCALE fTitleInfo->fScale
+
+ AVCodecContext * context;
+ context = avcodec_alloc_context();
+ context->bit_rate = 1024 * fTitleInfo->fBitrate;
+ context->bit_rate_tolerance = 1024 * fTitleInfo->fBitrate;
+ context->flags |= CODEC_FLAG_HQ;
+ context->width = WIDTH;
+ context->height = HEIGHT;
+ context->frame_rate = RATE;
+ context->frame_rate_base = SCALE;
+ context->gop_size = 10 * RATE / SCALE;
+
+ if( avcodec_open( context, codec ) < 0 )
+ {
+ Log( "HBMpeg4Encoder: avcodec_open() failed" );
+ fManager->Error();
+ return;
+ }
+
+ AVFrame * frame = avcodec_alloc_frame();
+ HBBuffer * mpeg4Buffer;
+
+ for( ;; )
+ {
+ /* Get another frame */
+ if( !( fRawBuffer = fTitleInfo->fRawFifo->Pop() ) )
+ break;
+
+ frame->data[0] = fRawBuffer->fData;
+ frame->data[1] = frame->data[0] + WIDTH * HEIGHT;
+ frame->data[2] = frame->data[1] + WIDTH * HEIGHT / 4;
+ frame->linesize[0] = WIDTH;
+ frame->linesize[1] = WIDTH / 2;
+ frame->linesize[2] = WIDTH / 2;
+
+ mpeg4Buffer = new HBBuffer( 3 * WIDTH * HEIGHT / 2 );
+ /* Should be too much. It can't be bigger than the raw video ! */
+
+ mpeg4Buffer->fSize =
+ avcodec_encode_video( context, mpeg4Buffer->fData,
+ mpeg4Buffer->fAllocSize, frame );
+ mpeg4Buffer->fKeyFrame = ( context->coded_frame->key_frame != 0 );
+
+#undef WIDTH
+#undef HEIGHT
+#undef RATE
+#undef SCALE
+
+ delete fRawBuffer;
+
+ /* Mux it */
+ if( !fTitleInfo->fMpeg4Fifo->Push( mpeg4Buffer ) )
+ {
+ break;
+ }
+ }
+}
diff --git a/HBMpeg4Encoder.h b/HBMpeg4Encoder.h
new file mode 100644
index 000000000..3f5ccacfa
--- /dev/null
+++ b/HBMpeg4Encoder.h
@@ -0,0 +1,27 @@
+/* $Id: HBMpeg4Encoder.h,v 1.4 2003/08/05 16:47:19 titer Exp $ */
+
+#ifndef _HB_MPEG4_ENCODER_H
+#define _HB_MPEG4_ENCODER_H
+
+#include "HBThread.h"
+class HBManager;
+class HBFifo;
+class HBAudioInfo;
+class HBTitleInfo;
+class HBBuffer;
+
+class HBMpeg4Encoder : public HBThread
+{
+ public:
+ HBMpeg4Encoder( HBManager * manager, HBTitleInfo * titleInfo );
+
+ private:
+ void DoWork();
+
+ HBManager * fManager;
+ HBTitleInfo * fTitleInfo;
+
+ HBBuffer * fRawBuffer;
+};
+
+#endif
diff --git a/HBMpegDemux.cpp b/HBMpegDemux.cpp
new file mode 100644
index 000000000..5fda3dde3
--- /dev/null
+++ b/HBMpegDemux.cpp
@@ -0,0 +1,244 @@
+/* $Id: HBMpegDemux.cpp,v 1.13 2003/08/24 19:28:18 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBManager.h"
+#include "HBMpegDemux.h"
+#include "HBFifo.h"
+
+extern "C" {
+#include <a52dec/a52.h>
+}
+
+HBMpegDemux::HBMpegDemux( HBManager * manager, HBTitleInfo * titleInfo,
+ HBAudioInfo * audio1Info, HBAudioInfo * audio2Info )
+ : HBThread( "mpegdemux" )
+{
+ fManager = manager;
+ fTitleInfo = titleInfo;
+ fAudio1Info = audio1Info;
+ fAudio2Info = audio2Info;
+
+ fPSBuffer = NULL;
+ fESBuffer = NULL;
+ fESBufferList = NULL;
+
+ fFirstVideoPTS = -1;
+ fFirstAudio1PTS = -1;
+ fFirstAudio2PTS = -1;
+}
+
+void HBMpegDemux::DoWork()
+{
+ while( !fDie )
+ {
+ /* Get a PS packet */
+ fPSBuffer = fTitleInfo->fPSFifo->Pop();
+
+ if( !fPSBuffer )
+ {
+ continue;
+ }
+
+ /* Get the ES data in it */
+ fESBufferList = PStoES( fPSBuffer );
+
+ if( !fESBufferList )
+ {
+ continue;
+ }
+
+ while( ( fESBuffer = (HBBuffer*) fESBufferList->ItemAt( 0 ) ) )
+ {
+ fESBufferList->RemoveItem( fESBuffer );
+
+ /* Look for a decoder for this ES */
+ if( fESBuffer->fStreamId == 0xE0 )
+ {
+ if( fFirstVideoPTS < 0 )
+ {
+ fFirstVideoPTS = fESBuffer->fPTS;
+ }
+ fTitleInfo->fMpeg2Fifo->Push( fESBuffer );
+ }
+ else if( fESBuffer->fStreamId == fAudio1Info->fId )
+ {
+ /* If the audio track starts later than the video,
+ repeat the first frame as long as needed */
+ if( fFirstAudio1PTS < 0 )
+ {
+ fFirstAudio1PTS = fESBuffer->fPTS;
+
+ if( fFirstAudio1PTS > fFirstVideoPTS )
+ {
+ Log( "HBMpegDemux::DoWork() : audio track %x is late",
+ fAudio1Info->fId );
+ InsertSilence( fFirstAudio1PTS - fFirstVideoPTS,
+ fAudio1Info->fAc3Fifo,
+ fESBuffer );
+ }
+ }
+ fAudio1Info->fAc3Fifo->Push( fESBuffer );
+ }
+ else if( fESBuffer->fStreamId == fAudio2Info->fId )
+ {
+ if( fFirstAudio2PTS < 0 )
+ {
+ fFirstAudio2PTS = fESBuffer->fPTS;
+
+ if( fFirstAudio2PTS > fFirstVideoPTS )
+ {
+ Log( "HBMpegDemux::DoWork() : audio track %x is late",
+ fAudio2Info->fId );
+ InsertSilence( fFirstAudio2PTS - fFirstVideoPTS,
+ fAudio2Info->fAc3Fifo,
+ fESBuffer );
+ }
+ }
+ fAudio2Info->fAc3Fifo->Push( fESBuffer );
+ }
+ else
+ {
+ delete fESBuffer;
+ }
+ }
+ delete fESBufferList;
+ }
+}
+
+void HBMpegDemux::InsertSilence( int64_t time, HBFifo * fifo,
+ HBBuffer * buffer )
+{
+ int flags = 0;
+ int sampleRate = 0;
+ int bitrate = 0;
+ int frameSize = a52_syncinfo( buffer->fData, &flags,
+ &sampleRate, &bitrate );
+
+ if( !frameSize )
+ {
+ Log( "HBMpegDemux::InsertSilence() : a52_syncinfo() failed" );
+ return;
+ }
+
+ uint32_t samples = sampleRate * time / 90000;
+ HBBuffer * buffer2;
+
+ Log( "HBMpegDemux::InsertSilence() : adding %d samples", samples );
+
+ for( uint32_t i = 0; i < samples / ( 6 * 256 ); i++ )
+ {
+ buffer2 = new HBBuffer( frameSize );
+ memcpy( buffer2->fData, buffer->fData, frameSize );
+ fifo->Push( buffer2 );
+ }
+}
+
+BList * PStoES( HBBuffer * psBuffer )
+{
+#define psData (psBuffer->fData)
+
+ BList * esBufferList = new BList();
+ HBBuffer * esBuffer;
+ uint32_t pos = 0;
+
+ /* pack_header */
+ if( psData[pos] != 0 || psData[pos+1] != 0 ||
+ psData[pos+2] != 0x1 || psData[pos+3] != 0xBA )
+ {
+ Log( "PStoES : not a PS packet (%02x%02x%02x%02x)",
+ psData[pos] << 24, psData[pos+1] << 16,
+ psData[pos+2] << 8, psData[pos+3] );
+ delete psBuffer;
+ return NULL;
+ }
+ pos += 4; /* pack_start_code */
+ pos += 9; /* pack_header */
+ pos += 1 + ( psData[pos] & 0x7 ); /* stuffing bytes */
+
+ /* system_header */
+ if( psData[pos] == 0 && psData[pos+1] == 0 &&
+ psData[pos+2] == 0x1 && psData[pos+3] == 0xBB )
+ {
+ uint32_t header_length;
+
+ pos += 4; /* system_header_start_code */
+ header_length = ( psData[pos] << 8 ) + psData[pos+1];
+ pos += 2 + header_length;
+ }
+
+ /* PES */
+ while( pos + 2 < psBuffer->fSize &&
+ psData[pos] == 0 && psData[pos+1] == 0 && psData[pos+2] == 0x1 )
+ {
+ uint32_t streamId;
+ uint32_t PES_packet_length;
+ uint32_t PES_packet_end;
+ uint32_t PES_header_data_length;
+ uint32_t PES_header_end;
+ bool hasPTS;
+ uint64_t PTS = 0;
+
+ pos += 3; /* packet_start_code_prefix */
+ streamId = psData[pos++];
+
+ PES_packet_length = ( psData[pos] << 8 ) + psData[pos+1];
+ pos += 2; /* PES_packet_length */
+ PES_packet_end = pos + PES_packet_length;
+
+ hasPTS = ( ( psData[pos+1] >> 6 ) & 0x2 );
+ pos += 2; /* Required headers */
+
+ PES_header_data_length = psData[pos];
+ pos += 1;
+ PES_header_end = pos + PES_header_data_length;
+
+ if( hasPTS )
+ {
+ PTS = ( ( ( psData[pos] >> 1 ) & 0x7 ) << 30 ) +
+ ( psData[pos+1] << 22 ) +
+ ( ( psData[pos+2] >> 1 ) << 15 ) +
+ ( psData[pos+3] << 7 ) +
+ ( psData[pos+4] >> 1 );
+ }
+
+ pos = PES_header_end;
+
+ if( streamId != 0xE0 && streamId != 0xBD )
+ {
+ /* Not interesting */
+ continue;
+ }
+
+ if( streamId == 0xBD )
+ {
+ /* A52 : don't ask */
+ streamId |= ( psData[pos] << 8 );
+ pos += 4;
+ }
+
+ /* Here we hit we ES payload */
+ esBuffer = new HBBuffer( PES_packet_end - pos );
+
+ esBuffer->fPosition = psBuffer->fPosition;
+ esBuffer->fStreamId = streamId;
+ esBuffer->fPTS = PTS;
+ memcpy( esBuffer->fData, psBuffer->fData + pos,
+ PES_packet_end - pos );
+
+ esBufferList->AddItem( esBuffer );
+
+ pos = PES_packet_end;
+ }
+
+ delete psBuffer;
+
+ if( esBufferList && !esBufferList->CountItems() )
+ {
+ delete esBufferList;
+ return NULL;
+ }
+
+ return esBufferList;
+
+#undef psData
+}
diff --git a/HBMpegDemux.h b/HBMpegDemux.h
new file mode 100644
index 000000000..f98c0a0ae
--- /dev/null
+++ b/HBMpegDemux.h
@@ -0,0 +1,38 @@
+/* $Id: HBMpegDemux.h,v 1.7 2003/08/24 13:27:41 titer Exp $ */
+
+#ifndef _HB_MPEG_DEMUX_H
+#define _HB_MPEG_DEMUX_H
+
+#include "HBThread.h"
+class HBManager;
+class HBBuffer;
+class BList;
+
+BList * PStoES( HBBuffer * psBuffer );
+
+class HBMpegDemux : public HBThread
+{
+ public:
+ HBMpegDemux( HBManager * manager, HBTitleInfo * titleInfo,
+ HBAudioInfo * audio1Info, HBAudioInfo * audio2Info );
+
+ private:
+ void DoWork();
+ void InsertSilence( int64_t time, HBFifo * fifo,
+ HBBuffer * buffer );
+
+ HBManager * fManager;
+ HBTitleInfo * fTitleInfo;
+ HBAudioInfo * fAudio1Info;
+ HBAudioInfo * fAudio2Info;
+
+ HBBuffer * fPSBuffer;
+ HBBuffer * fESBuffer;
+ BList * fESBufferList;
+
+ int64_t fFirstVideoPTS;
+ int64_t fFirstAudio1PTS;
+ int64_t fFirstAudio2PTS;
+};
+
+#endif
diff --git a/HBPictureWin.cpp b/HBPictureWin.cpp
new file mode 100644
index 000000000..9849af010
--- /dev/null
+++ b/HBPictureWin.cpp
@@ -0,0 +1,288 @@
+/* $Id: HBPictureWin.cpp,v 1.14 2003/08/24 20:50:49 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBPictureWin.h"
+#include "HBManager.h"
+
+#include <Bitmap.h>
+#include <Box.h>
+#include <CheckBox.h>
+#include <Slider.h>
+
+#include <ffmpeg/avcodec.h>
+
+#define UPDATE_BITMAP 'upbi'
+
+HBPictureView::HBPictureView( BRect rect, BBitmap * bitmap )
+ : BView( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW )
+{
+ fBitmap = bitmap;
+}
+
+void HBPictureView::Draw( BRect rect )
+{
+ if( LockLooper() )
+ {
+ DrawBitmap( fBitmap, Bounds() );
+ UnlockLooper();
+ }
+ else
+ {
+ Log( "HBPictureView::Draw : LockLooper() failed" );
+ }
+
+ BView::Draw( rect );
+}
+
+
+/* Constructor */
+HBPictureWin::HBPictureWin( HBTitleInfo * titleInfo )
+ : BWindow( BRect( 50, 50, 60, 60 ), "Picture settings",
+ B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE )
+{
+ fTitleInfo = titleInfo;
+
+ fMaxOutWidth = fTitleInfo->fInWidth;
+ fMaxOutHeight = MULTIPLE_16( fTitleInfo->fInHeight * fTitleInfo->fPixelHeight /
+ fTitleInfo->fPixelWidth );
+ fBitmap = new BBitmap( BRect( 0, 0, fMaxOutWidth, fMaxOutHeight ),
+ 0, B_RGB32 );
+
+ ResizeTo( fMaxOutWidth + 40, fMaxOutHeight + 330 );
+
+ BRect r;
+
+ /* Add a background view */
+ BView * view;
+ view = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
+ view->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
+ AddChild( view );
+
+ /* First box : picture + slider */
+ r = BRect( 10, 10, fMaxOutWidth + 30, fMaxOutHeight + 65 );
+ BBox * pictureBox;
+ pictureBox = new BBox( r, NULL );
+ pictureBox->SetLabel( "Preview" );
+
+ /* Picture view */
+ r = BRect( 10, 15, fMaxOutWidth + 10, fMaxOutHeight + 15 );
+ fPictureView = new HBPictureView( r, fBitmap );
+ pictureBox->AddChild( fPictureView );
+
+ /* Slider */
+ r = BRect( 10, fMaxOutHeight + 25, fMaxOutWidth + 10, fMaxOutHeight + 55 );
+ fPictureSlider = new BSlider( r, NULL, NULL, new BMessage( UPDATE_BITMAP ), 0, 9 );
+ pictureBox->AddChild( fPictureSlider );
+
+ view->AddChild( pictureBox );
+
+ /* Second box : resize & crop settings */
+ r = BRect( 10, fMaxOutHeight + 75, fMaxOutWidth + 30, fMaxOutHeight + 320 );
+ BBox * settingsBox;
+ settingsBox = new BBox( r, NULL );
+ settingsBox->SetLabel( "Settings" );
+
+ r = BRect( 10, 15, fMaxOutWidth + 10, 45 );
+ fWidthSlider = new BSlider( r, NULL, "Picture size",
+ new BMessage( UPDATE_BITMAP ),
+ 1, fMaxOutWidth / 16,
+ B_TRIANGLE_THUMB );
+ fWidthSlider->SetValue( fMaxOutWidth / 16 );
+ settingsBox->AddChild( fWidthSlider );
+
+ r = BRect( 10, 55, fMaxOutWidth + 10, 85 );
+ fTopCropSlider = new BSlider( r, NULL, "Top cropping",
+ new BMessage( UPDATE_BITMAP ),
+ 0, fTitleInfo->fInHeight / 4,
+ B_TRIANGLE_THUMB );
+ settingsBox->AddChild( fTopCropSlider );
+
+ r = BRect( 10, 95, fMaxOutWidth + 10, 125 );
+ fBottomCropSlider = new BSlider( r, NULL, "Bottom cropping",
+ new BMessage( UPDATE_BITMAP ),
+ 0, fTitleInfo->fInHeight / 4,
+ B_TRIANGLE_THUMB );
+ settingsBox->AddChild( fBottomCropSlider );
+
+ r = BRect( 10, 135, fMaxOutWidth + 10, 165 );
+ fLeftCropSlider = new BSlider( r, NULL, "Left cropping",
+ new BMessage( UPDATE_BITMAP ),
+ 0, fTitleInfo->fInWidth / 4,
+ B_TRIANGLE_THUMB );
+ settingsBox->AddChild( fLeftCropSlider );
+
+ r = BRect( 10, 175, fMaxOutWidth + 10, 205 );
+ fRightCropSlider = new BSlider( r, NULL, "Right cropping",
+ new BMessage( UPDATE_BITMAP ),
+ 0, fTitleInfo->fInWidth / 4,
+ B_TRIANGLE_THUMB );
+ settingsBox->AddChild( fRightCropSlider );
+
+ r = BRect( 10, 215, fMaxOutWidth + 10, 235 );
+ fDeinterlaceCheck = new BCheckBox( r, NULL, "Deinterlace",
+ new BMessage( UPDATE_BITMAP ) );
+ settingsBox->AddChild( fDeinterlaceCheck );
+
+ view->AddChild( settingsBox );
+
+ /* Buttons */
+
+
+ Hide();
+ Show();
+
+ UpdateBitmap( 0 );
+}
+
+bool HBPictureWin::QuitRequested()
+{
+ if( Lock() )
+ {
+ Hide();
+ Unlock();
+ }
+ else
+ {
+ Log( "HBPictureWin::QuitRequested : cannot Lock()" );
+ }
+ return false;
+}
+
+void HBPictureWin::MessageReceived( BMessage * message )
+{
+ switch( message->what )
+ {
+ case UPDATE_BITMAP:
+ UpdateBitmap( fPictureSlider->Value() );
+ fPictureView->Draw( fPictureView->Bounds() );
+ break;
+
+ default:
+ BWindow::MessageReceived( message );
+ }
+}
+
+void HBPictureWin::UpdateBitmap( int which )
+{
+#define fInWidth fTitleInfo->fInWidth
+#define fInHeight fTitleInfo->fInHeight
+#define fPixelWidth fTitleInfo->fPixelWidth
+#define fPixelHeight fTitleInfo->fPixelHeight
+#define fDeinterlace fTitleInfo->fDeinterlace
+#define fOutWidth fTitleInfo->fOutWidth
+#define fOutHeight fTitleInfo->fOutHeight
+#define fTopCrop fTitleInfo->fTopCrop
+#define fBottomCrop fTitleInfo->fBottomCrop
+#define fLeftCrop fTitleInfo->fLeftCrop
+#define fRightCrop fTitleInfo->fRightCrop
+#define fPictures fTitleInfo->fPictures
+
+ fTopCrop = 2 * fTopCropSlider->Value();
+ fBottomCrop = 2 * fBottomCropSlider->Value();
+ fLeftCrop = 2 * fLeftCropSlider->Value();
+ fRightCrop = 2 * fRightCropSlider->Value();
+ fDeinterlace = ( fDeinterlaceCheck->Value() != 0 );
+
+ fOutWidth = MULTIPLE_16( 16 * fWidthSlider->Value() - fLeftCrop - fRightCrop );
+ fOutHeight = MULTIPLE_16( ( fInHeight - fTopCrop - fBottomCrop ) *
+ ( 16 * fWidthSlider->Value() * fPixelHeight ) /
+ ( fInWidth * fPixelWidth ) );
+
+ AVPicture pic1; /* original YUV picture */
+ avpicture_fill( &pic1, fPictures[which],
+ PIX_FMT_YUV420P, fInWidth, fInHeight );
+
+ AVPicture pic2; /* deinterlaced YUV picture */
+ uint8_t * buf2 = (uint8_t*) malloc( 3 * fInWidth * fInHeight / 2 );
+ avpicture_fill( &pic2, buf2, PIX_FMT_YUV420P, fInWidth, fInHeight );
+
+ AVPicture pic3; /* resized YUV picture */
+ uint8_t * buf3 = (uint8_t*) malloc( 3 * fOutWidth * fOutHeight / 2 );
+ avpicture_fill( &pic3, buf3, PIX_FMT_YUV420P, fOutWidth, fOutHeight );
+
+ AVPicture pic4; /* resized RGB picture */
+ uint8_t * buf4 = (uint8_t*) malloc( 4 * fOutWidth * fOutHeight );
+ avpicture_fill( &pic4, buf4, PIX_FMT_RGBA32, fOutWidth, fOutHeight );
+
+ ImgReSampleContext * resampleContext;
+ resampleContext = img_resample_full_init( fOutWidth, fOutHeight,
+ fInWidth, fInHeight,
+ fTopCrop, fBottomCrop,
+ fLeftCrop, fRightCrop );
+
+ if( fDeinterlace )
+ {
+ avpicture_deinterlace( &pic2, &pic1, PIX_FMT_YUV420P, fInWidth, fInHeight );
+ img_resample( resampleContext, &pic3, &pic2 );
+ }
+ else
+ {
+ img_resample( resampleContext, &pic3, &pic1 );
+ }
+ img_convert( &pic4, PIX_FMT_RGBA32, &pic3, PIX_FMT_YUV420P, fOutWidth, fOutHeight );
+
+ /* Blank the bitmap */
+ for( uint32_t i = 0; i < fMaxOutHeight; i++ )
+ {
+ memset( (uint8_t*) fBitmap->Bits() + i * fBitmap->BytesPerRow(),
+ 0, fMaxOutWidth * 4 );
+ }
+
+ /* Draw the picture (centered) */
+ uint32_t leftOffset = ( fMaxOutWidth - fOutWidth ) / 2;
+ uint32_t topOffset = ( fMaxOutHeight - fOutHeight ) / 2;
+ for( uint32_t i = 0; i < fOutHeight; i++ )
+ {
+ memcpy( (uint8_t*) fBitmap->Bits() +
+ ( i + topOffset ) * fBitmap->BytesPerRow() +
+ leftOffset * 4,
+ buf4 + i * fOutWidth * 4,
+ fOutWidth * 4 );
+ }
+
+ /* Draw the cropping zone */
+ memset( (uint8_t*) fBitmap->Bits() +
+ topOffset * fBitmap->BytesPerRow() +
+ leftOffset * 4,
+ 0xFF,
+ fOutWidth * 4 );
+
+ for( uint32_t i = 0; i < fOutHeight; i++ )
+ {
+ memset( (uint8_t*) fBitmap->Bits() +
+ ( i + topOffset ) * fBitmap->BytesPerRow() +
+ leftOffset * 4,
+ 0xFF,
+ 4 );
+ memset( (uint8_t*) fBitmap->Bits() +
+ ( i + topOffset ) * fBitmap->BytesPerRow() +
+ ( leftOffset + fOutWidth - 1 ) * 4,
+ 0xFF,
+ 4 );
+ }
+
+ memset( (uint8_t*) fBitmap->Bits() +
+ ( topOffset + fOutHeight - 1 ) * fBitmap->BytesPerRow() +
+ leftOffset * 4,
+ 0xFF,
+ fOutWidth * 4 );
+
+ /* Clean up */
+ free( buf2 );
+ free( buf3 );
+ free( buf4 );
+
+ /* Show the output size */
+ if( !Lock() )
+ {
+ Log( "HBPictureWin::UpdateBitmap() : cannot Lock()" );
+ return;
+ }
+
+ char label[128]; memset( label, 0, 128 );
+ snprintf( label, 128, "Picture size : %d x %d",
+ fOutWidth, fOutHeight );
+ fWidthSlider->SetLabel( label );
+
+ Unlock();
+}
diff --git a/HBPictureWin.h b/HBPictureWin.h
new file mode 100644
index 000000000..9f1e37648
--- /dev/null
+++ b/HBPictureWin.h
@@ -0,0 +1,52 @@
+/* $Id: HBPictureWin.h,v 1.6 2003/08/20 20:30:30 titer Exp $ */
+
+#ifndef _HB_PICTURE_WIN_H
+#define _HB_PICTURE_WIN_H
+
+class HBTitleInfo;
+
+#include <View.h>
+#include <Window.h>
+class BSlider;
+class BCheckBox;
+
+class HBPictureView : public BView
+{
+ public:
+ HBPictureView::HBPictureView( BRect rect, BBitmap * bitmap );
+ virtual void Draw( BRect rect );
+
+ private:
+ BBitmap * fBitmap;
+};
+
+class HBPictureWin : public BWindow
+{
+ public:
+ HBPictureWin( HBTitleInfo * titleInfo );
+ virtual bool QuitRequested();
+ virtual void MessageReceived( BMessage * message );
+
+ void UpdateBitmap( int which );
+
+
+ private:
+ HBTitleInfo * fTitleInfo;
+
+ /* GUI */
+ HBPictureView * fPictureView;
+ BSlider * fPictureSlider;
+ BBitmap * fBitmap;
+ BSlider * fWidthSlider;
+ BSlider * fTopCropSlider;
+ BSlider * fBottomCropSlider;
+ BSlider * fLeftCropSlider;
+ BSlider * fRightCropSlider;
+ BCheckBox * fDeinterlaceCheck;
+
+ /* Internal infos */
+ uint32_t fMaxOutWidth;
+ uint32_t fMaxOutHeight;
+};
+
+#endif
diff --git a/HBThread.cpp b/HBThread.cpp
new file mode 100644
index 000000000..b36462be0
--- /dev/null
+++ b/HBThread.cpp
@@ -0,0 +1,49 @@
+/* $Id: HBThread.cpp,v 1.3 2003/08/24 13:27:41 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBThread.h"
+
+#include <OS.h>
+
+HBThread::HBThread( char * name, int priority = B_LOW_PRIORITY )
+{
+ fName = strdup( name );
+ fThread = spawn_thread( ThreadFunc, fName, priority, this );
+}
+
+HBThread::~HBThread()
+{
+ fDie = true;
+ Log( "Stopping thread %d (\"%s\")", fThread, fName );
+ int32 exit_value;
+ wait_for_thread( fThread, &exit_value );
+ Log( "Thread %d stopped (\"%s\")", fThread, fName );
+ free( fName );
+}
+
+void HBThread::Run()
+{
+ fDie = false;
+ resume_thread( fThread );
+ Log( "Thread %d started (\"%s\")", fThread, fName );
+}
+
+void HBThread::Suspend()
+{
+ suspend_thread( fThread );
+}
+
+void HBThread::Resume()
+{
+ resume_thread( fThread );
+}
+
+long HBThread::ThreadFunc( HBThread * _this )
+{
+ _this->DoWork();
+ return 0;
+}
+
+void HBThread::DoWork()
+{
+}
diff --git a/HBThread.h b/HBThread.h
new file mode 100644
index 000000000..5356e5c1f
--- /dev/null
+++ b/HBThread.h
@@ -0,0 +1,26 @@
+/* $Id: HBThread.h,v 1.3 2003/08/24 13:27:41 titer Exp $ */
+
+#ifndef _HB_THREAD_H
+#define _HB_THREAD_H
+
+class HBThread
+{
+ public:
+ HBThread( char * name, int priority = 5 );
+ virtual ~HBThread();
+ void Run();
+ void Suspend();
+ void Resume();
+
+ protected:
+ volatile bool fDie;
+
+ private:
+ static long ThreadFunc( HBThread * _this );
+ virtual void DoWork();
+
+ char * fName;
+ int fThread;
+};
+
+#endif
diff --git a/HBWindow.cpp b/HBWindow.cpp
new file mode 100644
index 000000000..0d665ae45
--- /dev/null
+++ b/HBWindow.cpp
@@ -0,0 +1,630 @@
+/* $Id: HBWindow.cpp,v 1.20 2003/08/24 20:50:49 titer Exp $ */
+
+#include "HBCommon.h"
+#include "HBWindow.h"
+#include "HBManager.h"
+#include "HBPictureWin.h"
+
+#include <Alert.h>
+#include <Application.h>
+#include <Box.h>
+#include <Button.h>
+#include <MenuField.h>
+#include <PopUpMenu.h>
+#include <Slider.h>
+#include <StatusBar.h>
+#include <StringView.h>
+#include <TextControl.h>
+
+#define WINDOW_RECT BRect( 100,100,500,505 )
+
+/* HBBox : almost a simple BBox, unless we draw a horizontal line
+ before the "Picture" and "Advanced" buttons. There must be a
+ cleaner way to do this, but I'm not a expert GUI programmer. */
+
+/* Constructor */
+HBBox::HBBox( BRect rect )
+ : BBox( rect, NULL )
+{
+}
+
+/* Draw */
+void HBBox::Draw( BRect rect )
+{
+ /* Inherited method */
+ BBox::Draw( rect );
+
+ /* Draw the line */
+ SetHighColor( 120, 120, 120 );
+ SetLowColor( 255, 255, 255 );
+ StrokeLine( BPoint( 10, 265 ),
+ BPoint( Bounds().Width() - 10, 265 ),
+ B_SOLID_HIGH );
+ StrokeLine( BPoint( 11, 266 ),
+ BPoint( Bounds().Width() - 10, 266 ),
+ B_SOLID_LOW );
+}
+
+/* HBWindow : the real interface */
+
+/* Constructor */
+HBWindow::HBWindow()
+ : BWindow( WINDOW_RECT, "HandBrake " VERSION, B_TITLED_WINDOW,
+ B_NOT_RESIZABLE | B_NOT_ZOOMABLE )
+{
+ BRect r;
+
+ /* Add a background view */
+ BView * view;
+ view = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
+ view->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
+ AddChild( view );
+
+ /* Add the settings box */
+ r = BRect( 10, 10, view->Bounds().Width() - 10,
+ view->Bounds().Height() - 85 );
+ fBox = new HBBox( r );
+ fBox->SetLabel( "Settings" );
+
+ /* Volume */
+ r = BRect( 10, 15, fBox->Bounds().Width() - 10, 35 );
+ fVolumePopUp = new BPopUpMenu( "No DVD found" );
+ fVolumeField = new BMenuField( r, NULL, "Volume :",
+ fVolumePopUp, true );
+ fBox->AddChild( fVolumeField );
+
+ /* Title */
+ r = BRect( 10, 45, fBox->Bounds().Width() - 10, 65 );
+ fTitlePopUp = new BPopUpMenu( "No title found" );
+ fTitleField = new BMenuField( r, NULL, "Title :",
+ fTitlePopUp, true );
+ fBox->AddChild( fTitleField );
+
+ /* Audio 1 */
+ r = BRect( 10, 75, fBox->Bounds().Width() - 10, 95 );
+ fAudio1PopUp = new BPopUpMenu( "No audio found" );
+ fAudio1Field = new BMenuField( r, NULL, "Audio 1 :",
+ fAudio1PopUp, true );
+ fBox->AddChild( fAudio1Field );
+
+ /* Audio 2 */
+ r = BRect( 10, 105, fBox->Bounds().Width() - 10, 125 );
+ fAudio2PopUp = new BPopUpMenu( "No audio found" );
+ fAudio2Field = new BMenuField( r, NULL, "Audio 2 :",
+ fAudio2PopUp, true );
+ fBox->AddChild( fAudio2Field );
+
+ /* Video bitrate */
+ r = BRect( 10, 135, fBox->Bounds().Width() - 10, 165 );
+ fVideoSlider = new BSlider( r, NULL, "Video bitrate : 1024 kbps",
+ new BMessage( VIDEO_SLIDER ),
+ 128, 4096, B_TRIANGLE_THUMB );
+ fVideoSlider->SetValue( 1024 );
+ fBox->AddChild( fVideoSlider );
+
+ /* Audio bitrate */
+ r = BRect( 10, 175, fBox->Bounds().Width() - 10, 205 );
+ fAudioSlider = new BSlider( r, NULL, "Audio bitrate : 128 kbps",
+ new BMessage( AUDIO_SLIDER ),
+ 64, 384, B_TRIANGLE_THUMB );
+ fAudioSlider->SetValue( 128 );
+ fBox->AddChild( fAudioSlider );
+
+ /* Destination file */
+ r = BRect( 10, 215, fBox->Bounds().Width() - 10, 230 );
+ fFileString = new BStringView( r, NULL, "Destination file :" );
+ fBox->AddChild( fFileString );
+ r = BRect( 10, 235, fBox->Bounds().Width() - 90, 255 );
+ fFileControl = new BTextControl( r, NULL, "", "/boot/home/Desktop/Movie.avi",
+ new BMessage() );
+ fFileControl->SetDivider( 0 );
+ fBox->AddChild( fFileControl );
+ r = BRect( fBox->Bounds().Width() - 80, 230,
+ fBox->Bounds().Width() - 10, 255 );
+ fFileButton = new BButton( r, NULL, "Browse...",
+ new BMessage( NOT_IMPLEMENTED ) );
+ fBox->AddChild( fFileButton );
+
+ view->AddChild( fBox );
+
+ /* Settings buttons */
+ r = BRect( fBox->Bounds().Width() - 200, 275,
+ fBox->Bounds().Width() - 100, 300 );
+ fPictureButton = new BButton( r, NULL, "Picture settings...",
+ new BMessage( PICTURE_WIN ) );
+ fBox->AddChild( fPictureButton );
+
+ r = BRect( fBox->Bounds().Width() - 90, 275,
+ fBox->Bounds().Width() - 10, 300 );
+ fAdvancedButton = new BButton( r, NULL, "Advanced...",
+ new BMessage( NOT_IMPLEMENTED ) );
+ fBox->AddChild( fAdvancedButton );
+
+ /* Status bar */
+ r = BRect( 10, view->Bounds().Height() - 75,
+ view->Bounds().Width() - 10, view->Bounds().Height() - 45 );
+ fStatusBar = new BStatusBar( r, NULL, NULL );
+ fStatusBar->SetMaxValue( 1.0 );
+ view->AddChild( fStatusBar );
+
+ /* Buttons */
+ r = BRect( view->Bounds().Width() - 320, view->Bounds().Height() - 35,
+ view->Bounds().Width() - 250, view->Bounds().Height() - 10 );
+ BButton * aboutButton;
+ aboutButton = new BButton( r, NULL, "About...",
+ new BMessage( B_ABOUT_REQUESTED ) );
+ view->AddChild( aboutButton );
+
+ r = BRect( view->Bounds().Width() - 240, view->Bounds().Height() - 35,
+ view->Bounds().Width() - 170, view->Bounds().Height() - 10 );
+ fRefreshButton = new BButton( r, NULL, "Refresh",
+ new BMessage( REFRESH_VOLUMES ) );
+ view->AddChild( fRefreshButton );
+
+ r = BRect( view->Bounds().Width() - 160, view->Bounds().Height() - 35,
+ view->Bounds().Width() - 90, view->Bounds().Height() - 10 );
+ fSuspendButton = new BButton( r, NULL, "Suspend", new BMessage( SUSPEND_CONVERT ) );
+ view->AddChild( fSuspendButton );
+
+ r = BRect( view->Bounds().Width() - 80, view->Bounds().Height() - 35,
+ view->Bounds().Width() - 10, view->Bounds().Height() - 10 );
+ fStartButton = new BButton( r, NULL, "Start !", new BMessage( START_CONVERT ) );
+ view->AddChild( fStartButton );
+}
+
+bool HBWindow::QuitRequested()
+{
+ /* Empty the PopUps - the BMenuItems do not belong to us */
+ HBVolumeInfo * volumeInfo;
+ while( ( volumeInfo = (HBVolumeInfo*) fVolumePopUp->ItemAt( 0 ) ) )
+ {
+ fVolumePopUp->RemoveItem( volumeInfo );
+ }
+
+ HBTitleInfo * titleInfo;
+ while( ( titleInfo = (HBTitleInfo*) fTitlePopUp->ItemAt( 0 ) ) )
+ {
+ fTitlePopUp->RemoveItem( titleInfo );
+ }
+
+ HBAudioInfo * audioInfo;
+ while( ( audioInfo = (HBAudioInfo*) fAudio1PopUp->ItemAt( 0 ) ) )
+ {
+ fAudio1PopUp->RemoveItem( audioInfo );
+ }
+ while( ( audioInfo = (HBAudioInfo*) fAudio2PopUp->ItemAt( 0 ) ) )
+ {
+ fAudio2PopUp->RemoveItem( audioInfo );
+ }
+
+ /* Stop the application */
+ be_app->PostMessage( B_QUIT_REQUESTED );
+ return true;
+}
+
+void HBWindow::MessageReceived( BMessage * message )
+{
+ switch( message->what )
+ {
+ case NOT_IMPLEMENTED:
+ {
+ /* Warn the user with a BAlert */
+ BAlert * alert;
+ alert = new BAlert( "Not implemented",
+ "This feature has not yet been implemented.",
+ "Come back later !" );
+ alert->Go( NULL );
+ break;
+ }
+
+ case VOLUME_SELECTED:
+ case TITLE_SELECTED:
+ case LANGUAGE_SELECTED:
+ SelectionChanged();
+ break;
+
+ case VIDEO_SLIDER:
+ {
+ /* Update the slider label */
+ char label[128]; memset( label, 0, 128 );
+ snprintf( label, 128,
+ "Video bitrate : %ld kbps",
+ fVideoSlider->Value() );
+ fVideoSlider->SetLabel( label );
+ break;
+ }
+
+ case AUDIO_SLIDER:
+ {
+ /* Update the slider label */
+ char label[128]; memset( label, 0, 128 );
+ snprintf( label, 128,
+ "Audio bitrate : %ld kbps",
+ fAudioSlider->Value() );
+ fAudioSlider->SetLabel( label );
+ break;
+ }
+
+ case PICTURE_WIN:
+ {
+ HBTitleInfo * titleInfo;
+ titleInfo = (HBTitleInfo*) fTitlePopUp->FindMarked();
+
+ if( titleInfo->fPictureWin->Lock() )
+ {
+ titleInfo->fPictureWin->Show();
+ titleInfo->fPictureWin->Unlock();
+ break;
+ }
+ else
+ {
+ Log( "Couldn't lock fPictureWin" );
+ }
+
+ break;
+ }
+
+ case SUSPEND_CONVERT:
+ /* Suspend all threads */
+ fManager->Suspend();
+
+ /* Update the button label */
+ if( Lock() )
+ {
+ fSuspendButton->SetLabel( "Resume" );
+ fSuspendButton->SetMessage( new BMessage( RESUME_CONVERT ) );
+ Unlock();
+ }
+ break;
+
+ case RESUME_CONVERT:
+ /* Resume all threads */
+ fManager->Resume();
+
+ /* Update the button label */
+ if( Lock() )
+ {
+ fSuspendButton->SetLabel( "Suspend" );
+ fSuspendButton->SetMessage( new BMessage( SUSPEND_CONVERT ) );
+ Unlock();
+ }
+ break;
+
+ case START_CONVERT:
+ {
+ /* Shouldn't happen */
+ if( !fVolumePopUp->FindMarked() ||
+ !fTitlePopUp->FindMarked() ||
+ !fAudio1PopUp->FindMarked() ||
+ !fAudio2PopUp->FindMarked() )
+ break;
+
+ /* Disable the interface */
+ Status( "Starting...", 0.0, ENABLE_ENCODING );
+
+ /* Start the job */
+ HBVolumeInfo * volumeInfo = (HBVolumeInfo*) fVolumePopUp->FindMarked();
+ HBTitleInfo * titleInfo = (HBTitleInfo*) fTitlePopUp->FindMarked();
+ HBAudioInfo * audio1Info = (HBAudioInfo*) fAudio1PopUp->FindMarked();
+ HBAudioInfo * audio2Info = (HBAudioInfo*) fAudio2PopUp->FindMarked();
+
+ titleInfo->fBitrate = fVideoSlider->Value();
+ audio1Info->fOutBitrate = fAudioSlider->Value();
+ audio2Info->fOutBitrate = fAudioSlider->Value();
+
+ fManager->Start( volumeInfo, titleInfo,
+ audio1Info, audio2Info,
+ (char*) fFileControl->Text() );
+
+ /* Update the button label */
+ if( Lock() )
+ {
+ fStartButton->SetLabel( "Cancel" );
+ fStartButton->SetMessage( new BMessage( STOP_CONVERT ) );
+ Unlock();
+ }
+ break;
+ }
+
+ case STOP_CONVERT:
+ /* Stop the job */
+ fManager->Cancel();
+
+ /* Update the button label */
+ if( Lock() )
+ {
+ fStartButton->SetLabel( "Start !" );
+ fStartButton->SetMessage( new BMessage( START_CONVERT ) );
+ Unlock();
+ }
+
+ /* Enable the interface */
+ Status( "Cancelled.", 0.0, ENABLE_READY );
+ break;
+
+ case REFRESH_VOLUMES:
+ /* Disable the interface */
+ Status( "Checking DVD volumes...", 0.0, ENABLE_DETECTING );
+
+ /* Ask the manager to start the detection */
+ fManager->PostMessage( DETECT_VOLUMES );
+ break;
+
+ case VOLUMES_DETECTED:
+ {
+ /* Update the popup */
+ BList * volumeList;
+ message->FindPointer( "list", (void**)&volumeList );
+ RefreshVolumes( volumeList );
+
+ /* Enable the interface */
+ Status( "Ready.", 0.0, ENABLE_READY );
+ break;
+ }
+
+ case B_ABOUT_REQUESTED:
+ {
+ BAlert * alert;
+ alert = new BAlert( "title",
+ "HandBrake " VERSION "\n\n"
+ "by Eric Petit <[email protected]>\n"
+ "Homepage : <http://beos.titer.org/handbrake/>\n\n"
+ "No, you don't want to know where this stupid app "
+ "name comes from.",
+ "Woot !" );
+ alert->Go( NULL );
+ break;
+ }
+
+ case MANAGER_CREATED:
+ {
+ message->FindPointer( "manager", (void**)&fManager );
+ break;
+ }
+
+ case CHANGE_STATUS:
+ {
+ char * text;
+ float pos;
+ int mode;
+ message->FindPointer( "text", (void**) &text );
+ message->FindFloat( "pos", &pos );
+ message->FindInt32( "mode", (int32*) &mode );
+
+ if( !Lock() )
+ {
+ Log( "HBWindow::MessageReceived() : Lock() failed" );
+ break;
+ }
+ fStatusBar->Update( pos - fStatusBar->CurrentValue(), text );
+ Enable( mode );
+ Unlock();
+ break;
+ }
+
+ default:
+ {
+ BWindow::MessageReceived( message );
+ }
+ }
+}
+
+void HBWindow::Enable( int mode )
+{
+ switch( mode )
+ {
+ case ENABLE_DETECTING:
+ fVolumeField->SetEnabled( false );
+ fTitleField->SetEnabled( false );
+ fAudio1Field->SetEnabled( false );
+ fAudio2Field->SetEnabled( false );
+ fVideoSlider->SetEnabled( true );
+ fAudioSlider->SetEnabled( true );
+ fFileControl->SetEnabled( true );
+ fAdvancedButton->SetEnabled( true );
+ fFileString->SetHighColor( 0, 0, 0 );
+ fFileString->Invalidate();
+ fPictureButton->SetEnabled( false );
+ fRefreshButton->SetEnabled( false );
+ fSuspendButton->SetEnabled( false );
+ fStartButton->SetEnabled( false );
+ break;
+
+ case ENABLE_READY:
+ fVolumeField->SetEnabled( true );
+ fTitleField->SetEnabled( true );
+ fAudio1Field->SetEnabled( true );
+ fAudio2Field->SetEnabled( true );
+ fVideoSlider->SetEnabled( true );
+ fAudioSlider->SetEnabled( true );
+ fFileControl->SetEnabled( true );
+ fAdvancedButton->SetEnabled( true );
+ fFileString->SetHighColor( 0, 0, 0 );
+ fFileString->Invalidate();
+ fPictureButton->SetEnabled( true );
+ fRefreshButton->SetEnabled( true );
+ fSuspendButton->SetEnabled( false );
+ fStartButton->SetEnabled( true );
+ break;
+
+ case ENABLE_ENCODING:
+ fVolumeField->SetEnabled( false );
+ fTitleField->SetEnabled( false );
+ fAudio1Field->SetEnabled( false );
+ fAudio2Field->SetEnabled( false );
+ fVideoSlider->SetEnabled( false );
+ fAudioSlider->SetEnabled( false );
+ fFileControl->SetEnabled( false );
+ fAdvancedButton->SetEnabled( false );
+ fFileString->SetHighColor( 156, 156, 156 );
+ fFileString->Invalidate();
+ fPictureButton->SetEnabled( false );
+ fRefreshButton->SetEnabled( false );
+ fSuspendButton->SetEnabled( true );
+ fStartButton->SetEnabled( true );
+ break;
+ }
+}
+
+void HBWindow::RefreshVolumes( BList * volumeList )
+{
+ if( !( Lock() ) )
+ {
+ Log( "HBWindow::RefreshVolumes : Lock() failed" );
+ return;
+ }
+
+ /* Empty the PopUps */
+ HBVolumeInfo * volumeInfo;
+ while( ( volumeInfo = (HBVolumeInfo*) fVolumePopUp->ItemAt( 0 ) ) )
+ {
+ fVolumePopUp->RemoveItem( volumeInfo );
+ }
+
+ HBTitleInfo * titleInfo;
+ while( ( titleInfo = (HBTitleInfo*) fTitlePopUp->ItemAt( 0 ) ) )
+ {
+ fTitlePopUp->RemoveItem( titleInfo );
+ }
+
+ HBAudioInfo * audioInfo;
+ while( ( audioInfo = (HBAudioInfo*) fAudio1PopUp->ItemAt( 0 ) ) )
+ {
+ fAudio1PopUp->RemoveItem( audioInfo );
+ }
+ while( ( audioInfo = (HBAudioInfo*) fAudio2PopUp->ItemAt( 0 ) ) )
+ {
+ fAudio2PopUp->RemoveItem( audioInfo );
+ }
+
+ /* Fill the Volumes PopUp */
+ for( int i = 0; i < volumeList->CountItems(); i++ )
+ {
+ fVolumePopUp->AddItem( (HBVolumeInfo*) volumeList->ItemAt( i ) );
+ }
+
+ /* Select the first volume */
+ if( !( volumeInfo = (HBVolumeInfo*) volumeList->ItemAt( 0 ) ) )
+ {
+ Log( "HBWindow::RefreshVolumes : no volume found" );
+ Unlock();
+ return;
+ }
+ volumeInfo->SetMarked( true );
+
+ /* Fill the Titles PopUp */
+ BList * titleList = volumeInfo->fTitleList;
+ for( int i = 0; i < titleList->CountItems(); i++ )
+ {
+ fTitlePopUp->AddItem( (HBTitleInfo*) titleList->ItemAt( i ) );
+ }
+
+ /* Select the first title */
+ if( !( titleInfo = (HBTitleInfo*) titleList->ItemAt( 0 ) ) )
+ {
+ Log( "HBWindow::RefreshVolumes : no title found" );
+ Unlock();
+ return;
+ }
+ titleInfo->SetMarked( true );
+
+ /* Fill the Audios PopUp */
+ BList * audioList1 = titleInfo->fAudioInfoList1;
+ BList * audioList2 = titleInfo->fAudioInfoList2;
+ for( int i = 0; i < audioList1->CountItems(); i++ )
+ {
+ fAudio1PopUp->AddItem( (HBAudioInfo*) audioList1->ItemAt( i ) );
+ fAudio2PopUp->AddItem( (HBAudioInfo*) audioList2->ItemAt( i ) );
+ }
+
+ audioInfo = (HBAudioInfo*) fAudio1PopUp->ItemAt( 0 );
+ audioInfo->SetMarked( true );
+ audioInfo = (HBAudioInfo*) fAudio2PopUp->ItemAt( fAudio2PopUp->CountItems() - 1 );
+ audioInfo->SetMarked( true );
+
+ Unlock();
+}
+
+void HBWindow::SelectionChanged()
+{
+ HBVolumeInfo * volumeInfo;
+ HBTitleInfo * titleInfo;
+ HBAudioInfo * audioInfo;
+
+ /* Update the Title popup if needed */
+ bool updateTitlePopUp = true;
+ volumeInfo = (HBVolumeInfo*) fVolumePopUp->FindMarked();
+ titleInfo = (HBTitleInfo*) fTitlePopUp->FindMarked();
+
+ for( int i = 0; i < volumeInfo->fTitleList->CountItems(); i++ )
+ {
+ if( titleInfo == volumeInfo->fTitleList->ItemAt( i ) )
+ {
+ /* No need to update titles, we already are on the right
+ volume */
+ updateTitlePopUp = false;
+ break;
+ }
+ }
+
+ if( updateTitlePopUp )
+ {
+ /* Empty the popup */
+ while( ( titleInfo = (HBTitleInfo*) fTitlePopUp->ItemAt( 0 ) ) )
+ {
+ fTitlePopUp->RemoveItem( titleInfo );
+ }
+
+ /* Fill it */
+ for( int i = 0; i < volumeInfo->fTitleList->CountItems(); i++ )
+ {
+ fTitlePopUp->AddItem( (HBTitleInfo*) volumeInfo->fTitleList->ItemAt( i ) );
+ }
+
+ /* Select the first title */
+ ((HBTitleInfo*) fTitlePopUp->ItemAt( 0 ))->SetMarked( true );
+ }
+
+ /* Update the Audio popups if needed */
+ bool updateAudioPopUp = true;
+ titleInfo = (HBTitleInfo*) fTitlePopUp->FindMarked();
+ audioInfo = (HBAudioInfo*) fAudio1PopUp->FindMarked();
+
+ for( int i = 0; i < titleInfo->fAudioInfoList1->CountItems(); i++ )
+ {
+ if( audioInfo == titleInfo->fAudioInfoList1->ItemAt( i ) )
+ {
+ /* No need to update audio, we already are on the right
+ title */
+ updateAudioPopUp = false;
+ break;
+ }
+ }
+
+ if( updateAudioPopUp )
+ {
+ /* Empty the popups */
+ while( ( audioInfo = (HBAudioInfo*) fAudio1PopUp->ItemAt( 0 ) ) )
+ {
+ fAudio1PopUp->RemoveItem( audioInfo );
+ }
+ while( ( audioInfo = (HBAudioInfo*) fAudio2PopUp->ItemAt( 0 ) ) )
+ {
+ fAudio2PopUp->RemoveItem( audioInfo );
+ }
+
+ /* Fill it */
+ for( int i = 0; i < titleInfo->fAudioInfoList1->CountItems(); i++ )
+ {
+ fAudio1PopUp->AddItem( (HBAudioInfo*) titleInfo->fAudioInfoList1->ItemAt( i ) );
+ fAudio2PopUp->AddItem( (HBAudioInfo*) titleInfo->fAudioInfoList2->ItemAt( i ) );
+ }
+
+ /* Select the first track */
+ ((HBAudioInfo*) fAudio1PopUp->ItemAt( 0 ))->SetMarked( true );
+
+ /* Select "None" */
+ ((HBAudioInfo*) fAudio2PopUp->ItemAt( fAudio2PopUp->CountItems() - 1 ))->SetMarked( true );
+ }
+
+}
diff --git a/HBWindow.h b/HBWindow.h
new file mode 100644
index 000000000..73aa895b3
--- /dev/null
+++ b/HBWindow.h
@@ -0,0 +1,62 @@
+/* $Id: HBWindow.h,v 1.8 2003/08/24 19:28:18 titer Exp $ */
+
+#ifndef _HB_WINDOW_H
+#define _HB_WINDOW_H
+
+#include <Box.h>
+#include <Window.h>
+
+class HBManager;
+
+class BButton;
+class BMenuField;
+class BPopUpMenu;
+class BSlider;
+class BStatusBar;
+class BStringView;
+class BTextControl;
+
+class HBBox : public BBox
+{
+ public:
+ HBBox( BRect );
+ virtual void Draw( BRect );
+};
+
+class HBWindow : public BWindow
+{
+ public:
+ HBWindow();
+ virtual bool QuitRequested();
+ virtual void MessageReceived( BMessage * message );
+
+ void RefreshVolumes( BList * volumeList );
+
+ private:
+ void Enable( int mode );
+ void SelectionChanged();
+
+ HBManager * fManager;
+ HBBox * fBox;
+ BMenuField * fVolumeField;
+ BPopUpMenu * fVolumePopUp;
+ BMenuField * fTitleField;
+ BPopUpMenu * fTitlePopUp;
+ BMenuField * fAudio1Field;
+ BPopUpMenu * fAudio1PopUp;
+ BMenuField * fAudio2Field;
+ BPopUpMenu * fAudio2PopUp;
+ BSlider * fVideoSlider;
+ BSlider * fAudioSlider;
+ BStringView * fFileString;
+ BTextControl * fFileControl;
+ BButton * fFileButton;
+ BButton * fPictureButton;
+ BButton * fAdvancedButton;
+ BStatusBar * fStatusBar;
+ BButton * fRefreshButton;
+ BButton * fSuspendButton;
+ BButton * fStartButton;
+};
+
+#endif
diff --git a/HandBrake.cpp b/HandBrake.cpp
new file mode 100644
index 000000000..91a2628b4
--- /dev/null
+++ b/HandBrake.cpp
@@ -0,0 +1,18 @@
+/* $Id: HandBrake.cpp,v 1.1.1.1 2003/06/24 13:43:48 titer Exp $ */
+
+#include "HBApp.h"
+
+#include <ffmpeg/avcodec.h>
+
+int main()
+{
+ /* libavcodec initializations */
+ avcodec_init();
+ register_avcodec( &mpeg4_encoder );
+
+ /* Run the BApplication */
+ HBApp * app = new HBApp();
+ app->Run();
+ delete app;
+ return 0;
+}
diff --git a/Jamfile b/Jamfile
new file mode 100644
index 000000000..a3eeaeabd
--- /dev/null
+++ b/Jamfile
@@ -0,0 +1,14 @@
+# $Id: Jamfile,v 1.13 2003/08/24 21:04:14 titer Exp $
+
+HB_VERSION = 0.1 ;
+
+C++FLAGS = $(CPPFLAGS) ;
+C++FLAGS += -g -Wall -Werror -Wno-multichar -O3 -funroll-loops ;
+C++FLAGS += -DVERSION=\\\"$(HB_VERSION)\\\" ;
+LINKFLAGS = $(LDFLAGS) ;
+LINKLIBS = -lbe -ldvdplay -ldvdread -ldvdcss -lmpeg2 -lavcodec -la52 -lmp3lame ;
+
+Main HandBrake :
+ HandBrake.cpp HBAc3Decoder.cpp HBApp.cpp HBAviMuxer.cpp HBCommon.cpp
+ HBDVDReader.cpp HBFifo.cpp HBManager.cpp HBMp3Encoder.cpp HBMpeg2Decoder.cpp
+ HBMpeg4Encoder.cpp HBMpegDemux.cpp HBPictureWin.cpp HBThread.cpp HBWindow.cpp ;
diff --git a/NEWS b/NEWS
new file mode 100644
index 000000000..3a5850314
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,15 @@
+$Id: NEWS,v 1.4 2003/08/24 20:25:49 titer Exp $
+
+Changes between 0.1-alpha2 and 0.1 :
+ - Automatically detect ripped DVDs on BFS volumes
+ - Allow picture cropping and resizing
+ - Allow dual-audio encoding
+ - Created files are quite compliant now (tested with OSX/Quicktime and BSPlayer)
+ - Better A/V sync with some DVDs
+
+Changes between 0.1-alpha and 0.1-alpha2 :
+ - Show length for each title
+ - Fixed the screwed-audio bug
+ - Many bugfixes...
+
+First version is 0.1-alpha. \ No newline at end of file