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"
27 #include "interlacemodes.h"
29 #include "mwindow.inc"
31 #include "renderfarmfsserver.inc"
33 #include "mainerror.h"
43 FileList::FileList(Asset *asset,
45 const char *list_prefix,
46 const char *file_extension,
49 : FileBase(asset, file)
52 path_list.set_array_delete();
53 asset->video_data = 1;
54 this->list_prefix = list_prefix;
55 this->file_extension = file_extension;
56 this->frame_type = frame_type;
57 this->list_type = list_type;
58 table_lock = new Mutex("FileList::table_lock");
67 int FileList::reset_parameters_derived()
76 int FileList::open_file(int rd, int wr)
80 // skip header for write
83 // Frame files are created in write_frame and list index is created when
85 // Look for the starting number in the path but ignore the starting character
86 // and total digits since these are used by the header.
87 Render::get_starting_number(asset->path,
91 path_list.remove_all_objects();
92 writer = new FrameWriter(this,
93 asset->format == list_type ? file->cpus : 1);
98 // Determine type of file.
99 // Header isn't used for background rendering, in which case everything known
100 // by the file encoder is known by the decoder.
101 //printf("FileList::open_file %d %d\n", __LINE__, asset->use_header);
102 if(asset->use_header)
104 FILE *stream = fopen(asset->path, "rb");
105 //printf("FileList::open_file %d asset->path=%s\n", __LINE__, asset->path);
108 char string[BCTEXTLEN];
109 (void)fread(string, strlen(list_prefix), 1, stream);
112 if(!strncasecmp(string, list_prefix, strlen(list_prefix)))
115 //printf("FileList::open_file %d\n", __LINE__);
116 asset->format = list_type;
118 // Open index here or get frame size from file.
119 result = read_list_header();
120 //printf("FileList::open_file %d %s\n", __LINE__, path_list.values[0]);
121 if(!result) result = read_frame_header(path_list.values[0]);
125 //printf("FileList::open_file 2\n", asset->use_header);
126 //printf("FileList::open_file %d\n", __LINE__);
127 asset->format = frame_type;
128 result = read_frame_header(asset->path);
130 if(!asset->frame_rate)
131 asset->frame_rate = 1;
132 asset->video_length = -1;
138 Render::get_starting_number(asset->path,
146 file->current_frame = 0;
147 // Compressed data storage
154 int FileList::close_file()
156 // path_list.total, asset->format, list_type, wr);
157 if(asset->format == list_type && path_list.total)
159 if(file->wr && asset->use_header) write_list_header();
160 path_list.remove_all_objects();
162 if(data) delete data;
163 if(writer) delete writer;
164 if(temp) delete temp;
167 FileBase::close_file();
171 int FileList::write_list_header()
173 FILE *stream = fopen(asset->path, "w");
174 // Use sprintf instead of fprintf for VFS.
175 char string[BCTEXTLEN];
176 sprintf(string, "%s\n", list_prefix);
177 fwrite(string, strlen(string), 1, stream);
178 sprintf(string, "# First line is always %s\n", list_prefix);
179 fwrite(string, strlen(string), 1, stream);
180 sprintf(string, "# Frame rate:\n");
181 fwrite(string, strlen(string), 1, stream);
182 sprintf(string, "%f\n", asset->frame_rate);
183 fwrite(string, strlen(string), 1, stream);
184 sprintf(string, "# Width:\n");
185 fwrite(string, strlen(string), 1, stream);
186 sprintf(string, "%d\n", asset->width);
187 fwrite(string, strlen(string), 1, stream);
188 sprintf(string, "# Height:\n");
189 fwrite(string, strlen(string), 1, stream);
190 sprintf(string, "%d\n", asset->height);
191 fwrite(string, strlen(string), 1, stream);
192 sprintf(string, "# List of image files follows\n");
193 fwrite(string, strlen(string), 1, stream);
195 for(int i = 0; i < path_list.total; i++)
197 // Fix path for VFS but leave leading slash
198 if(!strncmp(path_list.values[i], RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
199 sprintf(string, "%s\n", path_list.values[i] + strlen(RENDERFARM_FS_PREFIX));
201 sprintf(string, "%s\n", path_list.values[i]);
202 fwrite(string, strlen(string), 1, stream);
208 int FileList::read_list_header()
210 char string[BCTEXTLEN], *new_entry;
212 FILE *stream = fopen(asset->path, "r");
217 // Get information about the frames
220 (void)fgets(string, BCTEXTLEN, stream);
221 }while(!feof(stream) && (string[0] == '#' || string[0] == ' ' || isalpha(string[0])));
223 // Don't want a user configured frame rate to get destroyed
224 if(asset->frame_rate == 0)
225 asset->frame_rate = atof(string);
229 (void)fgets(string, BCTEXTLEN, stream);
230 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
231 asset->width = atol(string);
235 (void)fgets(string, BCTEXTLEN, stream);
236 }while(!feof(stream) && (string[0] == '#' || string[0] == ' '));
237 asset->height = atol(string);
239 asset->interlace_mode = BC_ILACE_MODE_UNDETECTED; // May be good to store the info in the list?
241 asset->audio_data = 0;
242 asset->video_data = 1;
247 (void)fgets(string, BCTEXTLEN, stream);
248 if(strlen(string) && string[0] != '#' && string[0] != ' ' && !feof(stream))
250 string[strlen(string) - 1] = 0;
251 path_list.append(new_entry = new char[strlen(string) + 1]);
252 strcpy(new_entry, string);
256 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
258 asset->video_length = path_list.total;
266 int FileList::read_frame(VFrame *frame)
271 // printf("FileList::read_frame %d %d use_header=%d current_frame=%d total=%d\n",
274 // asset->use_header,
275 // file->current_frame,
278 if(file->current_frame < 0 ||
279 (asset->use_header && file->current_frame >= path_list.total &&
280 asset->format == list_type))
283 if(asset->format == list_type)
285 char string[BCTEXTLEN];
287 if(asset->use_header)
289 path = path_list.values[file->current_frame];
293 path = calculate_path(file->current_frame, string);
299 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
300 sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
302 strcpy(string, path);
306 if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
308 if(!(in = fopen(string, "rb"))) {
309 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), string);
314 stat(string, &ostat);
316 switch(frame->get_color_model())
319 frame->allocate_compressed_data(ostat.st_size);
320 frame->set_compressed_size(ostat.st_size);
321 (void)fread(frame->get_data(), ostat.st_size, 1, in);
324 data->allocate_compressed_data(ostat.st_size);
325 data->set_compressed_size(ostat.st_size);
326 (void)fread(data->get_data(), ostat.st_size, 1, in);
327 result = read_frame(frame, data);
336 //printf("FileList::read_frame %d %s\n", __LINE__, string);
337 result = read_frame(frame, string);
342 // Allocate and decompress single frame into new temporary
343 //printf("FileList::read_frame %d\n", frame->get_color_model());
344 if(!temp || temp->get_color_model() != frame->get_color_model())
346 if(temp) delete temp;
350 if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
352 FILE *fd = fopen(asset->path, "rb");
356 stat(asset->path, &ostat);
358 switch(frame->get_color_model())
361 frame->allocate_compressed_data(ostat.st_size);
362 frame->set_compressed_size(ostat.st_size);
363 (void)fread(frame->get_data(), ostat.st_size, 1, fd);
366 data->allocate_compressed_data(ostat.st_size);
367 data->set_compressed_size(ostat.st_size);
368 (void)fread(data->get_data(), ostat.st_size, 1, fd);
373 frame->get_color_model(),
375 read_frame(temp, data);
383 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
393 frame->get_color_model(),
395 read_frame(temp, asset->path);
399 if(!temp) return result;
401 // printf("FileList::read_frame frame=%d temp=%d\n",
402 // frame->get_color_model(),
403 // temp->get_color_model());
404 if(frame->get_color_model() == temp->get_color_model())
406 frame->copy_from(temp);
411 BC_CModels::transfer(frame->get_rows(), /* Leave NULL if non existent */
413 frame->get_y(), /* Leave NULL if non existent */
416 temp->get_y(), /* Leave NULL if non existent */
419 0, /* Dimensions to capture from input frame */
423 0, /* Dimensions to project on output frame */
427 temp->get_color_model(),
428 frame->get_color_model(),
429 0, /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
430 temp->get_w(), /* For planar use the luma rowspan */
436 // printf("FileList::read_frame %d %d\n", __LINE__, result);
438 // if(frame->get_y())
439 // for(int i = 0; i < 100000; i++)
441 // frame->get_y()[i] = 0xff;
443 // if(frame->get_rows())
444 // for(int i = 0; i < 100000; i++)
446 // frame->get_rows()[0][i] = 0xff;
453 int FileList::write_frames(VFrame ***frames, int len)
457 //printf("FileList::write_frames 1\n");
458 if(frames[0][0]->get_color_model() == BC_COMPRESSED)
460 for(int i = 0; i < asset->layers && !return_value; i++)
462 for(int j = 0; j < len && !return_value; j++)
464 VFrame *frame = frames[i][j];
465 char *path = create_path(frame->get_number());
466 //printf("FileList::write_frames %d %jd\n", __LINE__, frame->get_number());
469 FILE *fd = fopen(path, "wb");
472 return_value = !fwrite(frames[i][j]->get_data(),
473 frames[i][j]->get_compressed_size(),
481 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
489 //printf("FileList::write_frames 2\n");
490 writer->write_frames(frames, len);
491 //printf("FileList::write_frames 100\n");
504 void FileList::add_return_value(int amount)
506 table_lock->lock("FileList::add_return_value");
507 return_value += amount;
508 table_lock->unlock();
511 char* FileList::calculate_path(int number, char *string)
513 // Synthesize filename.
514 // If a header is used, the filename number must be in a different location.
515 if(asset->use_header)
518 strcpy(string, asset->path);
519 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
521 if(k <= 0) k = strlen(string);
523 sprintf(&string[k], "%06d%s",
528 // Without a header, the original filename can be altered.
530 Render::create_filename(string,
540 char* FileList::create_path(int number_override)
542 if(asset->format != list_type) return asset->path;
544 table_lock->lock("FileList::create_path");
549 char output[BCTEXTLEN];
550 if(file->current_frame >= path_list.total || !asset->use_header)
553 if(number_override < 0)
554 number = file->current_frame++;
557 number = number_override;
558 file->current_frame++;
561 if(!asset->use_header)
563 number += first_number;
566 calculate_path(number, output);
568 path = new char[strlen(output) + 1];
569 strcpy(path, output);
570 path_list.append(path);
574 // Overwrite an old path
575 path = path_list.values[file->current_frame];
579 table_lock->unlock();
584 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
586 return new FrameWriterUnit(writer);
589 int64_t FileList::get_memory_usage()
592 if(data) result += data->get_compressed_allocated();
593 if(temp) result += temp->get_data_size();
594 // printf("FileList::get_memory_usage %d %p %s %jd\n",
597 // file->asset->path,
602 int FileList::get_units()
604 return !writer ? 0 : writer->get_total_clients();
607 FrameWriterUnit* FileList::get_unit(int number)
609 return !writer ? 0 : (FrameWriterUnit*)writer->get_client(number);
612 int FileList::use_path()
622 FrameWriterPackage::FrameWriterPackage()
626 FrameWriterPackage::~FrameWriterPackage()
640 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
643 // Don't use server here since subclasses call this with no server.
644 this->server = server;
648 FrameWriterUnit::~FrameWriterUnit()
653 void FrameWriterUnit::process_package(LoadPackage *package)
655 //printf("FrameWriterUnit::process_package 1\n");
656 FrameWriterPackage *ptr = (FrameWriterPackage*)package;
660 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
661 if(!(file = fopen(ptr->path, "wb")))
663 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), ptr->path);
666 //printf("FrameWriterUnit::process_package 3");
669 int result = server->file->write_frame(ptr->input, output, this);
671 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
672 if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
673 //TRACE("FrameWriterUnit::process_package 4");
675 //TRACE("FrameWriterUnit::process_package 5");
677 server->file->add_return_value(result);
678 //TRACE("FrameWriterUnit::process_package 6");
691 FrameWriter::FrameWriter(FileList *file, int cpus)
692 : LoadServer(cpus, 0)
698 FrameWriter::~FrameWriter()
702 void FrameWriter::init_packages()
704 for(int i = 0, layer = 0, number = 0;
705 i < get_total_packages();
708 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
709 package->input = frames[layer][number];
710 package->path = file->create_path(package->input->get_number());
711 // printf("FrameWriter::init_packages 1 %p %d %s\n",
713 // package->input->get_number(),
724 void FrameWriter::write_frames(VFrame ***frames, int len)
726 this->frames = frames;
728 set_package_count(len * file->asset->layers);
733 LoadClient* FrameWriter::new_client()
735 return file->new_writer_unit(this);
738 LoadPackage* FrameWriter::new_package()
740 return new FrameWriterPackage;