r827: Fix a crash when no audio output device can be opened.
[cinelerra_cv.git] / cinelerra / filelist.C
blob6fff989536b6a578f31056dc5f6f6f3fb8ac7dbf
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 "mwindow.inc"
8 #include "render.h"
9 #include "renderfarmfsserver.inc"
10 #include "vframe.h"
12 #include <ctype.h>
13 #include <errno.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/stat.h>
19 FileList::FileList(Asset *asset, 
20         File *file, 
21         char *list_prefix,
22         char *file_extension, 
23         int frame_type,
24         int list_type)
25  : FileBase(asset, file)
27         reset_parameters();
28         asset->video_data = 1;
29         this->list_prefix = list_prefix;
30         this->file_extension = file_extension;
31         this->frame_type = frame_type;
32         this->list_type = list_type;
33         table_lock = new Mutex("FileList::table_lock");
36 FileList::~FileList()
38         close_file();
39         delete table_lock;
42 int FileList::reset_parameters_derived()
44         data = 0;
45         writer = 0;
46         temp = 0;
47         first_number = 0;
50 int FileList::open_file(int rd, int wr)
52         this->rd = rd;
53         this->wr = wr;
54         int result = 0;
56 // skip header for write
57         if(wr)
58         {
59 // Frame files are created in write_frame and list index is created when
60 // file is closed.
61 // Look for the starting number in the path but ignore the starting character
62 // and total digits since these are used by the header.
63                 Render::get_starting_number(asset->path, 
64                         first_number,
65                         number_start, 
66                         number_digits);
67                 path_list.remove_all_objects();
68                 writer = new FrameWriter(this, 
69                         asset->format == list_type ? file->cpus : 1);
70         }
71         else
72         if(rd)
73         {
74 // Determine type of file.
75 // Header isn't used for background rendering, in which case everything known
76 // by the file encoder is known by the decoder.
77 //printf("FileList::open_file 1 %d\n", asset->use_header);
78                 if(asset->use_header)
79                 {
80                         FILE *stream = fopen(asset->path, "rb");
81                         if(stream)
82                         {
83                                 char string[BCTEXTLEN];
84                                 fread(string, strlen(list_prefix), 1, stream);
85                                 fclose(stream);
87                                 if(!strncasecmp(string, list_prefix, strlen(list_prefix)))
88                                 {
90                                         asset->format = list_type;
92 // Open index here or get frame size from file.
93                                         result = read_list_header();
94                                         if(!result) result = read_frame_header(path_list.values[0]);
95                                 }
96                                 else
97                                 {
98 //printf("FileList::open_file 2\n", asset->use_header);
99                                         asset->format = frame_type;
100                                         result = read_frame_header(asset->path);
101                                         asset->layers = 1;
102                                         if(!asset->frame_rate)
103                                                 asset->frame_rate = 1;
104                                         asset->video_length = -1;
105                                 }
106                         }
107                 }
108                 else
109                 {
110                         Render::get_starting_number(asset->path, 
111                                 first_number,
112                                 number_start, 
113                                 number_digits,
114                                 6);
115                 }
116         }
118         file->current_frame = 0;
119 // Compressed data storage
120         data = new VFrame;
122         return result;
126 int FileList::close_file()
128 //      path_list.total, asset->format, list_type, wr);
129         if(asset->format == list_type && path_list.total)
130         {
131                 if(wr && asset->use_header) write_list_header();
132                 path_list.remove_all_objects();
133         }
134         if(data) delete data;
135         if(writer) delete writer;
136         if(temp) delete temp;
137         reset_parameters();
139         FileBase::close_file();
140         return 0;
143 int FileList::write_list_header()
145         FILE *stream = fopen(asset->path, "w");
146 // Use sprintf instead of fprintf for VFS.
147         char string[BCTEXTLEN];
148         sprintf(string, "%s\n", list_prefix);
149         fwrite(string, strlen(string), 1, stream);
150         sprintf(string, "# First line is always %s\n", list_prefix);
151         fwrite(string, strlen(string), 1, stream);
152         sprintf(string, "# Frame rate:\n");
153         fwrite(string, strlen(string), 1, stream);
154         sprintf(string, "%f\n", asset->frame_rate);
155         fwrite(string, strlen(string), 1, stream);
156         sprintf(string, "# Width:\n");
157         fwrite(string, strlen(string), 1, stream);
158         sprintf(string, "%d\n", asset->width);
159         fwrite(string, strlen(string), 1, stream);
160         sprintf(string, "# Height:\n");
161         fwrite(string, strlen(string), 1, stream);
162         sprintf(string, "%d\n", asset->height);
163         fwrite(string, strlen(string), 1, stream);
164         sprintf(string, "# List of image files follows\n");
165         fwrite(string, strlen(string), 1, stream);
167         for(int i = 0; i < path_list.total; i++)
168         {
169 // Fix path for VFS but leave leading slash
170                 if(!strncmp(path_list.values[i], RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
171                         sprintf(string, "%s\n", path_list.values[i] + strlen(RENDERFARM_FS_PREFIX));
172                 else
173                         sprintf(string, "%s\n", path_list.values[i]);
174                 fwrite(string, strlen(string), 1, stream);
175         }
176         fclose(stream);
177         return 0;
180 int FileList::read_list_header()
182         char string[BCTEXTLEN], *new_entry;
184         FILE *stream = fopen(asset->path, "r");
185         
186         
187         if(stream)
188         {
189 // Get information about the frames
190                 do
191                 {
192                         fgets(string, BCTEXTLEN, stream);
193                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' ' || isalpha(string[0])));
195 // Don't want a user configured frame rate to get destroyed
196                 if(asset->frame_rate == 0)
197                         asset->frame_rate = atof(string);
199                 do
200                 {
201                         fgets(string, BCTEXTLEN, stream);
202                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
203                 asset->width = atol(string);
205                 do
206                 {
207                         fgets(string, BCTEXTLEN, stream);
208                 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
209                 asset->height = atol(string);
211                 asset->interlace_mode = BC_ILACE_MODE_UNDETECTED;  // May be good to store the info in the list?
212                 asset->layers = 1;
213                 asset->audio_data = 0;
214                 asset->video_data = 1;
216 // Get all the paths
217                 while(!feof(stream))
218                 {
219                         fgets(string, BCTEXTLEN, stream);
220                         if(strlen(string) && string[0] != '#' && string[0] != ' ' && !feof(stream))
221                         {
222                                 string[strlen(string) - 1] = 0;
223                                 path_list.append(new_entry = new char[strlen(string) + 1]);
224                                 strcpy(new_entry, string);
225                         }
226                 }
228 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
229                 fclose(stream);
230                 asset->video_length = path_list.total;
231         }
232         else
233                 return 1;
235         return 0;
238 int FileList::read_frame(VFrame *frame)
240         int result = 0;
241         if(file->current_frame < 0 || 
242                 (asset->use_header && file->current_frame >= path_list.total &&
243                         asset->format == list_type))
244                 return 1;
246         if(asset->format == list_type)
247         {
248                 char string[BCTEXTLEN];
249                 char *path;
250                 if(asset->use_header)
251                 {
252                         path = path_list.values[file->current_frame];
253                 }
254                 else
255                 {
256                         path = calculate_path(file->current_frame, string);
257                 }
258                 FILE *in;
261 // Fix path for VFS
262                 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
263                         sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
264                 else
265                         strcpy(string, path);
267                 if(!(in = fopen(string, "rb")))
268                 {
269                         fprintf(stderr, "FileList::read_frame %s: %s\n", string, strerror(errno));
270                 }
271                 else
272                 {
273                         struct stat ostat;
274                         stat(string, &ostat);
276                         switch(frame->get_color_model())
277                         {
278                                 case BC_COMPRESSED:
279                                         frame->allocate_compressed_data(ostat.st_size);
280                                         frame->set_compressed_size(ostat.st_size);
281                                         fread(frame->get_data(), ostat.st_size, 1, in);
282                                         break;
283                                 default:
284                                         data->allocate_compressed_data(ostat.st_size);
285                                         data->set_compressed_size(ostat.st_size);
286                                         fread(data->get_data(), ostat.st_size, 1, in);
287                                         result = read_frame(frame, data);
288                                         break;
289                         }
292                         fclose(in);
293                 }
294         }
295         else
296         {
298 // Allocate and decompress once into temporary
299                 if(!temp || temp->get_color_model() != frame->get_color_model())
300                 {
301                         if(temp) delete temp;
302                         temp = 0;
303                 
304                         FILE *fd = fopen(asset->path, "rb");
305                         if(fd)
306                         {
307                                 struct stat ostat;
308                                 stat(asset->path, &ostat);
310                                 switch(frame->get_color_model())
311                                 {
312                                         case BC_COMPRESSED:
313                                                 frame->allocate_compressed_data(ostat.st_size);
314                                                 frame->set_compressed_size(ostat.st_size);
315                                                 fread(frame->get_data(), ostat.st_size, 1, fd);
316                                                 break;
317                                         default:
318                                                 data->allocate_compressed_data(ostat.st_size);
319                                                 data->set_compressed_size(ostat.st_size);
320                                                 fread(data->get_data(), ostat.st_size, 1, fd);
321                                                 temp = new VFrame(0, 
322                                                         asset->width, 
323                                                         asset->height, 
324                                                         frame->get_color_model());
325                                                 read_frame(temp, data);
326                                                 break;
327                                 }
329                                 fclose(fd);
330                         }
331                         else
332                         {
333                                 fprintf(stderr, "FileList::read_frame %s: %s\n", asset->path, strerror(errno));
334                                 result = 1;
335                         }
336                 }
338                 if(!temp) return result;
340                 if(frame->get_color_model() == temp->get_color_model())
341                 {
342                         frame->copy_from(temp);
343                 }
344                 else
345                 {
346 // Never happens
347                         cmodel_transfer(frame->get_rows(), /* Leave NULL if non existent */
348                                 temp->get_rows(),
349                                 frame->get_y(), /* Leave NULL if non existent */
350                                 frame->get_u(),
351                                 frame->get_v(),
352                                 temp->get_y(), /* Leave NULL if non existent */
353                                 temp->get_u(),
354                                 temp->get_v(),
355                                 0,        /* Dimensions to capture from input frame */
356                                 0, 
357                                 asset->width, 
358                                 asset->height,
359                                 0,       /* Dimensions to project on output frame */
360                                 0, 
361                                 asset->width, 
362                                 asset->height,
363                                 temp->get_color_model(), 
364                                 frame->get_color_model(),
365                                 0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
366                                 temp->get_w(),       /* For planar use the luma rowspan */
367                                 frame->get_w());
368                 }
369         }
372 //printf("FileList::read_frame 5 %d\n", result);
375         return result;
378 int FileList::write_frames(VFrame ***frames, int len)
380         return_value = 0;
382 //printf("FileList::write_frames 1\n");
383         if(frames[0][0]->get_color_model() == BC_COMPRESSED)
384         {
385                 for(int i = 0; i < asset->layers && !return_value; i++)
386                 {
387                         for(int j = 0; j < len && !return_value; j++)
388                         {
389                                 VFrame *frame = frames[i][j];
390                                 char *path = create_path(frame->get_number());
392                                 FILE *fd = fopen(path, "wb");
393                                 if(fd)
394                                 {
395                                         return_value = !fwrite(frames[i][j]->get_data(),
396                                                 frames[i][j]->get_compressed_size(),
397                                                 1,
398                                                 fd);
400                                         fclose(fd);
401                                 }
402                                 else
403                                 {
404                                         printf("FileList::write_frames %s: %s\n", path, strerror(errno));
405                                         return_value++;
406                                 }
407                         }
408                 }
409         }
410         else
411         {
412 //printf("FileList::write_frames 2\n");
413                 writer->write_frames(frames, len);
414 //printf("FileList::write_frames 100\n");
415         }
416         return return_value;
427 void FileList::add_return_value(int amount)
429         table_lock->lock("FileList::add_return_value");
430         return_value += amount;
431         table_lock->unlock();
434 char* FileList::calculate_path(int number, char *string)
436 // Synthesize filename.
437 // If a header is used, the filename number must be in a different location.
438         if(asset->use_header)
439         {
440                 int k;
441                 strcpy(string, asset->path);
442                 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
443                         ;
444                 if(k <= 0) k = strlen(string);
446                 sprintf(&string[k], "%06d%s", 
447                         number, 
448                         file_extension);
449         }
450         else
451 // Without a header, the original filename can be altered.
452         {
453                 Render::create_filename(string, 
454                         asset->path, 
455                         number,
456                         number_digits,
457                         number_start);
458         }
460         return string;
463 char* FileList::create_path(int number_override)
465         if(asset->format != list_type) return asset->path;
467         table_lock->lock("FileList::create_path");
471         char *path = "";
472         char output[BCTEXTLEN];
473         if(file->current_frame >= path_list.total || !asset->use_header)
474         {
475                 int number;
476                 if(number_override < 0)
477                         number = file->current_frame++;
478                 else
479                 {
480                         number = number_override;
481                         file->current_frame++;
482                 }
484                 if(!asset->use_header)
485                 {
486                         number += first_number;
487                 }
489                 calculate_path(number, output);
491                 path = new char[strlen(output) + 1];
492                 strcpy(path, output);
493                 path_list.append(path);
494         }
495         else
496         {
497 // Overwrite an old path
498                 path = path_list.values[file->current_frame];
499         }
502         table_lock->unlock();
503         
504         return path;
507 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
509         return new FrameWriterUnit(writer);
512 int FileList::get_memory_usage()
514         int result = 0;
515         if(data) result += data->get_compressed_allocated();
516         if(temp) result += temp->get_data_size();
517         return result;
520 int FileList::get_units()
522         if(writer) return writer->get_total_clients();
523         return 0;
526 FrameWriterUnit* FileList::get_unit(int number)
528         if(writer) return (FrameWriterUnit*)writer->get_client(number);
537 FrameWriterPackage::FrameWriterPackage()
541 FrameWriterPackage::~FrameWriterPackage()
555 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
556  : LoadClient(server)
558 // Don't use server here since subclasses call this with no server.
559         this->server = server;
560         output = new VFrame;
563 FrameWriterUnit::~FrameWriterUnit()
565         delete output;
568 void FrameWriterUnit::process_package(LoadPackage *package)
570 //printf("FrameWriterUnit::process_package 1\n");
571         FrameWriterPackage *ptr = (FrameWriterPackage*)package;
573         FILE *file;
575 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
576         if(!(file = fopen(ptr->path, "wb")))
577         {
578                 printf("FrameWriterUnit::process_package %s: %s\n",
579                         ptr->path,
580                         strerror(errno));
581                 return;
582         }
583 //printf("FrameWriterUnit::process_package 3");
586         int result = server->file->write_frame(ptr->input, output, this);
587         
588 //printf("FrameWriterUnit::process_package 4");
589         if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
590 //TRACE("FrameWriterUnit::process_package 4");
591         fclose(file);
592 //TRACE("FrameWriterUnit::process_package 5");
594         server->file->add_return_value(result);
595 //TRACE("FrameWriterUnit::process_package 6");
608 FrameWriter::FrameWriter(FileList *file, int cpus)
609  : LoadServer(cpus, 0)
611         this->file = file;
615 FrameWriter::~FrameWriter()
619 void FrameWriter::init_packages()
621         for(int i = 0, layer = 0, number = 0; 
622                 i < get_total_packages(); 
623                 i++)
624         {
625                 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
626                 package->input = frames[layer][number];
627                 package->path = file->create_path(package->input->get_number());
628 // printf("FrameWriter::init_packages 1 %p %d %s\n", 
629 // package->input,
630 // package->input->get_number(), 
631 // package->path);
632                 number++;
633                 if(number >= len)
634                 {
635                         layer++;
636                         number = 0;
637                 }
638         }
641 void FrameWriter::write_frames(VFrame ***frames, int len)
643         this->frames = frames;
644         this->len = len;
645         set_package_count(len * file->asset->layers);
646         
647         process_packages();
650 LoadClient* FrameWriter::new_client()
652         return file->new_writer_unit(this);
655 LoadPackage* FrameWriter::new_package()
657         return new FrameWriterPackage;