4 * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 #include "bcsignals.h"
28 #include "interlacemodes.h"
30 #include "mwindow.inc"
32 #include "renderfarmfsserver.inc"
34 #include "mainerror.h"
45 FileList::FileList(Asset *asset,
47 const char *list_prefix,
48 const char *file_extension,
51 : FileBase(asset, file)
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");
69 int FileList::reset_parameters_derived()
78 int FileList::open_file(int rd, int wr)
82 // skip header for write
85 int fd = open(asset->path, O_CREAT+O_TRUNC+O_RDWR, 0777);
89 // Frame files are created in write_frame and list index is created when
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);
100 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
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)
111 FILE *stream = fopen(asset->path, "rb");
112 //printf("FileList::open_file %d asset->path=%s\n", __LINE__, asset->path);
115 char string[BCTEXTLEN];
116 (void)fread(string, strlen(list_prefix), 1, stream);
119 if(!strncasecmp(string, list_prefix, strlen(list_prefix)))
122 //printf("FileList::open_file %d\n", __LINE__);
123 asset->format = list_type;
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]);
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);
137 if(!asset->frame_rate)
138 asset->frame_rate = 1;
139 asset->video_length = -1;
144 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
148 Render::get_starting_number(asset->path,
149 first_number, number_start, number_digits, 6);
154 file->current_frame = 0;
155 // Compressed data storage
162 int FileList::close_file()
164 // path_list.total, asset->format, list_type, wr);
165 if(asset->format == list_type && path_list.total)
167 if(file->wr && asset->use_header) write_list_header();
168 path_list.remove_all_objects();
170 if(data) delete data;
171 if(writer) delete writer;
172 if(temp) delete temp;
175 FileBase::close_file();
179 int FileList::write_list_header()
181 FILE *stream = fopen(asset->path, "w");
182 if( !stream ) return 1;
183 // Use sprintf instead of fprintf for VFS.
184 char string[BCTEXTLEN];
185 sprintf(string, "%s\n", list_prefix);
186 fwrite(string, strlen(string), 1, stream);
187 sprintf(string, "# First line is always %s\n", list_prefix);
188 fwrite(string, strlen(string), 1, stream);
189 sprintf(string, "# Frame rate:\n");
190 fwrite(string, strlen(string), 1, stream);
191 sprintf(string, "%f\n", asset->frame_rate);
192 fwrite(string, strlen(string), 1, stream);
193 sprintf(string, "# Width:\n");
194 fwrite(string, strlen(string), 1, stream);
195 sprintf(string, "%d\n", asset->width);
196 fwrite(string, strlen(string), 1, stream);
197 sprintf(string, "# Height:\n");
198 fwrite(string, strlen(string), 1, stream);
199 sprintf(string, "%d\n", asset->height);
200 fwrite(string, strlen(string), 1, stream);
201 sprintf(string, "# List of image files follows\n");
202 fwrite(string, strlen(string), 1, stream);
204 for(int i = 0; i < path_list.total; i++)
206 // Fix path for VFS but leave leading slash
207 if(!strncmp(path_list.values[i], RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
208 sprintf(string, "%s\n", path_list.values[i] + strlen(RENDERFARM_FS_PREFIX));
210 sprintf(string, "%s\n", path_list.values[i]);
211 fwrite(string, strlen(string), 1, stream);
217 int FileList::read_list_header()
219 char string[BCTEXTLEN];
221 FILE *stream = fopen(asset->path, "r");
222 if( !stream ) return 1;
223 // Get information about the frames
225 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
226 } while(string[0] == '#' || string[0] == ' ' || isalpha(string[0]));
228 // Don't want a user configured frame rate to get destroyed
229 if(asset->frame_rate == 0)
230 asset->frame_rate = atof(string);
233 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
234 } while(string[0] == '#' || string[0] == ' ');
235 if( (asset->width = atol(string)) <= 0 ) return 1;
238 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
239 } while(string[0] == '#' || string[0] == ' ');
240 if( (asset->height = atol(string)) <= 0 ) return 1;
242 asset->interlace_mode = ILACE_MODE_UNDETECTED;
244 asset->audio_data = 0;
245 asset->video_data = 1;
249 while(!feof(stream) && fgets(string, BCTEXTLEN, stream) ) {
250 int len = strlen(string);
251 if( !len || string[0] == '#' || string[0] == ' ') continue;
253 if( access(string,R_OK) && !missing++ )
254 eprintf(_("%s:no such file"), string);
255 path_list.append(cstrdup(string));
258 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
260 if( !(asset->video_length = path_list.total) )
261 eprintf(_("%s:\nlist empty"), asset->path);
263 eprintf(_("%s:\n%d files not found"), asset->path, missing);
267 int FileList::read_frame(VFrame *frame)
272 // printf("FileList::read_frame %d %d use_header=%d current_frame=%d total=%d\n",
275 // asset->use_header,
276 // file->current_frame,
279 if(file->current_frame < 0 ||
280 (asset->use_header && file->current_frame >= path_list.total &&
281 asset->format == list_type))
284 if(asset->format == list_type)
286 char string[BCTEXTLEN];
288 if(asset->use_header)
290 path = path_list.values[file->current_frame];
294 path = calculate_path(file->current_frame, string);
299 // Fix path for VFS. Not used anymore.
300 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
301 sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
303 strcpy(string, path);
307 if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
309 if(!(in = fopen(string, "rb"))) {
310 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), string);
315 stat(string, &ostat);
317 switch(frame->get_color_model())
320 frame->allocate_compressed_data(ostat.st_size);
321 frame->set_compressed_size(ostat.st_size);
322 (void)fread(frame->get_data(), ostat.st_size, 1, in);
325 data->allocate_compressed_data(ostat.st_size);
326 data->set_compressed_size(ostat.st_size);
327 (void)fread(data->get_data(), ostat.st_size, 1, in);
328 result = read_frame(frame, data);
337 //printf("FileList::read_frame %d %s\n", __LINE__, string);
338 result = read_frame(frame, string);
343 asset->single_frame = 1;
344 // Allocate and decompress single frame into new temporary
345 //printf("FileList::read_frame %d\n", frame->get_color_model());
346 if(!temp || temp->get_color_model() != frame->get_color_model())
348 if(temp) delete temp;
352 if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
354 FILE *fd = fopen(asset->path, "rb");
358 stat(asset->path, &ostat);
360 switch(frame->get_color_model())
363 frame->allocate_compressed_data(ostat.st_size);
364 frame->set_compressed_size(ostat.st_size);
365 (void)fread(frame->get_data(), ostat.st_size, 1, fd);
368 data->allocate_compressed_data(ostat.st_size);
369 data->set_compressed_size(ostat.st_size);
370 (void)fread(data->get_data(), ostat.st_size, 1, fd);
371 temp = new VFrame(asset->width, asset->height,
372 frame->get_color_model(), 0);
373 read_frame(temp, data);
381 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
387 temp = new VFrame(asset->width, asset->height, frame->get_color_model(), 0);
388 read_frame(temp, asset->path);
392 if(!temp) return result;
394 //printf("FileList::read_frame frame=%d temp=%d\n",
395 // frame->get_color_model(), // temp->get_color_model());
396 frame->transfer_from(temp);
400 // printf("FileList::read_frame %d %d\n", __LINE__, result);
402 // if(frame->get_y())
403 // for(int i = 0; i < 100000; i++)
405 // frame->get_y()[i] = 0xff;
407 // if(frame->get_rows())
408 // for(int i = 0; i < 100000; i++)
410 // frame->get_rows()[0][i] = 0xff;
417 int FileList::write_frames(VFrame ***frames, int len)
421 //printf("FileList::write_frames 1\n");
422 if(frames[0][0]->get_color_model() == BC_COMPRESSED)
424 for(int i = 0; i < asset->layers && !return_value; i++)
426 for(int j = 0; j < len && !return_value; j++)
428 VFrame *frame = frames[i][j];
429 char *path = create_path(frame->get_number());
430 //printf("FileList::write_frames %d %jd\n", __LINE__, frame->get_number());
433 FILE *fd = fopen(path, "wb");
436 return_value = !fwrite(frames[i][j]->get_data(),
437 frames[i][j]->get_compressed_size(),
445 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
453 //printf("FileList::write_frames 2\n");
454 writer->write_frames(frames, len);
455 //printf("FileList::write_frames 100\n");
468 void FileList::add_return_value(int amount)
470 table_lock->lock("FileList::add_return_value");
471 return_value += amount;
472 table_lock->unlock();
475 char* FileList::calculate_path(int number, char *string)
477 // Synthesize filename.
478 // If a header is used, the filename number must be in a different location.
479 if(asset->use_header)
482 strcpy(string, asset->path);
483 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
485 if(k <= 0) k = strlen(string);
487 sprintf(&string[k], "%06d%s",
492 // Without a header, the original filename can be altered.
494 Render::create_filename(string,
504 char* FileList::create_path(int number_override)
506 if(asset->format != list_type) return asset->path;
508 table_lock->lock("FileList::create_path");
513 char output[BCTEXTLEN];
514 if(file->current_frame >= path_list.total || !asset->use_header)
517 if(number_override < 0)
518 number = file->current_frame++;
521 number = number_override;
522 file->current_frame++;
525 if(!asset->use_header)
527 number += first_number;
530 calculate_path(number, output);
532 path = new char[strlen(output) + 1];
533 strcpy(path, output);
534 path_list.append(path);
538 // Overwrite an old path
539 path = path_list.values[file->current_frame];
543 table_lock->unlock();
548 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
550 return new FrameWriterUnit(writer);
553 int64_t FileList::get_memory_usage()
556 if(data) result += data->get_compressed_allocated();
557 if(temp) result += temp->get_data_size();
558 // printf("FileList::get_memory_usage %d %p %s %jd\n",
561 // file->asset->path,
566 int FileList::get_units()
568 return !writer ? 0 : writer->get_total_clients();
571 FrameWriterUnit* FileList::get_unit(int number)
573 return !writer ? 0 : (FrameWriterUnit*)writer->get_client(number);
576 int FileList::use_path()
586 FrameWriterPackage::FrameWriterPackage()
590 FrameWriterPackage::~FrameWriterPackage()
604 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
607 // Don't use server here since subclasses call this with no server.
608 this->server = server;
612 FrameWriterUnit::~FrameWriterUnit()
617 void FrameWriterUnit::process_package(LoadPackage *package)
619 //printf("FrameWriterUnit::process_package 1\n");
620 FrameWriterPackage *ptr = (FrameWriterPackage*)package;
624 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
625 if(!(file = fopen(ptr->path, "wb")))
627 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), ptr->path);
630 //printf("FrameWriterUnit::process_package 3");
633 int result = server->file->write_frame(ptr->input, output, this);
635 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
636 if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
637 //TRACE("FrameWriterUnit::process_package 4");
639 //TRACE("FrameWriterUnit::process_package 5");
641 server->file->add_return_value(result);
642 //TRACE("FrameWriterUnit::process_package 6");
655 FrameWriter::FrameWriter(FileList *file, int cpus)
656 : LoadServer(cpus, 0)
662 FrameWriter::~FrameWriter()
666 void FrameWriter::init_packages()
668 for(int i = 0, layer = 0, number = 0;
669 i < get_total_packages();
672 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
673 package->input = frames[layer][number];
674 package->path = file->create_path(package->input->get_number());
675 // printf("FrameWriter::init_packages 1 %p %d %s\n",
677 // package->input->get_number(),
688 void FrameWriter::write_frames(VFrame ***frames, int len)
690 this->frames = frames;
692 set_package_count(len * file->asset->layers);
697 LoadClient* FrameWriter::new_client()
699 return file->new_writer_unit(this);
702 LoadPackage* FrameWriter::new_package()
704 return new FrameWriterPackage;