00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
00225 for ( i = begin; i <= end && exportPage->isExporting; i += every, frameNum++ )
00226 {
00227 innerLoopUpdate( i, begin, end, every );
00228
00229
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
00242 if ( resample )
00243 {
00244 if ( ! resampler )
00245 {
00246 frame.GetAudioInfo( info );
00247
00248
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
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 }