Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

page_export_avi.cc

Go to the documentation of this file.
00001 /*
00002 * page_export_avi.cc Notebook Firewire/AVI/Still Frame Export Page Object
00003 * Copyright (C) 2001-2007 Dan Dennedy <dan@dennedy.org>
00004 *
00005 * This program is free software; you can redistribute it and/or modify
00006 * it under the terms of the GNU General Public License as published by
00007 * the Free Software Foundation; either version 2 of the License, or
00008 * (at your option) any later version.
00009 *
00010 * This program is distributed in the hope that it will be useful,
00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 * GNU General Public License for more details.
00014 *
00015 * You should have received a copy of the GNU General Public License
00016 * along with this program; if not, write to the Free Software Foundation,
00017 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 #include <iostream>
00025 using std::cerr;
00026 using std::endl;
00027 
00028 #include <gtk/gtk.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 
00032 #include "page_export_avi.h"
00033 #include "preferences.h"
00034 #include "filehandler.h"
00035 #include "message.h"
00036 #include "page_editor.h"
00037 
00044 ExportAVI::ExportAVI( PageExport *_exportPage, KinoCommon *_common ) :
00045         Export( _exportPage, _common ), writer( NULL )
00046 {
00047     cerr << "> Creating ExportAVI Page" << endl;
00048 
00049     /* Get pointers to our controls */
00050     fileEntry = GTK_ENTRY( lookup_widget( common->getWidget(), "entry_export_avi_file" ) );
00051 
00052     formatDV1Toggle
00053     = GTK_TOGGLE_BUTTON( lookup_widget( common->getWidget(),
00054                                         "radiobutton_export_avi_type1" ) );
00055     formatDV2Toggle
00056     = GTK_TOGGLE_BUTTON( lookup_widget( common->getWidget(),
00057                                         "radiobutton_export_avi_type2" ) );
00058     formatRawDVToggle
00059     = GTK_TOGGLE_BUTTON( lookup_widget( common->getWidget(),
00060                                         "radiobutton_export_rawdv" ) );
00061     formatQtToggle
00062     = GTK_TOGGLE_BUTTON( lookup_widget( common->getWidget(),
00063                                         "radiobutton_export_quicktime" ) );
00064 #ifdef HAVE_LIBQUICKTIME
00065     gtk_widget_show( GTK_WIDGET( formatQtToggle ) );
00066     gtk_widget_set_sensitive( GTK_WIDGET( formatQtToggle ), 1 );
00067 #endif
00068 
00069     autoSplitToggle
00070     = GTK_TOGGLE_BUTTON( lookup_widget( common->getWidget(),
00071                                         "checkbutton_export_avi_autosplit" ) );
00072     timeStampToggle
00073     = GTK_TOGGLE_BUTTON( lookup_widget( common->getWidget(),
00074                                         "checkbutton_export_avi_timestamp" ) );
00075     framesEntry
00076     = GTK_ENTRY( lookup_widget( exportPage->getWidget(),
00077                                 "entry_export_avi_frames" ) );
00078     metadataToggle
00079     = GTK_TOGGLE_BUTTON( lookup_widget( exportPage->getWidget(),
00080                                         "checkbutton_export_avi_metadata" ) );
00081     sizeEntry
00082     = GTK_ENTRY( lookup_widget( exportPage->getWidget(),
00083                                 "entry_export_avi_size" ) );
00084     OpenDMLToggle
00085     = GTK_TOGGLE_BUTTON( lookup_widget( common->getWidget(),
00086                                         "checkbutton_export_avi_opendml" ) );
00087 }
00088 
00092 ExportAVI::~ExportAVI()
00093 {
00094     cerr << "> Destroying ExportAVI Page" << endl;
00095 }
00096 
00100 void ExportAVI::start()
00101 {
00102     char s[ 20 ];
00103     cerr << ">> Starting ExportAVI" << endl;
00104 
00105     switch ( Preferences::getInstance().fileFormat )
00106     {
00107     case AVI_DV1_FORMAT:
00108         gtk_toggle_button_set_active( formatDV1Toggle, TRUE );
00109         break;
00110     case AVI_DV2_FORMAT:
00111         gtk_toggle_button_set_active( formatDV2Toggle, TRUE );
00112         break;
00113     case QT_FORMAT:
00114         gtk_toggle_button_set_active( formatQtToggle, TRUE );
00115         break;
00116     default:
00117         gtk_toggle_button_set_active( formatRawDVToggle, TRUE );
00118         break;
00119     }
00120     gtk_toggle_button_set_active( autoSplitToggle,
00121                                   Preferences::getInstance().autoSplit );
00122     gtk_toggle_button_set_active( timeStampToggle,
00123                                   Preferences::getInstance().timeStamp );
00124     gtk_entry_set_text( fileEntry, Preferences::getInstance().file );
00125     sprintf( s, "%d", Preferences::getInstance().frames );
00126     gtk_entry_set_text( framesEntry, s );
00127     sprintf( s, "%d", Preferences::getInstance().maxFileSize );
00128     gtk_entry_set_text( sizeEntry, s );
00129     gtk_toggle_button_set_active( OpenDMLToggle, Preferences::getInstance().isOpenDML );
00130 }
00131 
00135 void ExportAVI::clean()
00136 {
00137     cerr << ">> Leaving ExportAVI" << endl;
00138 }
00139 
00140 
00143 enum export_result
00144 ExportAVI::doExport( PlayList * playlist, int begin, int end, int every,
00145                      bool preview )
00146 {
00147     Frame& frame = *GetFramePool()->GetFrame();
00148     vector <int> scene = common->getPageEditor() ->GetScene();
00149     int sceneIndex = 0;
00150     enum export_result status = EXPORT_RESULT_SUCCESS;
00151 
00152     strcpy( Preferences::getInstance().file, gtk_entry_get_text( fileEntry ) );
00153 
00154     if ( !strcmp( Preferences::getInstance().file, "" ) )
00155     {
00156         modal_message( _( "You must enter a stem filename without an extension." ) );
00157         return EXPORT_RESULT_FAILURE;
00158     }
00159 
00160     bool updateMetadata = gtk_toggle_button_get_active( metadataToggle );
00161 
00162     if ( gtk_toggle_button_get_active( formatDV1Toggle ) )
00163         Preferences::getInstance().fileFormat = AVI_DV1_FORMAT;
00164     if ( gtk_toggle_button_get_active( formatDV2Toggle ) )
00165         Preferences::getInstance().fileFormat = AVI_DV2_FORMAT;
00166     if ( gtk_toggle_button_get_active( formatRawDVToggle ) )
00167         Preferences::getInstance().fileFormat = RAW_FORMAT;
00168     if ( gtk_toggle_button_get_active( formatQtToggle ) )
00169         Preferences::getInstance().fileFormat = QT_FORMAT;
00170     Preferences::getInstance().isOpenDML
00171     = gtk_toggle_button_get_active( OpenDMLToggle );
00172     Preferences::getInstance().autoSplit
00173     = gtk_toggle_button_get_active( autoSplitToggle );
00174     Preferences::getInstance().timeStamp
00175     = gtk_toggle_button_get_active( timeStampToggle );
00176     Preferences::getInstance().frames = atoi( gtk_entry_get_text( framesEntry ) );
00177     Preferences::getInstance().maxFileSize = atoi( gtk_entry_get_text( sizeEntry ) );
00178     exportPage->resetProgress();
00179 
00180     switch ( Preferences::getInstance().fileFormat )
00181     {
00182     case RAW_FORMAT:
00183         writer = new RawHandler();
00184         break;
00185 
00186 #ifdef HAVE_LIBQUICKTIME
00187     case QT_FORMAT:
00188         writer = new QtHandler();
00189         break;
00190 #endif
00191 
00192     case AVI_DV1_FORMAT:
00193     case AVI_DV2_FORMAT:
00194         AVIHandler *aviWriter = new AVIHandler( Preferences::getInstance().fileFormat );
00195         writer = aviWriter;
00196         aviWriter->SetOpenDML( Preferences::getInstance().isOpenDML ||
00197                                Preferences::getInstance().maxFileSize == 0 ||
00198                                Preferences::getInstance().maxFileSize > 1024 );
00199         break;
00200     }
00201     writer->SetMaxFrameCount( Preferences::getInstance().frames );
00202     writer->SetAutoSplit( false );
00203     writer->SetTimeStamp( Preferences::getInstance().timeStamp );
00204     // writer->SetEveryNthFrame( Preferences::getInstance().every );
00205     writer->SetEveryNthFrame( 1 );
00206     writer->SetMaxFileSize( ( off_t ) Preferences::getInstance().maxFileSize * ( off_t ) ( 1024 * 1024 ) );
00207     writer->SetBaseName( Preferences::getInstance().file );
00208 
00209     try
00210     {
00211         time_t datetime = time( NULL );
00212         int frameNum = 0;
00213         int i;
00214         bool resample = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(
00215                             lookup_widget( common->getWidget(), "checkbutton_export_avi_resample" ) ) );
00216         int16_le_t *audio_buffers[ 4 ];
00217         AudioInfo info;
00218         AsyncAudioResample<int16_ne_t,int16_le_t>* resampler = 0;
00219         double adjustedRate = 0;
00220 
00221         for ( i = 0; i < 4; i++ )
00222             audio_buffers[ i ] = ( int16_le_t * ) calloc( 2 * DV_AUDIO_MAX_SAMPLES, sizeof( int16_t ) );
00223 
00224         /* Iterate over all frames */
00225         for ( i = begin; i <= end && exportPage->isExporting; i += every, frameNum++ )
00226         {
00227             innerLoopUpdate( i, begin, end, every );
00228 
00229             // Check for split
00230             playlist->GetFrame( i, frame );
00231             if ( Preferences::getInstance().autoSplit && writer->FileIsOpen()
00232                     && ( i > 0 ) && ( i == scene[ sceneIndex ] ) )
00233             {
00234                 sceneIndex++;
00235                 writer->Close();
00236                 frameNum = 0;
00237                 delete resampler;
00238                 resampler = 0;
00239             }
00240 
00241             /* resample audio */
00242             if ( resample )
00243             {
00244                 if ( ! resampler )
00245                 {
00246                     frame.GetAudioInfo( info );
00247 
00248                     // Determine correct amount of audio for duration
00249                     adjustedRate = calculateAdjustedRate( playlist, info.frequency, i,
00250                         Preferences::getInstance().autoSplit ? ( scene[ sceneIndex ] - 1 ) : end, every );
00251                     if ( ! adjustedRate )
00252                     {
00253                         status = EXPORT_RESULT_ABORT;
00254                         break;
00255                     }
00256 
00257                     // Setup a resampler
00258                     resampler = new AsyncAudioResample<int16_ne_t,int16_le_t>(
00259                         AUDIO_RESAMPLE_SRC_SINC_BEST_QUALITY, playlist, info.frequency, i,
00260                         Preferences::getInstance().autoSplit ? ( scene[ sceneIndex ] - 1 ) : end, every );
00261                     if ( ! resampler )
00262                     {
00263                         status = EXPORT_RESULT_FAILURE;
00264                         break;
00265                     }
00266                     if ( resampler->IsError() )
00267                     {
00268                         status = EXPORT_RESULT_FAILURE;
00269                         throw string( _("Resampler Error: ") ) + resampler->GetError();
00270                     }
00271                 }
00272                 int requestedSamples = frame.CalculateNumberSamples( info.frequency, frameNum );
00273                 info.samples = resampler->Process( adjustedRate, requestedSamples );
00274                 int16_le_t *p = resampler->GetOutput();
00275                 for ( int s = 0; s < info.samples; s++ )
00276                     for ( int c = 0; c < info.channels; c++ )
00277                         audio_buffers[ c ][ s ] = *p++;
00278                 if ( info.samples )
00279                 {
00280                     frame.EncodeAudio( info, audio_buffers );
00281                     frame.ExtractHeader();
00282                 }
00283             }
00284 
00285             if ( updateMetadata )
00286             {
00287                 frame.SetRecordingDate( &datetime, i );
00288                 frame.SetTimeCode( frameNum );
00289             }
00290             if ( writer->WriteFrame( frame ) == false )
00291                 throw _( "Failed to write to file. Is file name OK?" );
00292         }
00293         writer->Close();
00294         if ( !exportPage->isExporting )
00295             status = EXPORT_RESULT_ABORT;
00296 
00297         for ( i = 0; i < 4; i++ )
00298             free( audio_buffers[ i ] );
00299         delete resampler;
00300         resampler = 0;
00301     }
00302     catch ( string s )
00303     {
00304         cerr << "Could not save AVI file "
00305         << Preferences::getInstance().file
00306         << ", because an exception has occurred: " << endl;
00307         cerr << s << endl;
00308         status = EXPORT_RESULT_FAILURE;
00309     }
00310     catch ( const char * exc )
00311     {
00312         modal_message( ( char * ) exc );
00313         status = EXPORT_RESULT_FAILURE;
00314     }
00315 
00316     delete writer;
00317     writer = NULL;
00318 
00319     GetFramePool()->DoneWithFrame( &frame );
00320     
00321     return status;
00322 }
00323 
00324 extern "C"
00325 {
00326     void
00327     on_button_export_avi_file_clicked    (GtkButton       *button,
00328                                             gpointer         user_data)
00329     {
00330         const char *filename = common->getFileToSave( _("Enter a File Name to Save As") );
00331         gtk_widget_grab_focus( lookup_widget( GTK_WIDGET( button ), "entry_export_avi_file" ) );
00332         if ( strcmp( filename, "" ) )
00333             gtk_entry_set_text( GTK_ENTRY( lookup_widget( GTK_WIDGET( button ), "entry_export_avi_file" ) ), filename );
00334     }
00335 }

Generated on Sun Mar 11 22:11:46 2007 for Kino by  doxygen 1.4.2