add zoom slider, fix stop_playback on quit, new msg.txt, rework filelist
[goodguy/history.git] / cinelerra-5.1 / cinelerra / filelist.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "cstrdup.h"
25 #include "file.h"
26 #include "filelist.h"
27 #include "guicast.h"
28 #include "interlacemodes.h"
29 #include "mutex.h"
30 #include "mwindow.inc"
31 #include "render.h"
32 #include "renderfarmfsserver.inc"
33 #include "vframe.h"
34 #include "mainerror.h"
35
36 #include <ctype.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42
43
44 FileList::FileList(Asset *asset,
45         File *file,
46         const char *list_prefix,
47         const char *file_extension,
48         int frame_type,
49         int list_type)
50  : FileBase(asset, file)
51 {
52         reset_parameters();
53         path_list.set_array_delete();
54         asset->video_data = 1;
55         this->list_prefix = list_prefix;
56         this->file_extension = file_extension;
57         this->frame_type = frame_type;
58         this->list_type = list_type;
59         table_lock = new Mutex("FileList::table_lock");
60 }
61
62 FileList::~FileList()
63 {
64         close_file();
65         delete table_lock;
66 }
67
68 int FileList::reset_parameters_derived()
69 {
70         data = 0;
71         writer = 0;
72         temp = 0;
73         first_number = 0;
74         return 0;
75 }
76
77 int FileList::open_file(int rd, int wr)
78 {
79         int result = 0;
80
81 // skip header for write
82         if(file->wr)
83         {
84 // Frame files are created in write_frame and list index is created when
85 // file is closed.
86 // Look for the starting number in the path but ignore the starting character
87 // and total digits since these are used by the header.
88                 Render::get_starting_number(asset->path,
89                         first_number,
90                         number_start,
91                         number_digits);
92                 path_list.remove_all_objects();
93                 writer = new FrameWriter(this,
94                         asset->format == list_type ? file->cpus : 1);
95         }
96         else
97         if(file->rd)
98         {
99 // Determine type of file.
100 // Header isn't used for background rendering, in which case everything known
101 // by the file encoder is known by the decoder.
102 //printf("FileList::open_file %d %d\n", __LINE__, asset->use_header);
103                 if(asset->use_header)
104                 {
105                         FILE *stream = fopen(asset->path, "rb");
106 //printf("FileList::open_file %d asset->path=%s\n", __LINE__, asset->path);
107                         if(stream)
108                         {
109                                 char string[BCTEXTLEN];
110                                 (void)fread(string, strlen(list_prefix), 1, stream);
111                                 fclose(stream);
112
113                                 if(!strncasecmp(string, list_prefix, strlen(list_prefix)))
114                                 {
115
116 //printf("FileList::open_file %d\n", __LINE__);
117                                         asset->format = list_type;
118
119 // Open index here or get frame size from file.
120                                         result = read_list_header();
121 //printf("FileList::open_file %d %s\n", __LINE__, path_list.values[0]);
122                                         if(!result) result = read_frame_header(path_list.values[0]);
123                                 }
124                                 else
125                                 {
126 //printf("FileList::open_file 2\n", asset->use_header);
127 //printf("FileList::open_file %d\n", __LINE__);
128                                         asset->format = frame_type;
129                                         result = read_frame_header(asset->path);
130                                         asset->layers = 1;
131                                         if(!asset->frame_rate)
132                                                 asset->frame_rate = 1;
133                                         asset->video_length = -1;
134                                 }
135                         }
136                 }
137                 else
138                 {
139                         Render::get_starting_number(asset->path,
140                                 first_number,
141                                 number_start,
142                                 number_digits,
143                                 6);
144                 }
145         }
146
147         file->current_frame = 0;
148 // Compressed data storage
149         data = new VFrame;
150
151         return result;
152 }
153
154
155 int FileList::close_file()
156 {
157 //      path_list.total, asset->format, list_type, wr);
158         if(asset->format == list_type && path_list.total)
159         {
160                 if(file->wr && asset->use_header) write_list_header();
161                 path_list.remove_all_objects();
162         }
163         if(data) delete data;
164         if(writer) delete writer;
165         if(temp) delete temp;
166         reset_parameters();
167
168         FileBase::close_file();
169         return 0;
170 }
171
172 int FileList::write_list_header()
173 {
174         FILE *stream = fopen(asset->path, "w");
175 // Use sprintf instead of fprintf for VFS.
176         char string[BCTEXTLEN];
177         sprintf(string, "%s\n", list_prefix);
178         fwrite(string, strlen(string), 1, stream);
179         sprintf(string, "# First line is always %s\n", list_prefix);
180         fwrite(string, strlen(string), 1, stream);
181         sprintf(string, "# Frame rate:\n");
182         fwrite(string, strlen(string), 1, stream);
183         sprintf(string, "%f\n", asset->frame_rate);
184         fwrite(string, strlen(string), 1, stream);
185         sprintf(string, "# Width:\n");
186         fwrite(string, strlen(string), 1, stream);
187         sprintf(string, "%d\n", asset->width);
188         fwrite(string, strlen(string), 1, stream);
189         sprintf(string, "# Height:\n");
190         fwrite(string, strlen(string), 1, stream);
191         sprintf(string, "%d\n", asset->height);
192         fwrite(string, strlen(string), 1, stream);
193         sprintf(string, "# List of image files follows\n");
194         fwrite(string, strlen(string), 1, stream);
195
196         for(int i = 0; i < path_list.total; i++)
197         {
198 // Fix path for VFS but leave leading slash
199                 if(!strncmp(path_list.values[i], RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
200                         sprintf(string, "%s\n", path_list.values[i] + strlen(RENDERFARM_FS_PREFIX));
201                 else
202                         sprintf(string, "%s\n", path_list.values[i]);
203                 fwrite(string, strlen(string), 1, stream);
204         }
205         fclose(stream);
206         return 0;
207 }
208
209 int FileList::read_list_header()
210 {
211         char string[BCTEXTLEN];
212
213         FILE *stream = fopen(asset->path, "r");
214         if( !stream ) return 1;
215 // Get information about the frames
216         do {
217                 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
218         } while(string[0] == '#' || string[0] == ' ' || isalpha(string[0]));
219
220 // Don't want a user configured frame rate to get destroyed
221         if(asset->frame_rate == 0)
222                 asset->frame_rate = atof(string);
223
224         do {
225                 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
226         } while(string[0] == '#' || string[0] == ' ');
227         if( (asset->width = atol(string)) <= 0 ) return 1;
228
229         do {
230                 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
231         } while(string[0] == '#' || string[0] == ' ');
232         if( (asset->height = atol(string)) <= 0 ) return 1;
233
234         asset->interlace_mode = ILACE_MODE_UNDETECTED;
235         asset->layers = 1;
236         asset->audio_data = 0;
237         asset->video_data = 1;
238
239 // Get all the paths
240         int missing = 0;
241         while(!feof(stream) && fgets(string, BCTEXTLEN, stream) ) {
242                 int len = strlen(string);
243                 if( !len || string[0] == '#' || string[0] == ' ') continue;
244                 string[len-1] = 0;
245                 if( access(string,R_OK) && !missing++ )
246                         eprintf(_("%s:no such file"), string);
247                 path_list.append(cstrdup(string));
248         }
249
250 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
251         fclose(stream);
252         if( !(asset->video_length = path_list.total) )
253                 eprintf(_("%s:\nlist empty"), asset->path);
254         if( missing )
255                 eprintf(_("%s:\n%d files not found"), asset->path, missing);
256         return 0;
257 }
258
259 int FileList::read_frame(VFrame *frame)
260 {
261         int result = 0;
262
263 //      PRINT_TRACE
264 // printf("FileList::read_frame %d %d use_header=%d current_frame=%d total=%d\n",
265 // __LINE__,
266 // result,
267 // asset->use_header,
268 // file->current_frame,
269 // path_list.total);
270
271         if(file->current_frame < 0 ||
272                 (asset->use_header && file->current_frame >= path_list.total &&
273                         asset->format == list_type))
274                 return 1;
275
276         if(asset->format == list_type)
277         {
278                 char string[BCTEXTLEN];
279                 char *path;
280                 if(asset->use_header)
281                 {
282                         path = path_list.values[file->current_frame];
283                 }
284                 else
285                 {
286                         path = calculate_path(file->current_frame, string);
287                 }
288
289                 FILE *in;
290
291 // Fix path for VFS
292                 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
293                         sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
294                 else
295                         strcpy(string, path);
296
297
298
299                 if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
300                 {
301                         if(!(in = fopen(string, "rb"))) {
302                                 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), string);
303                         }
304                         else
305                         {
306                                 struct stat ostat;
307                                 stat(string, &ostat);
308
309                                 switch(frame->get_color_model())
310                                 {
311                                         case BC_COMPRESSED:
312                                                 frame->allocate_compressed_data(ostat.st_size);
313                                                 frame->set_compressed_size(ostat.st_size);
314                                                 (void)fread(frame->get_data(), ostat.st_size, 1, in);
315                                                 break;
316                                         default:
317                                                 data->allocate_compressed_data(ostat.st_size);
318                                                 data->set_compressed_size(ostat.st_size);
319                                                 (void)fread(data->get_data(), ostat.st_size, 1, in);
320                                                 result = read_frame(frame, data);
321                                                 break;
322                                 }
323
324                                 fclose(in);
325                         }
326                 }
327                 else
328                 {
329 //printf("FileList::read_frame %d %s\n", __LINE__, string);
330                         result = read_frame(frame, string);
331                 }
332         }
333         else
334         {
335                 asset->single_frame = 1;
336 // Allocate and decompress single frame into new temporary
337 //printf("FileList::read_frame %d\n", frame->get_color_model());
338                 if(!temp || temp->get_color_model() != frame->get_color_model())
339                 {
340                         if(temp) delete temp;
341                         temp = 0;
342
343
344                         if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
345                         {
346                                 FILE *fd = fopen(asset->path, "rb");
347                                 if(fd)
348                                 {
349                                         struct stat ostat;
350                                         stat(asset->path, &ostat);
351
352                                         switch(frame->get_color_model())
353                                         {
354                                                 case BC_COMPRESSED:
355                                                         frame->allocate_compressed_data(ostat.st_size);
356                                                         frame->set_compressed_size(ostat.st_size);
357                                                         (void)fread(frame->get_data(), ostat.st_size, 1, fd);
358                                                         break;
359                                                 default:
360                                                         data->allocate_compressed_data(ostat.st_size);
361                                                         data->set_compressed_size(ostat.st_size);
362                                                         (void)fread(data->get_data(), ostat.st_size, 1, fd);
363                                                         temp = new VFrame(0,
364                                                                 -1,
365                                                                 asset->width,
366                                                                 asset->height,
367                                                                 frame->get_color_model(),
368                                                                 -1);
369                                                         read_frame(temp, data);
370                                                         break;
371                                         }
372
373                                         fclose(fd);
374                                 }
375                                 else
376                                 {
377                                         eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
378                                         result = 1;
379                                 }
380                         }
381                         else
382                         {
383                                 temp = new VFrame(0,
384                                         -1,
385                                         asset->width,
386                                         asset->height,
387                                         frame->get_color_model(),
388                                         -1);
389                                 read_frame(temp, asset->path);
390                         }
391                 }
392
393                 if(!temp) return result;
394
395 // printf("FileList::read_frame frame=%d temp=%d\n",
396 // frame->get_color_model(),
397 // temp->get_color_model());
398                 if(frame->get_color_model() == temp->get_color_model())
399                 {
400                         frame->copy_from(temp);
401                 }
402                 else
403                 {
404 // Never happens
405                         BC_CModels::transfer(frame->get_rows(), /* Leave NULL if non existent */
406                                 temp->get_rows(),
407                                 frame->get_y(), /* Leave NULL if non existent */
408                                 frame->get_u(),
409                                 frame->get_v(),
410                                 temp->get_y(), /* Leave NULL if non existent */
411                                 temp->get_u(),
412                                 temp->get_v(),
413                                 0,        /* Dimensions to capture from input frame */
414                                 0,
415                                 asset->width,
416                                 asset->height,
417                                 0,       /* Dimensions to project on output frame */
418                                 0,
419                                 asset->width,
420                                 asset->height,
421                                 temp->get_color_model(),
422                                 frame->get_color_model(),
423                                 0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
424                                 temp->get_w(),       /* For planar use the luma rowspan */
425                                 frame->get_w());
426                 }
427         }
428
429
430 // printf("FileList::read_frame %d %d\n", __LINE__, result);
431 //
432 // if(frame->get_y())
433 // for(int i = 0; i < 100000; i++)
434 // {
435 //      frame->get_y()[i] = 0xff;
436 // }
437 // if(frame->get_rows())
438 // for(int i = 0; i < 100000; i++)
439 // {
440 //      frame->get_rows()[0][i] = 0xff;
441 // }
442
443
444         return result;
445 }
446
447 int FileList::write_frames(VFrame ***frames, int len)
448 {
449         return_value = 0;
450
451 //printf("FileList::write_frames 1\n");
452         if(frames[0][0]->get_color_model() == BC_COMPRESSED)
453         {
454                 for(int i = 0; i < asset->layers && !return_value; i++)
455                 {
456                         for(int j = 0; j < len && !return_value; j++)
457                         {
458                                 VFrame *frame = frames[i][j];
459                                 char *path = create_path(frame->get_number());
460 //printf("FileList::write_frames %d %jd\n", __LINE__, frame->get_number());
461
462
463                                 FILE *fd = fopen(path, "wb");
464                                 if(fd)
465                                 {
466                                         return_value = !fwrite(frames[i][j]->get_data(),
467                                                 frames[i][j]->get_compressed_size(),
468                                                 1,
469                                                 fd);
470
471                                         fclose(fd);
472                                 }
473                                 else
474                                 {
475                                         eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
476                                         return_value++;
477                                 }
478                         }
479                 }
480         }
481         else
482         {
483 //printf("FileList::write_frames 2\n");
484                 writer->write_frames(frames, len);
485 //printf("FileList::write_frames 100\n");
486         }
487         return return_value;
488 }
489
490
491
492
493
494
495
496
497
498 void FileList::add_return_value(int amount)
499 {
500         table_lock->lock("FileList::add_return_value");
501         return_value += amount;
502         table_lock->unlock();
503 }
504
505 char* FileList::calculate_path(int number, char *string)
506 {
507 // Synthesize filename.
508 // If a header is used, the filename number must be in a different location.
509         if(asset->use_header)
510         {
511                 int k;
512                 strcpy(string, asset->path);
513                 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
514                         ;
515                 if(k <= 0) k = strlen(string);
516
517                 sprintf(&string[k], "%06d%s",
518                         number,
519                         file_extension);
520         }
521         else
522 // Without a header, the original filename can be altered.
523         {
524                 Render::create_filename(string,
525                         asset->path,
526                         number,
527                         number_digits,
528                         number_start);
529         }
530
531         return string;
532 }
533
534 char* FileList::create_path(int number_override)
535 {
536         if(asset->format != list_type) return asset->path;
537
538         table_lock->lock("FileList::create_path");
539
540
541
542         char *path = 0;
543         char output[BCTEXTLEN];
544         if(file->current_frame >= path_list.total || !asset->use_header)
545         {
546                 int number;
547                 if(number_override < 0)
548                         number = file->current_frame++;
549                 else
550                 {
551                         number = number_override;
552                         file->current_frame++;
553                 }
554
555                 if(!asset->use_header)
556                 {
557                         number += first_number;
558                 }
559
560                 calculate_path(number, output);
561
562                 path = new char[strlen(output) + 1];
563                 strcpy(path, output);
564                 path_list.append(path);
565         }
566         else
567         {
568 // Overwrite an old path
569                 path = path_list.values[file->current_frame];
570         }
571
572
573         table_lock->unlock();
574
575         return path;
576 }
577
578 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
579 {
580         return new FrameWriterUnit(writer);
581 }
582
583 int64_t FileList::get_memory_usage()
584 {
585         int64_t result = 0;
586         if(data) result += data->get_compressed_allocated();
587         if(temp) result += temp->get_data_size();
588 // printf("FileList::get_memory_usage %d %p %s %jd\n",
589 // __LINE__,
590 // this,
591 // file->asset->path,
592 // result);
593         return result;
594 }
595
596 int FileList::get_units()
597 {
598         return !writer ? 0 : writer->get_total_clients();
599 }
600
601 FrameWriterUnit* FileList::get_unit(int number)
602 {
603         return !writer ? 0 : (FrameWriterUnit*)writer->get_client(number);
604 }
605
606 int FileList::use_path()
607 {
608         return 0;
609 }
610
611
612
613
614
615
616 FrameWriterPackage::FrameWriterPackage()
617 {
618 }
619
620 FrameWriterPackage::~FrameWriterPackage()
621 {
622 }
623
624
625
626
627
628
629
630
631
632
633
634 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
635  : LoadClient(server)
636 {
637 // Don't use server here since subclasses call this with no server.
638         this->server = server;
639         output = new VFrame;
640 }
641
642 FrameWriterUnit::~FrameWriterUnit()
643 {
644         delete output;
645 }
646
647 void FrameWriterUnit::process_package(LoadPackage *package)
648 {
649 //printf("FrameWriterUnit::process_package 1\n");
650         FrameWriterPackage *ptr = (FrameWriterPackage*)package;
651
652         FILE *file;
653
654 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
655         if(!(file = fopen(ptr->path, "wb")))
656         {
657                 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), ptr->path);
658                 return;
659         }
660 //printf("FrameWriterUnit::process_package 3");
661
662
663         int result = server->file->write_frame(ptr->input, output, this);
664
665 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
666         if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
667 //TRACE("FrameWriterUnit::process_package 4");
668         fclose(file);
669 //TRACE("FrameWriterUnit::process_package 5");
670
671         server->file->add_return_value(result);
672 //TRACE("FrameWriterUnit::process_package 6");
673 }
674
675
676
677
678
679
680
681
682
683
684
685 FrameWriter::FrameWriter(FileList *file, int cpus)
686  : LoadServer(cpus, 0)
687 {
688         this->file = file;
689 }
690
691
692 FrameWriter::~FrameWriter()
693 {
694 }
695
696 void FrameWriter::init_packages()
697 {
698         for(int i = 0, layer = 0, number = 0;
699                 i < get_total_packages();
700                 i++)
701         {
702                 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
703                 package->input = frames[layer][number];
704                 package->path = file->create_path(package->input->get_number());
705 // printf("FrameWriter::init_packages 1 %p %d %s\n",
706 // package->input,
707 // package->input->get_number(),
708 // package->path);
709                 number++;
710                 if(number >= len)
711                 {
712                         layer++;
713                         number = 0;
714                 }
715         }
716 }
717
718 void FrameWriter::write_frames(VFrame ***frames, int len)
719 {
720         this->frames = frames;
721         this->len = len;
722         set_package_count(len * file->asset->layers);
723
724         process_packages();
725 }
726
727 LoadClient* FrameWriter::new_client()
728 {
729         return file->new_writer_unit(this);
730 }
731
732 LoadPackage* FrameWriter::new_package()
733 {
734         return new FrameWriterPackage;
735 }
736
737
738