4 * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "bcsignals.h"
29 #include "interlacemodes.h"
31 #include "mwindow.inc"
33 #include "renderfarmfsserver.inc"
35 #include "mainerror.h"
46 FileList::FileList(Asset *asset,
48 const char *list_prefix,
49 const char *file_extension,
52 : FileBase(asset, file)
55 path_list.set_array_delete();
56 asset->video_data = 1;
57 this->list_prefix = list_prefix;
58 this->file_extension = file_extension;
59 this->frame_type = frame_type;
60 this->list_type = list_type;
61 table_lock = new Mutex("FileList::table_lock");
70 int FileList::reset_parameters_derived()
79 int FileList::open_file(int rd, int wr)
83 // skip header for write
86 int fd = open(asset->path, O_CREAT+O_TRUNC+O_RDWR, 0777);
90 // Frame files are created in write_frame and list index is created when
92 // Look for the starting number in the path but ignore the starting character
93 // and total digits since these are used by the header.
94 Render::get_starting_number(asset->path,
95 first_number, number_start, number_digits);
96 path_list.remove_all_objects();
97 writer = new FrameWriter(this,
98 asset->format == list_type ? file->cpus : 1);
101 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
106 // Determine type of file.
107 // Header isn't used for background rendering, in which case everything known
108 // by the file encoder is known by the decoder.
109 //printf("FileList::open_file %d %d\n", __LINE__, asset->use_header);
110 if(asset->use_header)
112 FILE *stream = fopen(asset->path, "rb");
113 //printf("FileList::open_file %d asset->path=%s\n", __LINE__, asset->path);
116 int width = asset->width, height = asset->height;
117 char string[BCTEXTLEN];
118 int len = strlen(list_prefix);
119 int ret = fread(string, 1, len, stream);
121 result = len == ret ? 0 : 1;
122 if( !result && !strncasecmp(string, list_prefix, len)) {
123 asset->format = list_type;
124 result = read_list_header();
126 result = read_frame_header(path_list.values[0]);
128 else if( !result && frame_type != FILE_UNKNOWN ) {
129 asset->format = frame_type;
130 result = read_frame_header(asset->path);
131 asset->video_length = -1;
136 asset->actual_width = asset->width;
137 asset->actual_height = asset->height;
138 int scale = asset->proxy_scale;
140 asset->width = asset->actual_width * scale;
141 asset->height = asset->actual_height * scale;
143 else { // can_scale_input
144 if( width ) asset->width = width;
145 if( height ) asset->height = height;
148 if( !asset->frame_rate )
149 asset->frame_rate = 10;
153 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
157 Render::get_starting_number(asset->path,
158 first_number, number_start, number_digits, 6);
163 file->current_frame = 0;
164 // Compressed data storage
171 int FileList::close_file()
173 // path_list.total, asset->format, list_type, wr);
174 if(asset->format == list_type && path_list.total)
176 if(file->wr && asset->use_header) write_list_header();
177 path_list.remove_all_objects();
179 if(data) delete data;
180 if(writer) delete writer;
181 if(temp) delete temp;
184 FileBase::close_file();
188 int FileList::write_list_header()
190 FILE *stream = fopen(asset->path, "w");
191 if( !stream ) return 1;
192 // Use sprintf instead of fprintf for VFS.
193 fprintf(stream, "%s\n", list_prefix);
194 fprintf(stream, "# First line is always %s\n", list_prefix);
195 fprintf(stream, "# Frame rate:\n");
196 fprintf(stream, "%f\n", asset->frame_rate);
197 fprintf(stream, "# Width:\n");
198 fprintf(stream, "%d\n", asset->width);
199 fprintf(stream, "# Height:\n");
200 fprintf(stream, "%d\n", asset->height);
201 fprintf(stream, "# List of image files follows\n");
203 char *cp = strrchr(asset->path, '/');
204 int dir_len = !cp ? 0 : cp - asset->path;
206 for(int i = 0; i < path_list.total; i++) {
207 const char *path = path_list.values[i];
208 // Fix path for VFS but leave leading slash
209 if( !strncmp(path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)) )
210 path += strlen(RENDERFARM_FS_PREFIX);
211 // ./path for relative list access
212 else if( dir_len > 0 && !strncmp(path, asset->path, dir_len) ) {
213 fprintf(stream, "."); path += dir_len;
215 fprintf(stream, "%s\n", path);
221 int FileList::read_list_header()
223 char string[BCTEXTLEN];
225 FILE *stream = fopen(asset->path, "r");
226 if( !stream ) return 1;
227 // Get information about the frames
229 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
230 } while(string[0] == '#' || string[0] == ' ' || isalpha(string[0]));
232 // Don't want a user configured frame rate to get destroyed
233 if(asset->frame_rate == 0)
234 asset->frame_rate = atof(string);
237 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
238 } while(string[0] == '#' || string[0] == ' ');
239 if( (asset->width = atol(string)) <= 0 ) return 1;
242 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
243 } while(string[0] == '#' || string[0] == ' ');
244 if( (asset->height = atol(string)) <= 0 ) return 1;
246 asset->interlace_mode = ILACE_MODE_UNDETECTED;
248 asset->audio_data = 0;
249 asset->video_data = 1;
251 char prefix[BCTEXTLEN], *bp = prefix, *cp = strrchr(asset->path, '/');
252 for( int i=0, n=!cp ? 0 : cp-asset->path; i<n; ++i ) *bp++ = asset->path[i];
255 // Get all the paths, expand relative paths
257 while( !feof(stream) && fgets(string, BCTEXTLEN, stream) ) {
258 int len = strlen(string);
259 if( !len || string[0] == '#' || string[0] == ' ' ) continue;
260 if( string[len-1] == '\n' ) string[len-1] = 0;
261 char path[BCTEXTLEN], *pp = path, *ep = pp + sizeof(path)-1;
262 if( string[0] == '.' && string[1] == '/' && prefix[0] )
263 pp += snprintf(pp, ep-pp, "%s/", prefix);
264 snprintf(pp, ep-pp, "%s", string);
265 if( access(path, R_OK) && !missing++ )
266 eprintf(_("%s:no such file"), path);
267 path_list.append(cstrdup(path));
270 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
272 if( !(asset->video_length = path_list.total) )
273 eprintf(_("%s:\nlist empty"), asset->path);
275 eprintf(_("%s:\n%d files not found"), asset->path, missing);
279 int FileList::read_frame(VFrame *frame)
284 // printf("FileList::read_frame %d %d use_header=%d current_frame=%d total=%d\n",
287 // asset->use_header,
288 // file->current_frame,
291 if(file->current_frame < 0 ||
292 (asset->use_header && file->current_frame >= path_list.total &&
293 asset->format == list_type))
296 if(asset->format == list_type)
298 char string[BCTEXTLEN];
300 if(asset->use_header)
302 path = path_list.values[file->current_frame];
306 path = calculate_path(file->current_frame, string);
311 // Fix path for VFS. Not used anymore.
312 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
313 sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
315 strcpy(string, path);
319 if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
321 if(!(in = fopen(string, "rb"))) {
322 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), string);
327 stat(string, &ostat);
329 switch(frame->get_color_model())
332 frame->allocate_compressed_data(ostat.st_size);
333 frame->set_compressed_size(ostat.st_size);
334 (void)fread(frame->get_data(), ostat.st_size, 1, in);
337 data->allocate_compressed_data(ostat.st_size);
338 data->set_compressed_size(ostat.st_size);
339 (void)fread(data->get_data(), ostat.st_size, 1, in);
340 result = read_frame(frame, data);
349 //printf("FileList::read_frame %d %s\n", __LINE__, string);
350 result = read_frame(frame, string);
355 asset->single_frame = 1;
356 // Allocate and decompress single frame into new temporary
357 //printf("FileList::read_frame %d\n", frame->get_color_model());
358 if( !temp || temp->get_color_model() != frame->get_color_model() ) {
359 delete temp; temp = 0;
360 int aw = asset->actual_width, ah = asset->actual_height;
361 int color_model = frame->get_color_model();
362 switch( color_model ) {
366 aw = (aw+1) & ~1; ah = (ah+1) & ~1;
370 aw = (aw+3) & ~3; ah = (ah+3) & ~3;
373 if( !use_path() || color_model == BC_COMPRESSED ) {
374 FILE *fd = fopen(asset->path, "rb");
377 stat(asset->path, &ostat);
379 switch(frame->get_color_model()) {
381 frame->allocate_compressed_data(ostat.st_size);
382 frame->set_compressed_size(ostat.st_size);
383 (void)fread(frame->get_data(), ostat.st_size, 1, fd);
386 data->allocate_compressed_data(ostat.st_size);
387 data->set_compressed_size(ostat.st_size);
388 (void)fread(data->get_data(), ostat.st_size, 1, fd);
389 temp = new VFrame(aw, ah, color_model);
390 read_frame(temp, data);
397 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
402 temp = new VFrame(aw, ah, color_model);
403 read_frame(temp, asset->path);
407 if(!temp) return result;
409 //printf("FileList::read_frame frame=%d temp=%d\n",
410 // frame->get_color_model(), // temp->get_color_model());
411 frame->transfer_from(temp);
415 // printf("FileList::read_frame %d %d\n", __LINE__, result);
417 // if(frame->get_y())
418 // for(int i = 0; i < 100000; i++)
420 // frame->get_y()[i] = 0xff;
422 // if(frame->get_rows())
423 // for(int i = 0; i < 100000; i++)
425 // frame->get_rows()[0][i] = 0xff;
432 int FileList::write_frames(VFrame ***frames, int len)
436 //printf("FileList::write_frames 1\n");
437 if(frames[0][0]->get_color_model() == BC_COMPRESSED)
439 for(int i = 0; i < asset->layers && !return_value; i++)
441 for(int j = 0; j < len && !return_value; j++)
443 VFrame *frame = frames[i][j];
444 char *path = create_path(frame->get_number());
445 //printf("FileList::write_frames %d %jd\n", __LINE__, frame->get_number());
448 FILE *fd = fopen(path, "wb");
451 return_value = !fwrite(frames[i][j]->get_data(),
452 frames[i][j]->get_compressed_size(),
460 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
468 //printf("FileList::write_frames 2\n");
469 writer->write_frames(frames, len);
470 //printf("FileList::write_frames 100\n");
483 void FileList::add_return_value(int amount)
485 table_lock->lock("FileList::add_return_value");
486 return_value += amount;
487 table_lock->unlock();
490 char* FileList::calculate_path(int number, char *string)
492 // Synthesize filename.
493 // If a header is used, the filename number must be in a different location.
494 if(asset->use_header)
497 strcpy(string, asset->path);
498 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
500 if(k <= 0) k = strlen(string);
502 sprintf(&string[k], "%06d%s",
507 // Without a header, the original filename can be altered.
509 Render::create_filename(string,
519 char* FileList::create_path(int number_override)
521 if(asset->format != list_type) return asset->path;
523 table_lock->lock("FileList::create_path");
528 char output[BCTEXTLEN];
529 if(file->current_frame >= path_list.total || !asset->use_header)
532 if(number_override < 0)
533 number = file->current_frame++;
536 number = number_override;
537 file->current_frame++;
540 if(!asset->use_header)
542 number += first_number;
545 calculate_path(number, output);
547 path = new char[strlen(output) + 1];
548 strcpy(path, output);
549 path_list.append(path);
553 // Overwrite an old path
554 path = path_list.values[file->current_frame];
558 table_lock->unlock();
563 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
565 return new FrameWriterUnit(writer);
568 int64_t FileList::get_memory_usage()
571 if(data) result += data->get_compressed_allocated();
572 if(temp) result += temp->get_data_size();
573 // printf("FileList::get_memory_usage %d %p %s %jd\n",
576 // file->asset->path,
581 int FileList::get_units()
583 return !writer ? 0 : writer->get_total_clients();
586 FrameWriterUnit* FileList::get_unit(int number)
588 return !writer ? 0 : (FrameWriterUnit*)writer->get_client(number);
591 int FileList::use_path()
601 FrameWriterPackage::FrameWriterPackage()
605 FrameWriterPackage::~FrameWriterPackage()
619 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
622 // Don't use server here since subclasses call this with no server.
623 this->server = server;
627 FrameWriterUnit::~FrameWriterUnit()
632 void FrameWriterUnit::process_package(LoadPackage *package)
634 //printf("FrameWriterUnit::process_package 1\n");
635 FrameWriterPackage *ptr = (FrameWriterPackage*)package;
639 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
640 if(!(file = fopen(ptr->path, "wb")))
642 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), ptr->path);
645 //printf("FrameWriterUnit::process_package 3");
648 int result = server->file->write_frame(ptr->input, output, this);
650 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
651 if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
652 //TRACE("FrameWriterUnit::process_package 4");
654 //TRACE("FrameWriterUnit::process_package 5");
656 server->file->add_return_value(result);
657 //TRACE("FrameWriterUnit::process_package 6");
670 FrameWriter::FrameWriter(FileList *file, int cpus)
671 : LoadServer(cpus, 0)
677 FrameWriter::~FrameWriter()
681 void FrameWriter::init_packages()
683 for(int i = 0, layer = 0, number = 0;
684 i < get_total_packages();
687 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
688 package->input = frames[layer][number];
689 package->path = file->create_path(package->input->get_number());
690 // printf("FrameWriter::init_packages 1 %p %d %s\n",
692 // package->input->get_number(),
703 void FrameWriter::write_frames(VFrame ***frames, int len)
705 this->frames = frames;
707 set_package_count(len * file->asset->layers);
712 LoadClient* FrameWriter::new_client()
714 return file->new_writer_unit(this);
717 LoadPackage* FrameWriter::new_package()
719 return new FrameWriterPackage;