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