4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "StreamInfo.h"
35 #include "fileavi.inc"
37 #include "mwindow.inc"
48 int FileAVI::avifile_initialized = 0;
54 // Status of AVI derivatives:
55 // Arne2 - depends on Kino, DV only
56 // Lavtools - 2 gig limited
69 FileAVI::FileAVI(Asset *asset, File *file)
70 : FileBase(asset, file)
80 int FileAVI::check_sig(Asset *asset)
82 // Pick whoever gets the most tracks
83 int score_lavtools = 0;
86 int score_avifile = 0;
94 check_sig_lavtools(asset, score_lavtools);
95 check_sig_arne2(asset, score_arne2);
96 check_sig_arne1(asset, score_arne1);
97 check_sig_avifile(asset, score_avifile);
99 if(score_lavtools > final)
101 final = score_lavtools;
102 result = FILE_AVI_LAVTOOLS;
104 if(score_arne2 > final)
107 result = FILE_AVI_ARNE2;
109 if(score_arne1 > final)
112 result = FILE_AVI_ARNE1;
114 if(score_avifile > final)
116 final = score_avifile;
117 result = FILE_AVI_AVIFILE;
129 int FileAVI::check_sig_arne2(Asset *asset, int &score)
134 int FileAVI::check_sig_arne1(Asset *asset, int &score)
139 int FileAVI::check_sig_lavtools(Asset *asset, int &score)
144 int FileAVI::check_sig_avifile(Asset *asset, int &score)
148 IAviReadFile *in_fd = 0;
152 in_fd = CreateIAviReadFile(asset->path);
154 catch(FatalError& error)
156 if(in_fd) delete in_fd;
160 int vtracks = in_fd->VideoStreamCount();
161 int atracks = in_fd->AudioStreamCount();
165 score = vtracks + atracks;
172 char* FileAVI::vcodec_to_fourcc(const char *input, char *output)
175 initialize_avifile();
176 for(avm::vector<CodecInfo>::iterator i = video_codecs.begin();
177 i < video_codecs.end();
180 if(i->direction & CodecInfo::Encode)
182 if(!strcasecmp(i->GetName(), input))
184 memcpy(output, (char*)&i->fourcc, 4);
196 char* FileAVI::fourcc_to_vcodec(char *input, char *output)
199 // Construct codec item list
200 initialize_avifile();
201 for(avm::vector<CodecInfo>::iterator i = video_codecs.begin();
202 i < video_codecs.end();
205 if(i->direction & CodecInfo::Encode)
207 if(!memcmp((char*)&i->fourcc, input, 4))
209 memcpy(output, (char*)&i->fourcc, 4);
210 strcpy(output, i->GetName());;
224 char* FileAVI::acodec_to_fourcc(const char *input, char *output)
227 // Construct codec item list
228 initialize_avifile();
229 for(avm::vector<CodecInfo>::iterator i = audio_codecs.begin();
230 i < audio_codecs.end();
233 if(i->direction & CodecInfo::Encode)
235 if(!strcasecmp(i->GetName(), input))
237 memcpy(output, (char*)&i->fourcc, 4);
249 char* FileAVI::fourcc_to_acodec(char *input, char *output)
252 // Construct codec item list
253 initialize_avifile();
254 for(avm::vector<CodecInfo>::iterator i = audio_codecs.begin();
255 i < audio_codecs.end();
258 if(i->direction & CodecInfo::Encode)
260 if(!memcmp((char*)&i->fourcc, input, 4))
262 memcpy(output, (char*)&i->fourcc, 4);
263 strcpy(output, i->GetName());
277 void FileAVI::initialize_avifile()
280 if(!avifile_initialized)
282 BITMAPINFOHEADER bih;
283 bih.biCompression = 0xffffffff;
284 Creators::CreateVideoDecoder(bih, 0, 0);
287 memset(&wih, 0xff, sizeof(WAVEFORMATEX));
288 Creators::CreateAudioDecoder(&wih, 0);
289 avifile_initialized = 1;
295 int FileAVI::open_file(int rd, int wr)
299 switch(asset->format)
301 case FILE_AVI_LAVTOOLS:
302 return open_lavtools_out(asset);
306 return open_arne2_out(asset);
310 return open_arne1_out(asset);
313 case FILE_AVI_AVIFILE:
314 return open_avifile_out(asset);
321 asset->format = check_sig(asset);
324 switch(asset->format)
326 case FILE_AVI_LAVTOOLS:
327 return open_lavtools_in(asset);
331 return open_arne2_in(asset);
335 return open_arne1_in(asset);
338 case FILE_AVI_AVIFILE:
339 return open_avifile_in(asset);
349 int FileAVI::open_avifile_out(Asset *asset)
354 out_fd = CreateIAviWriteFile(asset->path);
356 catch(FatalError& error)
363 if(asset->video_data)
365 out_color_model = get_best_colormodel(-1, -1);
366 out_bitmap_info = new BitmapInfo(asset->width, asset->height,
367 cmodel_bc_to_avi(out_color_model));
368 for(int i = 0; i < asset->layers && i < MAX_STREAMS; i++)
370 vstream_out[i] = out_fd->AddVideoStream(*(uint32_t*)asset->vcodec,
372 int(1000000.0 / asset->frame_rate));
376 if(asset->audio_data)
379 wfm.wFormatTag = 1; // PCM
380 wfm.nChannels = asset->channels;
381 wfm.nSamplesPerSec = asset->sample_rate;
382 wfm.nAvgBytesPerSec = 2 * asset->sample_rate * asset->channels;
383 wfm.nBlockAlign = 2 * asset->channels;
384 wfm.wBitsPerSample = 16;
387 for(int i = 0; i < asset->channels && i < MAX_STREAMS; i++)
389 astream_out[i] = out_fd->AddStream(AviStream::Audio,
392 1, // uncompressed PCM data
393 wfm.nAvgBytesPerSec, // bytes/sec
394 wfm.nBlockAlign); // bytes/sample
403 int FileAVI::open_arne2_out(Asset *asset)
409 int FileAVI::open_arne1_out(Asset *asset)
414 int FileAVI::open_lavtools_out(Asset *asset)
424 int FileAVI::open_avifile_in(Asset *asset)
429 in_fd = CreateIAviReadFile(asset->path);
431 catch(FatalError& error)
438 asset->layers = in_fd->VideoStreamCount();
441 for(int i = 0; i < asset->layers && i < MAX_STREAMS; i++)
443 vstream_in[i] = in_fd->GetStream(i, IAviReadStream::Video);
444 vstream_in[i]->StartStreaming();
445 vstream_in[i]->GetDecoder()->SetDestFmt(24);
446 vstream_in[i]->Seek(0);
447 //printf("FileAVI::open_file %d %p\n", i, vstream[i]);
450 StreamInfo *stream_info = vstream_in[0]->GetStreamInfo();
451 asset->video_data = 1;
452 if(!asset->frame_rate)
453 asset->frame_rate = (double)1 / vstream_in[0]->GetFrameTime();
454 asset->video_length = stream_info->GetStreamFrames();
456 vstream_in[0]->GetVideoFormatInfo(&bh, sizeof(bh));
457 asset->width = bh.biWidth;
458 asset->height = bh.biHeight;
460 uint32_t fourcc = stream_info->GetFormat();
461 asset->vcodec[0] = ((char*)&fourcc)[0];
462 asset->vcodec[1] = ((char*)&fourcc)[1];
463 asset->vcodec[2] = ((char*)&fourcc)[2];
464 asset->vcodec[3] = ((char*)&fourcc)[3];
465 source_cmodel = BC_RGB888;
469 asset->audio_data = in_fd->AudioStreamCount();
471 if(asset->audio_data)
475 for(int i = 0; i < 1 && i < MAX_STREAMS; i++)
477 astream_in[i] = in_fd->GetStream(i, IAviReadStream::Audio);
478 astream_in[i]->StartStreaming();
481 StreamInfo *stream_info = astream_in[0]->GetStreamInfo();
482 asset->channels = stream_info->GetAudioChannels();
483 if(asset->sample_rate == 0)
484 asset->sample_rate = stream_info->GetAudioSamplesPerSec();
485 asset->bits = MAX(16, stream_info->GetAudioBitsPerSample());
486 asset->audio_length = stream_info->GetStreamFrames();
495 int FileAVI::open_arne2_in(Asset *asset)
500 int FileAVI::open_arne1_in(Asset *asset)
505 int FileAVI::open_lavtools_in(Asset *asset)
527 int FileAVI::close_file()
530 if(in_fd) delete in_fd;
531 if(out_fd) delete out_fd;
532 if(out_bitmap_info) delete out_bitmap_info;
534 if(temp_audio) delete [] temp_audio;
539 int FileAVI::cmodel_bc_to_avi(int input)
556 void FileAVI::reset()
567 int FileAVI::get_best_colormodel(int driver, int colormodel)
581 void FileAVI::get_parameters(BC_WindowBase *parent_window,
583 BC_WindowBase* &format_window,
586 const char *locked_compressor)
590 AVIConfigAudio *window = new AVIConfigAudio(parent_window, asset);
591 format_window = window;
592 window->create_objects();
593 window->run_window();
599 //printf("FileAVI::get_parameters 1\n");
600 AVIConfigVideo *window = new AVIConfigVideo(parent_window,
603 format_window = window;
604 window->create_objects();
605 window->run_window();
610 int FileAVI::set_audio_position(int64_t x)
613 // quicktime sets positions for each track seperately so store position in audio_position
614 if(x >= 0 && x < asset->audio_length)
615 return astream_in[file->current_layer]->Seek(x);
620 int FileAVI::set_video_position(int64_t x)
623 if(x >= 0 && x < asset->video_length)
624 return vstream_in[file->current_layer]->Seek(x);
629 int FileAVI::read_samples(double *buffer, int64_t len)
632 Unsigned samples_read, bytes_read;
634 printf("FileAVI::read_samples 1\n");
635 if(temp_audio && temp_allocated < len * asset->bits / 8 * asset->channels)
637 delete [] temp_audio;
642 temp_allocated = len * asset->bits / 8 * asset->channels;
643 temp_audio = new unsigned char[temp_allocated];
646 astream_in[0]->ReadFrames((void*)temp_audio,
647 (unsigned int)temp_allocated,
652 // Extract single channel
657 int16_t *temp_int16 = (int16_t*)temp_audio;
658 for(int i = 0, j = file->current_channel;
660 i++, j += asset->channels)
662 buffer[i] = (double)temp_int16[j] / 32767;
674 int FileAVI::read_frame(VFrame *frame)
679 vstream_in[file->current_layer]->ReadFrame();
680 CImage *temp_image = vstream_in[file->current_layer]->GetFrame();
681 //printf("FileAVI::read_frame 1 %d %d\n", source_cmodel, frame->get_color_model());
682 switch(source_cmodel)
685 if(frame->get_color_model() == BC_RGB888)
686 bcopy(temp_image->Data(),
688 VFrame::calculate_data_size(asset->width,
698 int64_t FileAVI::compressed_frame_size()
704 int FileAVI::read_compressed_frame(VFrame *buffer)
711 int FileAVI::write_compressed_frame(VFrame *buffer)
718 int FileAVI::write_frames(VFrame ***frames, int len)
724 int FileAVI::write_samples(double **buffer, int64_t len)
733 AVIConfigAudio::AVIConfigAudio(BC_WindowBase *parent_window, Asset *asset)
734 : BC_Window(_(PROGRAM_NAME ": Audio compression"),
735 parent_window->get_abs_cursor_x(1),
736 parent_window->get_abs_cursor_y(1),
737 calculate_w(asset->format),
738 calculate_h(asset->format))
740 this->parent_window = parent_window;
744 AVIConfigAudio::~AVIConfigAudio()
748 int AVIConfigAudio::calculate_w(int format)
752 case FILE_AVI_AVIFILE: return 400; break;
753 case FILE_AVI_ARNE2: return 250; break;
758 int AVIConfigAudio::calculate_h(int format)
762 case FILE_AVI_AVIFILE: return 200; break;
763 case FILE_AVI_ARNE2: return 100; break;
768 void AVIConfigAudio::create_objects()
770 switch(asset->format)
773 case FILE_AVI_AVIFILE:
775 generate_codeclist();
779 add_subwindow(title = new BC_Title(x, y, _("Codec: ")));
780 list = new AVIACodecList(this, x, y);
781 list->create_objects();
788 add_subwindow(new BC_Title(10, 10, _("Compressor: 16 bit PCM")));
792 add_subwindow(new BC_OKButton(this));
795 int AVIConfigAudio::close_event()
800 int AVIConfigAudio::generate_codeclist()
802 FileAVI::initialize_avifile();
803 codec_items.remove_all_objects();
805 switch(asset->format)
808 case FILE_AVI_AVIFILE:
809 for(avm::vector<CodecInfo>::iterator i = audio_codecs.begin();
810 i < audio_codecs.end();
813 if(i->direction & CodecInfo::Encode)
815 codec_items.append(new BC_ListBoxItem((char*)i->GetName()));
825 void AVIConfigAudio::update_codecs()
838 AVIACodecList::AVIACodecList(AVIConfigAudio *gui, int x, int y)
839 : BC_PopupTextBox(gui,
841 FileAVI::fourcc_to_acodec(gui->asset->acodec, gui->string),
850 AVIACodecList::~AVIACodecList()
854 int AVIACodecList::handle_event()
856 strcpy(gui->asset->acodec,
857 FileAVI::acodec_to_fourcc(get_text(), gui->string));
865 AVIConfigVideo::AVIConfigVideo(BC_WindowBase *parent_window,
867 const char *locked_compressor)
868 : BC_Window(_(PROGRAM_NAME ": Video Compression"),
869 parent_window->get_abs_cursor_x(1),
870 parent_window->get_abs_cursor_y(1),
871 calculate_w(asset->format),
872 calculate_h(asset->format))
874 this->parent_window = parent_window;
876 this->locked_compressor = locked_compressor;
880 AVIConfigVideo::~AVIConfigVideo()
882 codec_items.remove_all_objects();
883 attribute_items[0].remove_all_objects();
884 attribute_items[1].remove_all_objects();
887 void AVIConfigVideo::reset()
893 int AVIConfigVideo::calculate_w(int format)
897 case FILE_AVI_AVIFILE: return 400;
898 case FILE_AVI_ARNE2: return 250;
903 int AVIConfigVideo::calculate_h(int format)
907 case FILE_AVI_AVIFILE: return 320;
908 case FILE_AVI_ARNE2: return 100;
913 void AVIConfigVideo::create_objects()
915 switch(asset->format)
918 case FILE_AVI_AVIFILE:
920 generate_codeclist();
921 generate_attributelist();
923 int x = 10, y = 10, x1 = 90;
925 add_subwindow(title = new BC_Title(x, y, _("Codec: ")));
926 list = new AVIVCodecList(this, x1, y);
927 list->create_objects();
928 y += list->get_h() + 5;
930 add_subwindow(title = new BC_Title(x, y, _("Attributes:")));
931 add_subwindow(attributes = new AVIVAttributeList(this, x1, y));
932 y += attributes->get_h() + 5;
934 add_subwindow(new BC_Title(x, y, _("Value:")));
935 add_subwindow(attribute = new AVIVAttribute(this, x1, y));
941 add_subwindow(new BC_Title(10, 10, _("Compressor: Consumer DV")));
945 add_subwindow(new BC_OKButton(this));
948 int AVIConfigVideo::close_event()
953 int AVIConfigVideo::generate_codeclist()
955 FileAVI::initialize_avifile();
956 switch(asset->format)
958 case FILE_AVI_AVIFILE:
960 // Construct codec item list
961 for(avm::vector<CodecInfo>::iterator i = video_codecs.begin();
962 i < video_codecs.end();
965 if(i->direction & CodecInfo::Encode)
967 codec_items.append(new BC_ListBoxItem((char*)i->GetName()));
977 void AVIConfigVideo::generate_attributelist()
980 // Remember selection number
981 int selection_number = attributes ? attributes->get_selection_number(0, 0) : -1;
982 attribute_items[0].remove_all_objects();
983 attribute_items[1].remove_all_objects();
984 FileAVI::initialize_avifile();
986 for(avm::vector<CodecInfo>::iterator i = video_codecs.begin();
987 i < video_codecs.end();
990 if(!memcmp((char*)&i->fourcc, asset->vcodec, 4))
992 avm::vector<AttributeInfo>& attributes = i->encoder_info;
994 for(avm::vector<AttributeInfo>::const_iterator j = attributes.begin();
995 j != attributes.end();
998 char *name = (char*)j->GetName();
999 char value[BCTEXTLEN];
1002 //printf("AVIConfigVideo::generate_attributelist %d\n", j->kind);
1005 case AttributeInfo::Integer:
1008 Creators::GetCodecAttr(*i, name, temp);
1009 sprintf(value, "%d", temp);
1013 case AttributeInfo::Select:
1016 Creators::GetCodecAttr(*i, name, temp);
1017 sprintf(value, "%d ( %s )", temp, j->options[temp].c_str());
1021 case AttributeInfo::String:
1023 const char * temp = 0;
1024 Creators::GetCodecAttr(*i, name, &temp);
1025 if(temp) strncpy(value, temp, BCTEXTLEN);
1030 attribute_items[0].append(new BC_ListBoxItem(name));
1031 attribute_items[1].append(new BC_ListBoxItem(value));
1033 int current_number = j - attributes.begin();
1034 if(current_number == selection_number)
1036 attribute_items[0].values[current_number]->set_selected(1);
1037 attribute_items[1].values[current_number]->set_selected(1);
1045 const char* AVIConfigVideo::get_current_attribute_text()
1047 BC_ListBoxItem *item = attributes->get_selection(0, 0);
1051 return item->get_text();
1057 const char* AVIConfigVideo::get_current_attribute_value()
1059 BC_ListBoxItem *item = attributes->get_selection(1, 0);
1063 return item->get_text();
1069 void AVIConfigVideo::set_current_attribute(const char *text)
1072 int number = attributes->get_selection_number(0, 0);
1076 FileAVI::initialize_avifile();
1078 for(avm::vector<CodecInfo>::iterator i = video_codecs.begin();
1079 i < video_codecs.end();
1082 if(!memcmp((char*)&i->fourcc, asset->vcodec, 4))
1084 avm::vector<AttributeInfo>& attributes = i->encoder_info;
1085 AttributeInfo& attribute = attributes[number];
1087 switch(attribute.kind)
1089 case AttributeInfo::Integer:
1090 Creators::SetCodecAttr(*i, attribute.GetName(), atol(text));
1093 case AttributeInfo::Select:
1094 Creators::SetCodecAttr(*i, attribute.GetName(), atol(text));
1097 case AttributeInfo::String:
1098 Creators::SetCodecAttr(*i, attribute.GetName(), text);
1105 update_attribute(1);
1112 void AVIConfigVideo::update_attribute(int recursive)
1114 generate_attributelist();
1115 attributes->update(attribute_items,
1119 attributes->get_xposition(),
1120 attributes->get_yposition(),
1124 if(!recursive) attribute->update(get_current_attribute_value());
1135 AVIVCodecList::AVIVCodecList(AVIConfigVideo *gui, int x, int y)
1136 : BC_PopupTextBox(gui,
1138 FileAVI::fourcc_to_vcodec(gui->asset->vcodec, gui->string),
1147 AVIVCodecList::~AVIVCodecList()
1151 int AVIVCodecList::handle_event()
1153 strcpy(gui->asset->vcodec, FileAVI::vcodec_to_fourcc(get_text(), gui->string));
1154 gui->update_attribute(0);
1160 AVIVAttributeList::AVIVAttributeList(AVIConfigVideo *gui, int x, int y)
1166 gui->attribute_items,
1174 int AVIVAttributeList::handle_event()
1176 gui->update_attribute(0);
1180 int AVIVAttributeList::selection_changed()
1182 gui->update_attribute(0);
1189 AVIVAttribute::AVIVAttribute(AVIConfigVideo *gui, int x, int y)
1190 : BC_TextBox(x, y, 300, 1, gui->get_current_attribute_value())
1195 int AVIVAttribute::handle_event()
1197 gui->set_current_attribute(get_text());