r1014: Enable horizontal scrolling with the mouse wheel by pressing Ctrl.
[cinelerra_cv/ct.git] / cinelerra / filelist.C
blob1f8a3a25dd146f92530305bc5370ef491b65e19a
1 #include "asset.h"
2 #include "bcsignals.h"
3 #include "file.h"
4 #include "filelist.h"
5 #include "guicast.h"
6 #include "interlacemodes.h"
7 #include "mutex.h"
8 #include "mwindow.inc"
9 #include "render.h"
10 #include "renderfarmfsserver.inc"
11 #include "vframe.h"
12 #include "mainerror.h"
14 #include <ctype.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
22 FileList::FileList(Asset *asset, 
23         File *file, 
24         char *list_prefix,
25         char *file_extension, 
26         int frame_type,
27         int list_type)
28  : FileBase(asset, file)
30         reset_parameters();
31         asset->video_data = 1;
32         this->list_prefix = list_prefix;
33         this->file_extension = file_extension;
34         this->frame_type = frame_type;
35         this->list_type = list_type;
36         table_lock = new Mutex("FileList::table_lock");
39 FileList::~FileList()
41         close_file();
42         delete table_lock;
45 int FileList::reset_parameters_derived()
47         data = 0;
48         writer = 0;
49         temp = 0;
50         first_number = 0;
53 int FileList::open_file(int rd, int wr)
55         this->rd = rd;
56         this->wr = wr;
57         int result = 0;
59 // skip header for write
60         if(wr)
61         {
62 // Frame files are created in write_frame and list index is created when
63 // file is closed.
64 // Look for the starting number in the path but ignore the starting character
65 // and total digits since these are used by the header.
66                 Render::get_starting_number(asset->path, 
67                         first_number,
68                         number_start, 
69                         number_digits);
70                 path_list.remove_all_objects();
71                 writer = new FrameWriter(this, 
72                         asset->format == list_type ? file->cpus : 1);
73         }
74         else
75         if(rd)
76         {
77 // Determine type of file.
78 // Header isn't used for background rendering, in which case everything known
79 // by the file encoder is known by the decoder.
80 //printf("FileList::open_file 1 %d\n", asset->use_header);
81                 if(asset->use_header)
82                 {
83                         FILE *stream = fopen(asset->path, "rb");
84                         if(stream)
85                         {
86                                 char string[BCTEXTLEN];
87                                 fread(string, strlen(list_prefix), 1, stream);
88                                 fclose(stream);
90                                 if(!strncasecmp(string, list_prefix, strlen(list_prefix)))
91                                 {
93                                         asset->format = list_type;
95 // Open index here or get frame size from file.
96                                         result = read_list_header();
97                                         if(!result) result = read_frame_header(path_list.values[0]);
98                                 }
99                                 else
100                                 {
101 //printf("FileList::open_file 2\n", asset->use_header);
102                                         asset->format = frame_type;
103                                         result = read_frame_header(asset->path);
104                                         asset->layers = 1;
105                                         if(!asset->frame_rate)
106                                                 asset->frame_rate = 1;
107                                         asset->video_length = -1;
108                                 }
109                         }
110                 }
111                 else
112                 {
113                         Render::get_starting_number(asset->path, 
114                                 first_number,
115                                 number_start, 
116                                 number_digits,
117                                 6);
118                 }
119         }
121         file->current_frame = 0;
122 // Compressed data storage
123         data = new VFrame;
125         return result;
129 int FileList::close_file()
131 //      path_list.total, asset->format, list_type, wr);
132         if(asset->format == list_type && path_list.total)
133         {
134                 if(wr && asset->use_header) write_list_header();
135                 path_list.remove_all_objects();
136         }
137         if(data) delete data;
138         if(writer) delete writer;
139         if(temp) delete temp;
140         reset_parameters();
142         FileBase::close_file();
143         return 0;
146 int FileList::write_list_header()
148         FILE *stream = fopen(asset->path, "w");
149 // Use sprintf instead of fprintf for VFS.
150         char string[BCTEXTLEN];
151         sprintf(string, "%s\n", list_prefix);
152         fwrite(string, strlen(string), 1, stream);
153         sprintf(string, "# First line is always %s\n", list_prefix);
154         fwrite(string, strlen(string), 1, stream);
155         sprintf(string, "# Frame rate:\n");
156         fwrite(string, strlen(string), 1, stream);
157         sprintf(string, "%f\n", asset->frame_rate);
158         fwrite(string, strlen(string), 1, stream);
159         sprintf(string, "# Width:\n");
160         fwrite(string, strlen(string), 1, stream);
161         sprintf(string, "%d\n", asset->width);
162         fwrite(string, strlen(string), 1, stream);
163         sprintf(string, "# Height:\n");
164         fwrite(string, strlen(string), 1, stream);
165         sprintf(string, "%d\n", asset->height);
166         fwrite(string, strlen(string), 1, stream);
167         sprintf(string, "# List of image files follows\n");
168         fwrite(string, strlen(string), 1, stream);
170         for(int i = 0; i < path_list.total; i++)
171         {
172 // Fix path for VFS but leave leading slash
173                 if(!strncmp(path_list.values[i], RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
174                         sprintf(string, "%s\n", path_list.values[i] + strlen(RENDERFARM_FS_PREFIX));
175                 else
176                         sprintf(string, "%s\n", path_list.values[i]);
177                 fwrite(string, strlen(string), 1, stream);
178         }
179         fclose(stream);
180         return 0;
183 int FileList::read_list_header()
185         char string[BCTEXTLEN], *new_entry;
187         FILE *stream = fopen(asset->path, "r");
188         
189         
190         if(stream)
191         {
192 // Get information about the frames
193                 do
194                 {
195                         fgets(string, BCTEXTLEN, stream);
196                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' ' || isalpha(string[0])));
198 // Don't want a user configured frame rate to get destroyed
199                 if(asset->frame_rate == 0)
200                         asset->frame_rate = atof(string);
202                 do
203                 {
204                         fgets(string, BCTEXTLEN, stream);
205                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
206                 asset->width = atol(string);
208                 do
209                 {
210                         fgets(string, BCTEXTLEN, stream);
211                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
212                 asset->height = atol(string);
214                 asset->interlace_mode = BC_ILACE_MODE_UNDETECTED;  // May be good to store the info in the list?
215                 asset->layers = 1;
216                 asset->audio_data = 0;
217                 asset->video_data = 1;
219 // Get all the paths
220                 while(!feof(stream))
221                 {
222                         fgets(string, BCTEXTLEN, stream);
223                         if(strlen(string) && string[0] != '#' && string[0] != ' ' && !feof(stream))
224                         {
225                                 string[strlen(string) - 1] = 0;
226                                 path_list.append(new_entry = new char[strlen(string) + 1]);
227                                 strcpy(new_entry, string);
228                         }
229                 }
231 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
232                 fclose(stream);
233                 asset->video_length = path_list.total;
234         }
235         else
236                 return 1;
238         return 0;
241 int FileList::read_frame(VFrame *frame)
243         int result = 0;
244         if(file->current_frame < 0 || 
245                 (asset->use_header && file->current_frame >= path_list.total &&
246                         asset->format == list_type))
247                 return 1;
249         if(asset->format == list_type)
250         {
251                 char string[BCTEXTLEN];
252                 char *path;
253                 if(asset->use_header)
254                 {
255                         path = path_list.values[file->current_frame];
256                 }
257                 else
258                 {
259                         path = calculate_path(file->current_frame, string);
260                 }
261                 FILE *in;
264 // Fix path for VFS
265                 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
266                         sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
267                 else
268                         strcpy(string, path);
270                 if(!(in = fopen(string, "rb")))
271                 {
272                         eprintf("Error while opening \"%s\" for reading. \n%m\n", string);
273                 }
274                 else
275                 {
276                         struct stat ostat;
277                         stat(string, &ostat);
279                         switch(frame->get_color_model())
280                         {
281                                 case BC_COMPRESSED:
282                                         frame->allocate_compressed_data(ostat.st_size);
283                                         frame->set_compressed_size(ostat.st_size);
284                                         fread(frame->get_data(), ostat.st_size, 1, in);
285                                         break;
286                                 default:
287                                         data->allocate_compressed_data(ostat.st_size);
288                                         data->set_compressed_size(ostat.st_size);
289                                         fread(data->get_data(), ostat.st_size, 1, in);
290                                         result = read_frame(frame, data);
291                                         break;
292                         }
295                         fclose(in);
296                 }
297         }
298         else
299         {
300 // Allocate and decompress once into temporary
301 //printf("FileList::read_frame %d\n", frame->get_color_model());
302                 if(!temp || temp->get_color_model() != frame->get_color_model())
303                 {
304                         if(temp) delete temp;
305                         temp = 0;
306                 
307                         FILE *fd = fopen(asset->path, "rb");
308                         if(fd)
309                         {
310                                 struct stat ostat;
311                                 stat(asset->path, &ostat);
313                                 switch(frame->get_color_model())
314                                 {
315                                         case BC_COMPRESSED:
316                                                 frame->allocate_compressed_data(ostat.st_size);
317                                                 frame->set_compressed_size(ostat.st_size);
318                                                 fread(frame->get_data(), ostat.st_size, 1, fd);
319                                                 break;
320                                         default:
321                                                 data->allocate_compressed_data(ostat.st_size);
322                                                 data->set_compressed_size(ostat.st_size);
323                                                 fread(data->get_data(), ostat.st_size, 1, fd);
324                                                 temp = new VFrame(0, 
325                                                         asset->width, 
326                                                         asset->height, 
327                                                         frame->get_color_model());
328                                                 read_frame(temp, data);
329                                                 break;
330                                 }
332                                 fclose(fd);
333                         }
334                         else
335                         {
336                                 eprintf("Error while opening \"%s\" for reading. \n%m\n", asset->path);
337                                 result = 1;
338                         }
339                 }
341                 if(!temp) return result;
343 // printf("FileList::read_frame frame=%d temp=%d\n", 
344 // frame->get_color_model(),
345 // temp->get_color_model());
346                 if(frame->get_color_model() == temp->get_color_model())
347                 {
348                         frame->copy_from(temp);
349                 }
350                 else
351                 {
352 // Never happens
353                         cmodel_transfer(frame->get_rows(), /* Leave NULL if non existent */
354                                 temp->get_rows(),
355                                 frame->get_y(), /* Leave NULL if non existent */
356                                 frame->get_u(),
357                                 frame->get_v(),
358                                 temp->get_y(), /* Leave NULL if non existent */
359                                 temp->get_u(),
360                                 temp->get_v(),
361                                 0,        /* Dimensions to capture from input frame */
362                                 0, 
363                                 asset->width, 
364                                 asset->height,
365                                 0,       /* Dimensions to project on output frame */
366                                 0, 
367                                 asset->width, 
368                                 asset->height,
369                                 temp->get_color_model(), 
370                                 frame->get_color_model(),
371                                 0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
372                                 temp->get_w(),       /* For planar use the luma rowspan */
373                                 frame->get_w());
374                 }
375         }
378 //printf("FileList::read_frame 5 %d\n", result);
381         return result;
384 int FileList::write_frames(VFrame ***frames, int len)
386         return_value = 0;
388 //printf("FileList::write_frames 1\n");
389         if(frames[0][0]->get_color_model() == BC_COMPRESSED)
390         {
391                 for(int i = 0; i < asset->layers && !return_value; i++)
392                 {
393                         for(int j = 0; j < len && !return_value; j++)
394                         {
395                                 VFrame *frame = frames[i][j];
396                                 char *path = create_path(frame->get_number());
398                                 FILE *fd = fopen(path, "wb");
399                                 if(fd)
400                                 {
401                                         return_value = !fwrite(frames[i][j]->get_data(),
402                                                 frames[i][j]->get_compressed_size(),
403                                                 1,
404                                                 fd);
406                                         fclose(fd);
407                                 }
408                                 else
409                                 {
410                                         eprintf("Error while opening \"%s\" for writing. \n%m\n", asset->path);
411                                         return_value++;
412                                 }
413                         }
414                 }
415         }
416         else
417         {
418 //printf("FileList::write_frames 2\n");
419                 writer->write_frames(frames, len);
420 //printf("FileList::write_frames 100\n");
421         }
422         return return_value;
433 void FileList::add_return_value(int amount)
435         table_lock->lock("FileList::add_return_value");
436         return_value += amount;
437         table_lock->unlock();
440 char* FileList::calculate_path(int number, char *string)
442 // Synthesize filename.
443 // If a header is used, the filename number must be in a different location.
444         if(asset->use_header)
445         {
446                 int k;
447                 strcpy(string, asset->path);
448                 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
449                         ;
450                 if(k <= 0) k = strlen(string);
452                 sprintf(&string[k], "%06d%s", 
453                         number, 
454                         file_extension);
455         }
456         else
457 // Without a header, the original filename can be altered.
458         {
459                 Render::create_filename(string, 
460                         asset->path, 
461                         number,
462                         number_digits,
463                         number_start);
464         }
466         return string;
469 char* FileList::create_path(int number_override)
471         if(asset->format != list_type) return asset->path;
473         table_lock->lock("FileList::create_path");
477         char *path = "";
478         char output[BCTEXTLEN];
479         if(file->current_frame >= path_list.total || !asset->use_header)
480         {
481                 int number;
482                 if(number_override < 0)
483                         number = file->current_frame++;
484                 else
485                 {
486                         number = number_override;
487                         file->current_frame++;
488                 }
490                 if(!asset->use_header)
491                 {
492                         number += first_number;
493                 }
495                 calculate_path(number, output);
497                 path = new char[strlen(output) + 1];
498                 strcpy(path, output);
499                 path_list.append(path);
500         }
501         else
502         {
503 // Overwrite an old path
504                 path = path_list.values[file->current_frame];
505         }
508         table_lock->unlock();
509         
510         return path;
513 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
515         return new FrameWriterUnit(writer);
518 int64_t FileList::get_memory_usage()
520         int64_t result = 0;
521         if(data) result += data->get_compressed_allocated();
522         if(temp) result += temp->get_data_size();
523         return result;
526 int FileList::get_units()
528         if(writer) return writer->get_total_clients();
529         return 0;
532 FrameWriterUnit* FileList::get_unit(int number)
534         if(writer) return (FrameWriterUnit*)writer->get_client(number);
543 FrameWriterPackage::FrameWriterPackage()
547 FrameWriterPackage::~FrameWriterPackage()
561 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
562  : LoadClient(server)
564 // Don't use server here since subclasses call this with no server.
565         this->server = server;
566         output = new VFrame;
569 FrameWriterUnit::~FrameWriterUnit()
571         delete output;
574 void FrameWriterUnit::process_package(LoadPackage *package)
576 //printf("FrameWriterUnit::process_package 1\n");
577         FrameWriterPackage *ptr = (FrameWriterPackage*)package;
579         FILE *file;
581 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
582         if(!(file = fopen(ptr->path, "wb")))
583         {
584                 eprintf("Error while opening \"%s\" for writing. \n%m\n", ptr->path);
585                 return;
586         }
587 //printf("FrameWriterUnit::process_package 3");
590         int result = server->file->write_frame(ptr->input, output, this);
591         
592 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
593         if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
594 //TRACE("FrameWriterUnit::process_package 4");
595         fclose(file);
596 //TRACE("FrameWriterUnit::process_package 5");
598         server->file->add_return_value(result);
599 //TRACE("FrameWriterUnit::process_package 6");
612 FrameWriter::FrameWriter(FileList *file, int cpus)
613  : LoadServer(cpus, 0)
615         this->file = file;
619 FrameWriter::~FrameWriter()
623 void FrameWriter::init_packages()
625         for(int i = 0, layer = 0, number = 0; 
626                 i < get_total_packages(); 
627                 i++)
628         {
629                 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
630                 package->input = frames[layer][number];
631                 package->path = file->create_path(package->input->get_number());
632 // printf("FrameWriter::init_packages 1 %p %d %s\n", 
633 // package->input,
634 // package->input->get_number(), 
635 // package->path);
636                 number++;
637                 if(number >= len)
638                 {
639                         layer++;
640                         number = 0;
641                 }
642         }
645 void FrameWriter::write_frames(VFrame ***frames, int len)
647         this->frames = frames;
648         this->len = len;
649         set_package_count(len * file->asset->layers);
650         
651         process_packages();
654 LoadClient* FrameWriter::new_client()
656         return file->new_writer_unit(this);
659 LoadPackage* FrameWriter::new_package()
661         return new FrameWriterPackage;