summaryrefslogtreecommitdiffstats
path: root/HBCommon.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'HBCommon.cpp')
-rw-r--r--HBCommon.cpp566
1 files changed, 566 insertions, 0 deletions
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()
+{
+}