r903: BC_FileBoxDirectoryText::handle_event - fix for the change in meaning of is_di...
[cinelerra_cv/mob.git] / cinelerra / filelist.C
blobc507b6513705470cb48f6c64b514391886b0e769
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"
13 #include <ctype.h>
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
21 FileList::FileList(Asset *asset, 
22         File *file, 
23         char *list_prefix,
24         char *file_extension, 
25         int frame_type,
26         int list_type)
27  : FileBase(asset, file)
29         reset_parameters();
30         asset->video_data = 1;
31         this->list_prefix = list_prefix;
32         this->file_extension = file_extension;
33         this->frame_type = frame_type;
34         this->list_type = list_type;
35         table_lock = new Mutex("FileList::table_lock");
38 FileList::~FileList()
40         close_file();
41         delete table_lock;
44 int FileList::reset_parameters_derived()
46         data = 0;
47         writer = 0;
48         temp = 0;
49         first_number = 0;
52 int FileList::open_file(int rd, int wr)
54         this->rd = rd;
55         this->wr = wr;
56         int result = 0;
58 // skip header for write
59         if(wr)
60         {
61 // Frame files are created in write_frame and list index is created when
62 // file is closed.
63 // Look for the starting number in the path but ignore the starting character
64 // and total digits since these are used by the header.
65                 Render::get_starting_number(asset->path, 
66                         first_number,
67                         number_start, 
68                         number_digits);
69                 path_list.remove_all_objects();
70                 writer = new FrameWriter(this, 
71                         asset->format == list_type ? file->cpus : 1);
72         }
73         else
74         if(rd)
75         {
76 // Determine type of file.
77 // Header isn't used for background rendering, in which case everything known
78 // by the file encoder is known by the decoder.
79 //printf("FileList::open_file 1 %d\n", asset->use_header);
80                 if(asset->use_header)
81                 {
82                         FILE *stream = fopen(asset->path, "rb");
83                         if(stream)
84                         {
85                                 char string[BCTEXTLEN];
86                                 fread(string, strlen(list_prefix), 1, stream);
87                                 fclose(stream);
89                                 if(!strncasecmp(string, list_prefix, strlen(list_prefix)))
90                                 {
92                                         asset->format = list_type;
94 // Open index here or get frame size from file.
95                                         result = read_list_header();
96                                         if(!result) result = read_frame_header(path_list.values[0]);
97                                 }
98                                 else
99                                 {
100 //printf("FileList::open_file 2\n", asset->use_header);
101                                         asset->format = frame_type;
102                                         result = read_frame_header(asset->path);
103                                         asset->layers = 1;
104                                         if(!asset->frame_rate)
105                                                 asset->frame_rate = 1;
106                                         asset->video_length = -1;
107                                 }
108                         }
109                 }
110                 else
111                 {
112                         Render::get_starting_number(asset->path, 
113                                 first_number,
114                                 number_start, 
115                                 number_digits,
116                                 6);
117                 }
118         }
120         file->current_frame = 0;
121 // Compressed data storage
122         data = new VFrame;
124         return result;
128 int FileList::close_file()
130 //      path_list.total, asset->format, list_type, wr);
131         if(asset->format == list_type && path_list.total)
132         {
133                 if(wr && asset->use_header) write_list_header();
134                 path_list.remove_all_objects();
135         }
136         if(data) delete data;
137         if(writer) delete writer;
138         if(temp) delete temp;
139         reset_parameters();
141         FileBase::close_file();
142         return 0;
145 int FileList::write_list_header()
147         FILE *stream = fopen(asset->path, "w");
148 // Use sprintf instead of fprintf for VFS.
149         char string[BCTEXTLEN];
150         sprintf(string, "%s\n", list_prefix);
151         fwrite(string, strlen(string), 1, stream);
152         sprintf(string, "# First line is always %s\n", list_prefix);
153         fwrite(string, strlen(string), 1, stream);
154         sprintf(string, "# Frame rate:\n");
155         fwrite(string, strlen(string), 1, stream);
156         sprintf(string, "%f\n", asset->frame_rate);
157         fwrite(string, strlen(string), 1, stream);
158         sprintf(string, "# Width:\n");
159         fwrite(string, strlen(string), 1, stream);
160         sprintf(string, "%d\n", asset->width);
161         fwrite(string, strlen(string), 1, stream);
162         sprintf(string, "# Height:\n");
163         fwrite(string, strlen(string), 1, stream);
164         sprintf(string, "%d\n", asset->height);
165         fwrite(string, strlen(string), 1, stream);
166         sprintf(string, "# List of image files follows\n");
167         fwrite(string, strlen(string), 1, stream);
169         for(int i = 0; i < path_list.total; i++)
170         {
171 // Fix path for VFS but leave leading slash
172                 if(!strncmp(path_list.values[i], RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
173                         sprintf(string, "%s\n", path_list.values[i] + strlen(RENDERFARM_FS_PREFIX));
174                 else
175                         sprintf(string, "%s\n", path_list.values[i]);
176                 fwrite(string, strlen(string), 1, stream);
177         }
178         fclose(stream);
179         return 0;
182 int FileList::read_list_header()
184         char string[BCTEXTLEN], *new_entry;
186         FILE *stream = fopen(asset->path, "r");
187         
188         
189         if(stream)
190         {
191 // Get information about the frames
192                 do
193                 {
194                         fgets(string, BCTEXTLEN, stream);
195                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' ' || isalpha(string[0])));
197 // Don't want a user configured frame rate to get destroyed
198                 if(asset->frame_rate == 0)
199                         asset->frame_rate = atof(string);
201                 do
202                 {
203                         fgets(string, BCTEXTLEN, stream);
204                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
205                 asset->width = atol(string);
207                 do
208                 {
209                         fgets(string, BCTEXTLEN, stream);
210                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
211                 asset->height = atol(string);
213                 asset->interlace_mode = BC_ILACE_MODE_UNDETECTED;  // May be good to store the info in the list?
214                 asset->layers = 1;
215                 asset->audio_data = 0;
216                 asset->video_data = 1;
218 // Get all the paths
219                 while(!feof(stream))
220                 {
221                         fgets(string, BCTEXTLEN, stream);
222                         if(strlen(string) && string[0] != '#' && string[0] != ' ' && !feof(stream))
223                         {
224                                 string[strlen(string) - 1] = 0;
225                                 path_list.append(new_entry = new char[strlen(string) + 1]);
226                                 strcpy(new_entry, string);
227                         }
228                 }
230 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
231                 fclose(stream);
232                 asset->video_length = path_list.total;
233         }
234         else
235                 return 1;
237         return 0;
240 int FileList::read_frame(VFrame *frame)
242         int result = 0;
243         if(file->current_frame < 0 || 
244                 (asset->use_header && file->current_frame >= path_list.total &&
245                         asset->format == list_type))
246                 return 1;
248         if(asset->format == list_type)
249         {
250                 char string[BCTEXTLEN];
251                 char *path;
252                 if(asset->use_header)
253                 {
254                         path = path_list.values[file->current_frame];
255                 }
256                 else
257                 {
258                         path = calculate_path(file->current_frame, string);
259                 }
260                 FILE *in;
263 // Fix path for VFS
264                 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
265                         sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
266                 else
267                         strcpy(string, path);
269                 if(!(in = fopen(string, "rb")))
270                 {
271                         fprintf(stderr, "FileList::read_frame %s: %s\n", string, strerror(errno));
272                 }
273                 else
274                 {
275                         struct stat ostat;
276                         stat(string, &ostat);
278                         switch(frame->get_color_model())
279                         {
280                                 case BC_COMPRESSED:
281                                         frame->allocate_compressed_data(ostat.st_size);
282                                         frame->set_compressed_size(ostat.st_size);
283                                         fread(frame->get_data(), ostat.st_size, 1, in);
284                                         break;
285                                 default:
286                                         data->allocate_compressed_data(ostat.st_size);
287                                         data->set_compressed_size(ostat.st_size);
288                                         fread(data->get_data(), ostat.st_size, 1, in);
289                                         result = read_frame(frame, data);
290                                         break;
291                         }
294                         fclose(in);
295                 }
296         }
297         else
298         {
299 // Allocate and decompress once into temporary
300 //printf("FileList::read_frame %d\n", frame->get_color_model());
301                 if(!temp || temp->get_color_model() != frame->get_color_model())
302                 {
303                         if(temp) delete temp;
304                         temp = 0;
305                 
306                         FILE *fd = fopen(asset->path, "rb");
307                         if(fd)
308                         {
309                                 struct stat ostat;
310                                 stat(asset->path, &ostat);
312                                 switch(frame->get_color_model())
313                                 {
314                                         case BC_COMPRESSED:
315                                                 frame->allocate_compressed_data(ostat.st_size);
316                                                 frame->set_compressed_size(ostat.st_size);
317                                                 fread(frame->get_data(), ostat.st_size, 1, fd);
318                                                 break;
319                                         default:
320                                                 data->allocate_compressed_data(ostat.st_size);
321                                                 data->set_compressed_size(ostat.st_size);
322                                                 fread(data->get_data(), ostat.st_size, 1, fd);
323                                                 temp = new VFrame(0, 
324                                                         asset->width, 
325                                                         asset->height, 
326                                                         frame->get_color_model());
327                                                 read_frame(temp, data);
328                                                 break;
329                                 }
331                                 fclose(fd);
332                         }
333                         else
334                         {
335                                 fprintf(stderr, "FileList::read_frame %s: %s\n", asset->path, strerror(errno));
336                                 result = 1;
337                         }
338                 }
340                 if(!temp) return result;
342 // printf("FileList::read_frame frame=%d temp=%d\n", 
343 // frame->get_color_model(),
344 // temp->get_color_model());
345                 if(frame->get_color_model() == temp->get_color_model())
346                 {
347                         frame->copy_from(temp);
348                 }
349                 else
350                 {
351 // Never happens
352                         cmodel_transfer(frame->get_rows(), /* Leave NULL if non existent */
353                                 temp->get_rows(),
354                                 frame->get_y(), /* Leave NULL if non existent */
355                                 frame->get_u(),
356                                 frame->get_v(),
357                                 temp->get_y(), /* Leave NULL if non existent */
358                                 temp->get_u(),
359                                 temp->get_v(),
360                                 0,        /* Dimensions to capture from input frame */
361                                 0, 
362                                 asset->width, 
363                                 asset->height,
364                                 0,       /* Dimensions to project on output frame */
365                                 0, 
366                                 asset->width, 
367                                 asset->height,
368                                 temp->get_color_model(), 
369                                 frame->get_color_model(),
370                                 0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
371                                 temp->get_w(),       /* For planar use the luma rowspan */
372                                 frame->get_w());
373                 }
374         }
377 //printf("FileList::read_frame 5 %d\n", result);
380         return result;
383 int FileList::write_frames(VFrame ***frames, int len)
385         return_value = 0;
387 //printf("FileList::write_frames 1\n");
388         if(frames[0][0]->get_color_model() == BC_COMPRESSED)
389         {
390                 for(int i = 0; i < asset->layers && !return_value; i++)
391                 {
392                         for(int j = 0; j < len && !return_value; j++)
393                         {
394                                 VFrame *frame = frames[i][j];
395                                 char *path = create_path(frame->get_number());
397                                 FILE *fd = fopen(path, "wb");
398                                 if(fd)
399                                 {
400                                         return_value = !fwrite(frames[i][j]->get_data(),
401                                                 frames[i][j]->get_compressed_size(),
402                                                 1,
403                                                 fd);
405                                         fclose(fd);
406                                 }
407                                 else
408                                 {
409                                         printf("FileList::write_frames %s: %s\n", path, strerror(errno));
410                                         return_value++;
411                                 }
412                         }
413                 }
414         }
415         else
416         {
417 //printf("FileList::write_frames 2\n");
418                 writer->write_frames(frames, len);
419 //printf("FileList::write_frames 100\n");
420         }
421         return return_value;
432 void FileList::add_return_value(int amount)
434         table_lock->lock("FileList::add_return_value");
435         return_value += amount;
436         table_lock->unlock();
439 char* FileList::calculate_path(int number, char *string)
441 // Synthesize filename.
442 // If a header is used, the filename number must be in a different location.
443         if(asset->use_header)
444         {
445                 int k;
446                 strcpy(string, asset->path);
447                 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
448                         ;
449                 if(k <= 0) k = strlen(string);
451                 sprintf(&string[k], "%06d%s", 
452                         number, 
453                         file_extension);
454         }
455         else
456 // Without a header, the original filename can be altered.
457         {
458                 Render::create_filename(string, 
459                         asset->path, 
460                         number,
461                         number_digits,
462                         number_start);
463         }
465         return string;
468 char* FileList::create_path(int number_override)
470         if(asset->format != list_type) return asset->path;
472         table_lock->lock("FileList::create_path");
476         char *path = "";
477         char output[BCTEXTLEN];
478         if(file->current_frame >= path_list.total || !asset->use_header)
479         {
480                 int number;
481                 if(number_override < 0)
482                         number = file->current_frame++;
483                 else
484                 {
485                         number = number_override;
486                         file->current_frame++;
487                 }
489                 if(!asset->use_header)
490                 {
491                         number += first_number;
492                 }
494                 calculate_path(number, output);
496                 path = new char[strlen(output) + 1];
497                 strcpy(path, output);
498                 path_list.append(path);
499         }
500         else
501         {
502 // Overwrite an old path
503                 path = path_list.values[file->current_frame];
504         }
507         table_lock->unlock();
508         
509         return path;
512 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
514         return new FrameWriterUnit(writer);
517 int64_t FileList::get_memory_usage()
519         int64_t result = 0;
520         if(data) result += data->get_compressed_allocated();
521         if(temp) result += temp->get_data_size();
522         return result;
525 int FileList::get_units()
527         if(writer) return writer->get_total_clients();
528         return 0;
531 FrameWriterUnit* FileList::get_unit(int number)
533         if(writer) return (FrameWriterUnit*)writer->get_client(number);
542 FrameWriterPackage::FrameWriterPackage()
546 FrameWriterPackage::~FrameWriterPackage()
560 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
561  : LoadClient(server)
563 // Don't use server here since subclasses call this with no server.
564         this->server = server;
565         output = new VFrame;
568 FrameWriterUnit::~FrameWriterUnit()
570         delete output;
573 void FrameWriterUnit::process_package(LoadPackage *package)
575 //printf("FrameWriterUnit::process_package 1\n");
576         FrameWriterPackage *ptr = (FrameWriterPackage*)package;
578         FILE *file;
580 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
581         if(!(file = fopen(ptr->path, "wb")))
582         {
583                 printf("FrameWriterUnit::process_package %s: %s\n",
584                         ptr->path,
585                         strerror(errno));
586                 return;
587         }
588 //printf("FrameWriterUnit::process_package 3");
591         int result = server->file->write_frame(ptr->input, output, this);
592         
593 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
594         if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
595 //TRACE("FrameWriterUnit::process_package 4");
596         fclose(file);
597 //TRACE("FrameWriterUnit::process_package 5");
599         server->file->add_return_value(result);
600 //TRACE("FrameWriterUnit::process_package 6");
613 FrameWriter::FrameWriter(FileList *file, int cpus)
614  : LoadServer(cpus, 0)
616         this->file = file;
620 FrameWriter::~FrameWriter()
624 void FrameWriter::init_packages()
626         for(int i = 0, layer = 0, number = 0; 
627                 i < get_total_packages(); 
628                 i++)
629         {
630                 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
631                 package->input = frames[layer][number];
632                 package->path = file->create_path(package->input->get_number());
633 // printf("FrameWriter::init_packages 1 %p %d %s\n", 
634 // package->input,
635 // package->input->get_number(), 
636 // package->path);
637                 number++;
638                 if(number >= len)
639                 {
640                         layer++;
641                         number = 0;
642                 }
643         }
646 void FrameWriter::write_frames(VFrame ***frames, int len)
648         this->frames = frames;
649         this->len = len;
650         set_package_count(len * file->asset->layers);
651         
652         process_packages();
655 LoadClient* FrameWriter::new_client()
657         return file->new_writer_unit(this);
660 LoadPackage* FrameWriter::new_package()
662         return new FrameWriterPackage;