9 #include "interlacemodes.h"
12 #include "mwindow.inc"
13 #include "quicktime.h"
15 #include "videodevice.inc"
16 #include "cmodel_permutation.h"
17 #include "mainerror.h"
21 #include <sys/types.h>
30 FileDV::FileDV(Asset *asset, File *file)
31 : FileBase(asset, file)
43 audio_sample_buffer = 0;
44 audio_sample_buffer_len = 0;
45 audio_sample_buffer_start = 0;
46 audio_sample_buffer_end = 0;
47 audio_sample_buffer_maxsize = 0;
49 audio_frames_written = 0;
51 if(asset->format == FILE_UNKNOWN)
52 asset->format = FILE_RAWDV;
53 asset->byte_order = 0;
55 stream_lock = new Mutex("FileDV::stream_lock");
56 decoder_lock = new Mutex("FileDV::decoder_lock");
57 video_position_lock = new Mutex("FileDV::video_position_lock");
62 if(stream) close_file();
64 if(decoder) dv_decoder_free(decoder);
65 if(encoder) dv_encoder_free(encoder);
66 if(audio_encoder) dv_encoder_free(audio_encoder);
70 delete video_position_lock;
72 delete[] video_buffer;
73 delete[] audio_buffer;
75 if(audio_sample_buffer)
77 for(int i = 0; i < asset->channels; i++)
78 delete[] audio_sample_buffer[i];
79 delete[] audio_sample_buffer;
83 void FileDV::get_parameters(BC_WindowBase *parent_window,
85 BC_WindowBase* &format_window,
91 DVConfigAudio *window = new DVConfigAudio(parent_window, asset);
92 format_window = window;
93 window->create_objects();
100 DVConfigVideo *window = new DVConfigVideo(parent_window, asset);
101 format_window = window;
102 window->create_objects();
103 window->run_window();
109 int FileDV::reset_parameters_derived()
111 if(decoder) dv_decoder_free(decoder);
112 if(encoder) dv_encoder_free(encoder);
113 if(audio_encoder) dv_encoder_free(audio_encoder);
118 TRACE("FileDV::reset_parameters_derived 10")
120 TRACE("FileDV::reset_parameters_derived: 20")
121 delete[] audio_buffer;
122 delete[] video_buffer;
123 TRACE("FileDV::reset_parameters_derived: 30")
128 if(stream) fclose(stream);
135 if(audio_sample_buffer)
137 for(int i = 0; i < asset->channels; i++)
138 delete[] audio_sample_buffer[i];
139 delete[] audio_sample_buffer;
141 audio_sample_buffer = 0;
142 audio_sample_buffer_start = 0;
143 audio_sample_buffer_len = 0;
144 audio_sample_buffer_end = 0;
145 audio_sample_buffer_maxsize = 0;
147 audio_frames_written = 0;
148 // output_size gets set in open_file, once we know if the frames are PAL or NTSC
149 // output and input are allocated at the same point.
156 int FileDV::open_file(int rd, int wr)
159 TRACE("FileDV::open_file 10")
164 TRACE("FileDV::open_file 20")
167 if (!(asset->height == 576 && asset->width == 720 && asset->frame_rate == 25) &&
168 !(asset->height == 480 && asset->width == 720 && (asset->frame_rate >= 29.96 && asset->frame_rate <= 29.98)))
170 eprintf("Raw DV format does not support following resolution: %ix%i framerate: %f\nAllowed resolutions are 720x576 25fps (PAL) and 720x480 29.97fps (NTSC)\n", asset->width, asset->height, asset->frame_rate);
171 if (asset->height == 480 && asset->width == 720 && asset->frame_rate == 30)
173 eprintf("Suggestion: Proper frame rate for NTSC DV is 29.97 fps, not 30 fps\n");
177 if (!(asset->channels == 2 && (asset->sample_rate == 48000 || asset->sample_rate == 44100)) &&
178 !((asset->channels == 4 || asset->channels == 2) && asset->sample_rate == 32000))
180 eprintf("Raw DV format does not support following audio configuration : %i channels at sample rate: %iHz\n", asset->channels, asset->sample_rate);
185 if((stream = fopen(asset->path, "w+b")) == 0)
187 eprintf("Error while opening \"%s\" for writing. \n%m\n", asset->path);
191 // Create a new encoder
192 if(encoder) dv_encoder_free(encoder);
193 encoder = dv_encoder_new(0,0,0);
194 encoder->vlc_encode_passes = 3;
195 encoder->static_qno = 0;
196 encoder->force_dct = DV_DCT_AUTO;
198 if(audio_encoder) dv_encoder_free(audio_encoder);
199 audio_encoder = dv_encoder_new(0, 0, 0);
200 audio_encoder->vlc_encode_passes = 3;
201 audio_encoder->static_qno = 0;
202 audio_encoder->force_dct = DV_DCT_AUTO;
204 if(decoder) dv_decoder_free(decoder);
205 decoder = dv_decoder_new(0,0,0);
206 decoder->quality = DV_QUALITY_BEST;
209 isPAL = (asset->height == 576 ? 1 : 0);
210 encoder->isPAL = isPAL;
211 output_size = (isPAL ? DV1394_PAL_FRAME_SIZE : DV1394_NTSC_FRAME_SIZE);
213 // Compare to 16 / 8 rather than == 16 / 9 in case of floating point
215 encoder->is16x9 = asset->aspect_ratio > 16 / 8;
221 TRACE("FileDV::open_file 30")
225 TRACE("FileDV::open_file 40")
227 if((stream = fopen(asset->path, "rb")) == 0)
229 eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
233 // temp storage to find out the correct info from the stream.
234 temp = new unsigned char[DV1394_PAL_FRAME_SIZE];
235 memset(temp, 0, DV1394_PAL_FRAME_SIZE);
237 // need file size info to get length.
238 stat(asset->path, &info);
240 TRACE("FileDV::open_file 50")
242 // read the first frame so we can get the stream info from it
243 // by reading the greatest possible frame size, we ensure we get all the
244 // data. libdv will determine if it's PAL or NTSC, and input and output
245 // buffers get allocated accordingly.
246 fread(temp, DV1394_PAL_FRAME_SIZE, 1, stream);
248 TRACE("FileDV::open_file 60")
250 if(decoder) dv_decoder_free(decoder);
251 decoder = dv_decoder_new(0,0,0);
252 decoder->quality = DV_QUALITY_BEST;
255 if(dv_parse_header(decoder, temp) > -1 )
257 // define video params first -- we need to find out output_size
259 asset->video_data = 1;
262 //TODO: according to the information I found, letterbox and widescreen
263 //are the same thing; however, libdv provides a function to check
264 //if the video feed is one of the other. Need to find out if there
266 if(dv_format_normal(decoder) != 0) asset->aspect_ratio = (double) 4 / 3;
267 else asset->aspect_ratio = (double) 16 / 9;
269 asset->width = decoder->width;
270 asset->height = decoder->height;
272 if(dv_is_progressive(decoder) > 0)
273 asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
275 asset->interlace_mode = BC_ILACE_MODE_BOTTOM_FIRST;
277 isPAL = dv_is_PAL(decoder);
279 output_size = (isPAL ? DV1394_PAL_FRAME_SIZE : DV1394_NTSC_FRAME_SIZE);
280 asset->video_length = info.st_size / output_size;
282 if(!asset->frame_rate)
283 asset->frame_rate = (isPAL ? 25 : 29.97);
284 strncpy(asset->vcodec, "dvc ", 4);
286 // see if there are any audio tracks
287 asset->channels = dv_get_num_channels(decoder);
288 if(asset->channels > 0)
290 asset->audio_data = 1;
291 asset->sample_rate = dv_get_frequency(decoder);
292 // libdv always scales the quantization up to 16 bits for dv_decode_full_audio
294 asset->audio_length = (int64_t) (info.st_size / output_size / asset->frame_rate * asset->sample_rate);
295 strncpy(asset->acodec, "dvc ", 4);
298 asset->audio_data = 0;
302 asset->audio_data = 0;
303 asset->video_data = 0;
306 fseeko(stream, 0, SEEK_SET);
307 TRACE("FileDV::open_file 80")
312 // allocate space for audio and video
313 video_buffer = new unsigned char[output_size + 4];
314 audio_buffer = new unsigned char[output_size + 4];
320 int FileDV::check_sig(Asset *asset)
322 unsigned char temp[3];
323 FILE *t_stream = fopen(asset->path, "rb");
325 fread(&temp, 3, 1, t_stream);
329 if(temp[0] == 0x1f &&
337 int FileDV::close_file_derived()
339 if(stream) fclose(stream);
345 int64_t FileDV::get_video_position()
347 return video_position;
350 int64_t FileDV::get_audio_position()
352 return audio_position;
355 int FileDV::set_video_position(int64_t x)
361 int FileDV::set_audio_position(int64_t x)
367 int FileDV::audio_samples_copy(double **buffer, int64_t len)
369 // take the buffer and copy it into a queue
370 if(!audio_sample_buffer)
372 audio_sample_buffer = new int16_t*[asset->channels];
373 if(!audio_sample_buffer)
375 fprintf(stderr, "ERROR: Unable to allocate memory for audio_sample_buffer.\n");
379 for(int i = 0; i < asset->channels; i++)
381 audio_sample_buffer[i] = new int16_t[len * 2];
383 if(!audio_sample_buffer[i])
385 fprintf(stderr, "ERROR: Unable to allocate memory for "
386 "audio_sample_buffer channel %d\n", i);
390 audio_sample_buffer_maxsize = len * 2;
391 audio_sample_buffer_len = 0;
392 audio_sample_buffer_start = 0;
393 audio_sample_buffer_end = 0;
396 if(audio_sample_buffer_maxsize <= audio_sample_buffer_len + len)
398 // Allocate double the needed size
399 for(int i = 0; i < asset->channels; i++)
401 int16_t *tmp = new int16_t[(audio_sample_buffer_len + len) * 2];
404 fprintf(stderr, "ERROR: Unable to reallocate memory for "
405 "audio_sample_buffer channel %d\n", i);
408 // Copy everything from audio_sample_buffer into tmp
409 for(int a = 0, b = audio_sample_buffer_start;
410 a < audio_sample_buffer_len;
411 a++, b = (b < (audio_sample_buffer_maxsize - 1) ? (b + 1) : 0))
413 tmp[a] = audio_sample_buffer[i][b];
415 // Free the current buffer, and reassign tmp to audio_sample_buffer[i]
416 delete[] audio_sample_buffer[i];
417 audio_sample_buffer[i] = tmp;
419 audio_sample_buffer_start = 0;
420 audio_sample_buffer_end = audio_sample_buffer_len - 1;
421 audio_sample_buffer_maxsize = (audio_sample_buffer_len + len) * 2;
425 for(int i = 0; i < asset->channels; i++)
427 if(len + audio_sample_buffer_end < audio_sample_buffer_maxsize)
429 // copy buffer into audio_sample_buffer, straight out (no loop around)
430 for(int a = 0; a < len; a++)
432 audio_sample_buffer[i][audio_sample_buffer_end + a] =
433 (buffer[i][a] * 32767);
435 if(i == (asset->channels - 1))
436 audio_sample_buffer_end += len;
440 // Need to loop back to the start of audio_sample_buffer
441 int copy_size = audio_sample_buffer_maxsize - audio_sample_buffer_end;
443 for(int a = 0; a < copy_size; a++)
444 audio_sample_buffer[i][a + audio_sample_buffer_end] =
445 (buffer[i][a] * 32767);
447 for(int a = 0; a < len - copy_size; a++)
448 audio_sample_buffer[i][a] = (buffer[i][a + copy_size] * 32767);
450 if(i == (asset->channels - 1))
451 audio_sample_buffer_end = len - copy_size;
455 audio_sample_buffer_len += len;
460 int FileDV::write_samples(double **buffer, int64_t len)
462 if(audio_samples_copy(buffer, len) != 0)
464 eprintf("Unable to store sample");
467 video_position_lock->lock("FileDV::write_samples");
469 TRACE("FileDV::write_samples 200")
470 // Get number of frames to be written. Order of operations is important here;
471 // the buffer length must be multiplied by the frame rate first in case the
472 // number of samples in the buffer is less than the sample rate.
473 int nFrames = MIN(video_position - audio_frames_written,
474 audio_sample_buffer_len * asset->frame_rate / asset->sample_rate);
476 video_position_lock->unlock();
478 TRACE("FileDV::write_samples 210")
480 int16_t **tmp_buf = new int16_t*[asset->channels];
481 for(int a = 0; a < asset->channels; a++)
482 tmp_buf[a] = new int16_t[asset->sample_rate];
484 TRACE("FileDV::write_samples 220")
486 for(int i = 0; i < nFrames; i++)
488 stream_lock->lock("FileDV::write_samples 10");
489 if(fseeko(stream, (off_t) audio_frames_written * output_size, SEEK_SET) != 0)
491 eprintf("Unable to set audio write position to %lli\n", (off_t) audio_frames_written * output_size);
493 stream_lock->unlock();
497 if(fread(audio_buffer, output_size, 1, stream) != 1)
499 eprintf("Unable to read from audio buffer file\n");
500 stream_lock->unlock();
504 stream_lock->unlock();
508 TRACE("FileDV::write_samples 230")
510 int samples = dv_calculate_samples(audio_encoder, asset->sample_rate,
511 audio_frames_written);
513 if(samples > audio_sample_buffer_maxsize - 1 - audio_sample_buffer_start)
515 TRACE("FileDV::write_samples 240")
516 int copy_size = audio_sample_buffer_maxsize - audio_sample_buffer_start - 1;
518 for(int a = 0; a < asset->channels; a++)
520 memcpy(tmp_buf[a], audio_sample_buffer[a] + audio_sample_buffer_start,
521 copy_size * sizeof(int16_t));
522 memcpy(tmp_buf[a] + copy_size, audio_sample_buffer[a],
523 (samples - copy_size) * sizeof(int16_t));
525 TRACE("FileDV::write_samples 250")
526 // Encode the audio into the frame
527 if(dv_encode_full_audio(audio_encoder, tmp_buf, asset->channels,
528 asset->sample_rate, audio_buffer) < 0)
530 eprintf("ERROR: unable to encode audio frame %d\n", audio_frames_written);
535 TRACE("FileDV::write_samples 260")
536 int16_t **tmp_buf2 = new int16_t*[asset->channels];
537 for(int a = 0; a < asset->channels; a++)
538 tmp_buf2[a] = audio_sample_buffer[a] + audio_sample_buffer_start;
539 if(dv_encode_full_audio(audio_encoder, tmp_buf2,
540 asset->channels, asset->sample_rate, audio_buffer) < 0)
542 eprintf("ERROR: unable to encode audio frame %d\n", audio_frames_written);
548 TRACE("FileDV::write_samples 270")
550 stream_lock->lock("FileDV::write_samples 20");
551 if(fseeko(stream, (off_t) audio_frames_written * output_size, SEEK_SET) != 0)
553 eprintf("ERROR: Unable to relocate for audio write to %lli\n", (off_t) audio_frames_written * output_size);
554 stream_lock->unlock();
558 if(fwrite(audio_buffer, output_size, 1, stream) != 1)
560 eprintf("Unable to write audio to audio buffer\n");
561 stream_lock->unlock();
565 stream_lock->unlock();
567 audio_frames_written++;
568 audio_sample_buffer_len -= samples;
569 audio_sample_buffer_start += samples;
570 if(audio_sample_buffer_start >= audio_sample_buffer_maxsize)
571 audio_sample_buffer_start -= audio_sample_buffer_maxsize;
574 TRACE("FileDV::write_samples 280")
576 for(int a = 0; a < asset->channels; a++)
580 TRACE("FileDV::write_samples 290")
588 int FileDV::write_frames(VFrame ***frames, int len)
592 if(stream == 0) return 1;
594 for(int j = 0; j < len && !result; j++)
596 VFrame *temp_frame = frames[0][j];
598 //printf("FileDV::write_frames: color_model %i\n", temp_frame->get_color_model());
599 switch(temp_frame->get_color_model())
602 memcpy(video_buffer, temp_frame->get_data(), output_size);
605 //printf("FileDV::write_frames: 4\n");
606 dv_encode_full_frame(encoder, temp_frame->get_rows(),
607 e_dv_color_yuv, video_buffer);
610 //printf("FileDV::write_frames: 5\n");
611 dv_encode_full_frame(encoder, temp_frame->get_rows(),
612 e_dv_color_rgb, video_buffer);
615 unsigned char *data = new unsigned char[asset->height * asset->width * 2];
616 unsigned char **cmodel_buf = new unsigned char *[asset->height];
617 //printf("FileDV::write_frames: 6\n");
618 unsigned char **row_pointers = temp_frame->get_rows();
619 for(int i = 0; i < asset->height; i++)
620 cmodel_buf[i] = data + asset->width * 2 * i;
622 cmodel_transfer(cmodel_buf,
638 temp_frame->get_color_model(),
644 dv_encode_full_frame(encoder, cmodel_buf,
645 e_dv_color_yuv, video_buffer);
651 //printf("FileDV::write_frames: 7\n");
653 // This is the only thread that modifies video_position,
654 // so video_position_lock can remain unlocked for reads.
655 stream_lock->lock("FileDV::write_frames");
656 if(fseeko(stream, (off_t) video_position * output_size, SEEK_SET) != 0)
658 eprintf("Unable to seek file to %lli\n", (off_t)(video_position * output_size));
660 if(fwrite(video_buffer, output_size, 1, stream) < 1)
662 eprintf("Unable to write video data to video buffer");
664 stream_lock->unlock();
666 video_position_lock->lock();
668 video_position_lock->unlock();
674 int FileDV::read_compressed_frame(VFrame *buffer)
677 if(stream == 0) return 0;
679 if (fseeko(stream, (off_t) video_position * output_size, SEEK_SET))
681 eprintf("Unable to seek file to %lli\n", (off_t)(video_position * output_size));
683 result = fread(buffer->get_data(), output_size, 1, stream);
686 buffer->set_compressed_size(result);
691 int FileDV::write_compressed_frame(VFrame *buffer)
694 if(stream == 0) return 0;
696 if (fseeko(stream, (off_t) video_position * output_size, SEEK_SET))
698 eprintf("Unable to seek file to %lli\n", (off_t)(video_position * output_size));
700 result = fwrite(buffer->get_data(), buffer->get_compressed_size(), 1, stream);
705 int64_t FileDV::compressed_frame_size()
710 int FileDV::read_samples(double *buffer, int64_t len)
714 int frame_count = get_audio_frame(audio_position);
715 int offset = get_audio_offset(audio_position);
717 stream_lock->lock("FileDV::read_samples");
720 stream_lock->unlock();
723 stream_lock->unlock();
725 // If the sample rate is 32 kHz, and the bitsize is 12, libdv
726 // requires we have space allocated for 4 channels even if
727 // the data only contains two channels.
729 // decoder will exist since it is not free'd after open_file
730 int channels = (asset->sample_rate == 32000 && decoder->audio->quantization == 12) ? 4 : 2;
732 int16_t **out_buffer = new int16_t*[channels];
733 for(int i = 0; i < channels; i++)
734 out_buffer[i] = new int16_t[DV_AUDIO_MAX_SAMPLES];
740 if(fseeko(stream, (off_t) frame_count * output_size, SEEK_SET) != 0)
742 stream_lock->unlock();
747 if(fread(audio_buffer, output_size, 1, stream) < 1)
749 stream_lock->unlock();
754 stream_lock->unlock();
758 decoder_lock->lock("FileDV::read_samples");
760 if(dv_decode_full_audio(decoder, audio_buffer, out_buffer) < 0)
762 eprintf("Error decoding audio frame %d\n", frame_count - 1);
765 int end = dv_get_num_samples(decoder);
766 decoder_lock->unlock();
768 if(len - count + offset < end)
769 end = len - count + offset;
771 for(int i = offset; i < end; i++)
772 buffer[count++] = out_buffer[file->current_channel][i] / 32767.0;
777 for(int i = 0; i < channels; i++)
778 delete[] out_buffer[i];
781 audio_position += len;
786 int FileDV::read_frame(VFrame *frame)
788 if(stream == 0) return 1;
789 int pitches[3] = {720 * 2, 0, 0};
791 TRACE("FileDV::read_frame 1")
792 unsigned char **row_pointers = frame->get_rows();
795 TRACE("FileDV::read_frame 10")
797 // Seek to video position
798 stream_lock->lock("FileDV::read_frame");
799 if(fseeko(stream, (off_t) video_position * output_size, SEEK_SET) < 0)
801 eprintf("Unable to seek file to %lli", (off_t)(video_position * output_size));
802 stream_lock->unlock();
805 fread(video_buffer, output_size, 1, stream);
806 stream_lock->unlock();
810 TRACE("FileDV::read_frame 20")
812 switch(frame->get_color_model())
816 TRACE("FileDV::read_frame 30")
818 frame->allocate_compressed_data(output_size);
819 frame->set_compressed_size(output_size);
820 memcpy(frame->get_data(), video_buffer, output_size);
824 TRACE("FileDV::read_frame 40")
826 pitches[0] = 720 * 3;
827 decoder_lock->lock("FileDV::read_frame 10");
828 dv_decode_full_frame(decoder, video_buffer, e_dv_color_rgb,
829 row_pointers, pitches);
830 decoder_lock->unlock();
833 TRACE("FileDV::read_frame 50")
834 decoder_lock->lock("FileDV::read_frame 20");
835 dv_decode_full_frame(decoder, video_buffer, e_dv_color_yuv,
836 row_pointers, pitches);
837 decoder_lock->unlock();
841 unsigned char *data = new unsigned char[asset->height * asset->width * 2];
842 unsigned char **temp_pointers = new unsigned char*[asset->height];
844 for(int i = 0; i < asset->height; i++)
845 temp_pointers[i] = data + asset->width * 2 * i;
848 TRACE("FileDV::read_frame 69")
850 decoder_lock->lock("FileDV::read_frame 30");
851 dv_decode_full_frame(decoder, video_buffer, e_dv_color_yuv,
852 temp_pointers, pitches);
853 decoder_lock->unlock();
855 TRACE("FileDV::read_frame 70")
857 cmodel_transfer(row_pointers,
874 frame->get_color_model(),
879 //for(int i = 0; i < asset->height; i++)
880 // delete[] temp_pointers[i];
881 delete[] temp_pointers;
888 TRACE("FileDV::read_frame 80")
895 int FileDV::colormodel_supported(int colormodel)
900 int FileDV::can_copy_from(Edit *edit, int64_t position)
902 if(edit->asset->format == FILE_RAWDV ||
903 (edit->asset->format == FILE_MOV &&
904 (match4(edit->asset->vcodec, QUICKTIME_DV) ||
905 match4(edit->asset->vcodec, QUICKTIME_DVSD) ||
906 match4(edit->asset->vcodec, QUICKTIME_DVCP))))
912 int FileDV::get_best_colormodel(Asset *asset, int driver)
919 case PLAYBACK_X11_XV:
922 case PLAYBACK_DV1394:
923 case PLAYBACK_FIREWIRE:
924 return BC_COMPRESSED;
934 case VIDEO4LINUX2JPEG:
937 case CAPTURE_FIREWIRE:
938 return BC_COMPRESSED;
944 int FileDV::get_audio_frame(int64_t pos)
946 return (double) pos * asset->frame_rate / asset->sample_rate;
949 // Get the sample offset from the frame start reported by get_audio_frame
950 int FileDV::get_audio_offset(int64_t pos)
952 int frame = get_audio_frame(pos);
954 // Samples needed from last frame
955 return pos - frame * asset->sample_rate / asset->frame_rate;
978 DVConfigAudio::DVConfigAudio(BC_WindowBase *parent_window, Asset *asset)
979 : BC_Window(PROGRAM_NAME ": Audio Compression",
980 parent_window->get_abs_cursor_x(1),
981 parent_window->get_abs_cursor_y(1),
985 this->parent_window = parent_window;
989 DVConfigAudio::~DVConfigAudio()
994 int DVConfigAudio::create_objects()
996 add_tool(new BC_Title(10, 10, _("There are no audio options for this format")));
997 add_subwindow(new BC_OKButton(this));
1001 int DVConfigAudio::close_event()
1012 DVConfigVideo::DVConfigVideo(BC_WindowBase *parent_window, Asset *asset)
1013 : BC_Window(PROGRAM_NAME ": Video Compression",
1014 parent_window->get_abs_cursor_x(1),
1015 parent_window->get_abs_cursor_y(1),
1019 this->parent_window = parent_window;
1020 this->asset = asset;
1023 DVConfigVideo::~DVConfigVideo()
1028 int DVConfigVideo::create_objects()
1030 add_tool(new BC_Title(10, 10, _("There are no video options for this format")));
1031 add_subwindow(new BC_OKButton(this));
1035 int DVConfigVideo::close_event()