centos build workarounds
[goodguy/history.git] / cinelerra-5.0 / cinelerra / filethread.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "condition.h"
25 #include "file.h"
26 #include "filethread.h"
27 #include "format.inc"
28 #include "mutex.h"
29 #include "samples.h"
30 #include "vframe.h"
31 #include "videodevice.inc"
32
33 #include <string.h>
34 #include <unistd.h>
35
36
37 FileThreadFrame::FileThreadFrame()
38 {
39         position = 0;
40         frame = 0;
41 }
42
43 FileThreadFrame::~FileThreadFrame()
44 {
45         if(frame) delete frame;
46 }
47
48
49
50 FileThread::FileThread(File *file, int do_audio, int do_video)
51  : Thread(1, 0, 0)
52 {
53         reset();
54         create_objects(file,
55                 do_audio,
56                 do_video);
57 }
58
59 FileThread::~FileThread()
60 {
61         delete_objects();
62
63
64 }
65
66 void FileThread::reset()
67 {
68         audio_buffer = 0;
69         video_buffer = 0;
70         output_size = 0;
71         input_lock = 0;
72         output_lock = 0;
73         last_buffer = 0;
74         is_writing = 0;
75         is_reading = 0;
76         file_lock = 0;
77
78         read_wait_lock = 0;
79         user_wait_lock = 0;
80         frame_lock = 0;
81         total_frames = 0;
82         done = 0;
83         disable_read = 1;
84         start_position = -1;
85         layer = -1;
86         read_position = 0;
87         bzero(read_frames, sizeof(FileThreadFrame*) * MAX_READ_FRAMES);
88 }
89
90
91 void FileThread::create_objects(File *file, 
92                 int do_audio, 
93                 int do_video)
94 {
95         this->file = file;
96         this->do_audio = do_audio;
97         this->do_video = do_video;
98         file_lock = new Mutex("FileThread::file_lock");
99         read_wait_lock = new Condition(0, "FileThread::read_wait_lock");
100         user_wait_lock = new Condition(0, "FileThread::user_wait_lock");
101         frame_lock = new Mutex("FileThread::frame_lock");
102         for(int i = 0; i < MAX_READ_FRAMES; i++)
103                 read_frames[i] = new FileThreadFrame;
104 }
105
106
107 void FileThread::delete_objects()
108 {
109         for(int i = 0; i < MAX_READ_FRAMES; i++)
110                 delete read_frames[i];
111
112         if(output_lock)
113         {
114                 for(int i = 0; i < ring_buffers; i++)
115                 {
116                         delete output_lock[i];
117                 }
118                 delete [] output_lock;
119         }
120
121         if(input_lock)
122         {
123                 for(int i = 0; i < ring_buffers; i++)
124                 {
125                         delete input_lock[i];
126                 }
127                 delete [] input_lock;
128         }
129
130
131         if(last_buffer)
132                 delete [] last_buffer;
133
134
135         delete [] output_size;
136
137         delete file_lock;
138
139
140         delete read_wait_lock;
141         delete user_wait_lock;
142         delete frame_lock;
143
144         reset();
145 }
146
147 void FileThread::run()
148 {
149         int i, j;
150         int debug = 0;
151         if(debug) PRINT_TRACE
152
153         if(is_reading)
154         {
155                 if(debug) PRINT_TRACE
156         
157                 while(!done && !disable_read)
158                 {
159                         if(debug) PRINT_TRACE
160                         frame_lock->lock("FileThread::run 1");
161                         int local_total_frames = total_frames;
162                         frame_lock->unlock();
163
164                         if(local_total_frames >= MAX_READ_FRAMES)
165                         {
166                                 read_wait_lock->lock("FileThread::run");
167                                 continue;
168                         }
169
170                         if(debug) PRINT_TRACE
171                         if(done || disable_read) break;
172
173 // Make local copes of the locked parameters
174                         FileThreadFrame *local_frame = 0;
175                         int64_t local_position = 0;
176                         int local_layer;
177                         if(debug) PRINT_TRACE
178
179                         frame_lock->lock("FileThread::run 2");
180 // Get position of next frame to read
181                         if(total_frames)
182                                 local_position = read_frames[total_frames - 1]->position + 1;
183                         else
184                                 local_position = start_position;
185 //printf("FileThread::run 1 %d " _LD "\n", total_frames, local_position);
186
187 // Get first available frame
188                         local_total_frames = total_frames;
189                         local_frame = read_frames[local_total_frames];
190                         local_layer = layer;
191                         local_frame->valid = 0;
192                         frame_lock->unlock();
193
194 // Read frame
195                         if(local_frame)
196                         {
197                                 if(debug) PRINT_TRACE
198                                 file->set_layer(local_layer, 1);
199                                 file->set_video_position(local_position, 1);
200                                 int supported_colormodel = 
201                                         file->get_best_colormodel(PLAYBACK_ASYNCHRONOUS);
202                                 if(debug) PRINT_TRACE
203
204
205 // Allocate frame
206                                 if(local_frame->frame &&
207                                         !local_frame->frame->params_match(file->asset->width,
208                                                 file->asset->height,
209                                                 supported_colormodel))
210                                 {
211                                         delete local_frame->frame;
212                                         local_frame->frame = 0;
213                                 }
214
215 //printf("FileThread::run %d\n", __LINE__);
216                                 if(!local_frame->frame)
217                                 {
218                                         local_frame->frame = new VFrame(0,
219                                                 -1,
220                                                 file->asset->width,
221                                                 file->asset->height,
222                                                 supported_colormodel,
223                                                 -1);
224                                 }
225
226 // Read it
227 // printf("FileThread::run %d w=%d h=%d supported_colormodel=%d\n", 
228 // __LINE__, 
229 // local_frame->frame->get_w(), 
230 // local_frame->frame->get_h(),
231 // local_frame->frame->get_color_model());
232                                 if(debug)
233                                 {
234                                         PRINT_TRACE
235                                         printf("file=%p local_frame->frame=%p\n", file, local_frame->frame);
236                                 }
237                                 file->read_frame(local_frame->frame, 1);
238                                 if(debug) PRINT_TRACE
239                                 local_frame->position = local_position;
240                                 local_frame->layer = local_layer;
241
242 // Put frame in last position but since the last position now may be
243 // lower than it was when we got the frame, swap the current
244 // last position with the previous last position.
245                                 frame_lock->lock("FileThread::run 3");
246                                 FileThreadFrame *old_frame = read_frames[total_frames];
247                                 read_frames[local_total_frames] = old_frame;
248                                 read_frames[total_frames++] = local_frame;
249                                 local_frame->valid = 1;
250                                 if(debug) PRINT_TRACE
251                                 frame_lock->unlock();
252
253 // Que the user
254                                 user_wait_lock->unlock();
255                                 if(debug) PRINT_TRACE
256                         }
257                 }
258         }
259         else
260         {
261                 while(!done)
262                 {
263                         output_lock[local_buffer]->lock("FileThread::run 1");
264                         return_value = 0;
265
266
267 // Timer timer;
268 // timer.update();
269                         if(!last_buffer[local_buffer])
270                         {
271                                 if(output_size[local_buffer])
272                                 {
273                                         int result = 0;
274                                         file_lock->lock("FileThread::run 2");
275                                         if(do_audio)
276                                         {
277                                                 result = file->write_samples(
278                                                         audio_buffer[local_buffer],
279                                                         output_size[local_buffer]);
280                                         }
281                                         else
282                                         if(do_video)
283                                         {
284                                                 if(compressed)
285                                                 {
286                                                         for(j = 0; j < file->asset->layers && !result; j++)
287                                                                 for(i = 0; i < output_size[local_buffer] && !result; i++)
288                                                                         result = file->write_compressed_frame(video_buffer[local_buffer][j][i]);
289                                                 }
290                                                 else
291                                                 {
292                                                         result = file->write_frames(video_buffer[local_buffer], 
293                                                                 output_size[local_buffer]);
294                                                 }
295                                         }
296
297                                         file_lock->unlock();
298                                         return_value = result;
299                                 }
300                                 else
301                                         return_value = 0;
302
303                                 output_size[local_buffer] = 0;
304                         }
305                         else
306                                 done = 1;
307
308                         input_lock[local_buffer]->unlock();
309                         local_buffer++;
310                         if(local_buffer >= ring_buffers) local_buffer = 0;
311                 }
312         }
313 }
314
315
316
317 int FileThread::stop_writing()
318 {
319         if(is_writing)
320         {
321                 int i, buffer, layer, frame;
322
323                 swap_buffer();
324                 input_lock[current_buffer]->lock("FileThread::stop_writing 1");
325
326                 last_buffer[current_buffer] = 1;
327
328                 for(i = 0; i < ring_buffers; i++)
329                         output_lock[i]->unlock();
330
331                 swap_buffer();
332
333 // wait for thread to finish
334                 Thread::join();
335
336 // delete buffers
337                 file_lock->lock("FileThread::stop_writing 2");
338                 if(do_audio)
339                 {
340                         for(buffer = 0; buffer < ring_buffers; buffer++)
341                         {
342                                 for(i = 0; i < file->asset->channels; i++)
343                                         delete audio_buffer[buffer][i];
344                                 delete [] audio_buffer[buffer];
345                         }
346                         delete [] audio_buffer;
347                         audio_buffer = 0;
348                 }
349
350 // printf("FileThread::stop_writing %d %d %d %d\n", 
351 // do_video,
352 // ring_buffers,
353 // file->asset->layers,
354 // buffer_size);
355                 if(do_video)
356                 {
357                         for(buffer = 0; buffer < ring_buffers; buffer++)
358                         {
359                                 for(layer = 0; layer < file->asset->layers; layer++)
360                                 {
361                                         for(frame = 0; frame < buffer_size; frame++)
362                                         {
363                                                 delete video_buffer[buffer][layer][frame];
364                                         }
365                                         delete [] video_buffer[buffer][layer];
366                                 }
367                                 delete [] video_buffer[buffer];
368                         }
369                         delete [] video_buffer;
370                         video_buffer = 0;
371                 }
372
373                 file_lock->unlock();
374         }
375         return 0;
376 }
377
378 int FileThread::start_writing(long buffer_size, 
379                 int color_model, 
380                 int ring_buffers, 
381                 int compressed)
382 {
383 // allocate buffers
384         int buffer, layer, frame;
385
386         this->ring_buffers = ring_buffers;
387         this->buffer_size = buffer_size;
388         this->color_model = color_model;
389         this->compressed = compressed;
390         this->current_buffer = ring_buffers - 1;
391         return_value = 0;
392         local_buffer = 0;
393
394         file_lock->lock("FileThread::start_writing 1");
395
396
397
398
399 // Buffer is swapped before first get
400         last_buffer = new int[ring_buffers];
401         output_size = new long[ring_buffers];
402
403
404         output_lock = new Condition*[ring_buffers];
405         input_lock = new Condition*[ring_buffers];
406         for(int i = 0; i < ring_buffers; i++)
407         {
408                 output_lock[i] = new Condition(0, "FileThread::output_lock");
409                 input_lock[i] = new Condition(1, "FileThread::input_lock");
410                 last_buffer[i] = 0;
411                 output_size[i] = 0;
412         }
413
414
415
416         if(do_audio)
417         {
418                 audio_buffer = new Samples**[ring_buffers];
419                 for(buffer = 0; buffer < ring_buffers; buffer++)
420                 {
421                         audio_buffer[buffer] = new Samples*[file->asset->channels];
422
423                         for(int channel = 0; channel < file->asset->channels; channel++)
424                         {
425                                 audio_buffer[buffer][channel] = new Samples(buffer_size);
426                         }
427                 }
428         }
429
430         if(do_video)
431         {
432                 this->color_model = color_model;
433                 //long bytes_per_frame = VFrame::calculate_data_size(file->asset->width,
434                 //      file->asset->height, -1, color_model);
435
436                 video_buffer = new VFrame***[ring_buffers];
437 // printf("FileThread::start_writing 1 %d %d %d %p\n", 
438 // ring_buffers,
439 // file->asset->layers,
440 // buffer_size,
441 // video_buffer);
442                 for(buffer = 0; buffer < ring_buffers; buffer++)
443                 {
444                         video_buffer[buffer] = new VFrame**[file->asset->layers];
445                         for(layer = 0; layer < file->asset->layers; layer++)
446                         {
447                                 video_buffer[buffer][layer] = new VFrame*[buffer_size];
448                                 for(frame = 0; frame < buffer_size; frame++)
449                                 {
450                                         if(compressed)
451                                         {
452                                                 video_buffer[buffer][layer][frame] = new VFrame;
453 //printf("FileThread::start_writing %d %d\n", __LINE__);
454                                         }
455                                         else
456                                         {
457                                                 video_buffer[buffer][layer][frame] = 
458                                                         new VFrame(0, 
459                                                                 -1,
460                                                                 file->asset->width, 
461                                                                 file->asset->height, 
462                                                                 color_model,
463                                                                 -1);
464 // printf("FileThread::start_writing %d %d %d %d %p\n", 
465 // __LINE__, 
466 // buffer, 
467 // layer, 
468 // frame, 
469 // video_buffer[buffer][layer]);
470                                         }
471                                 }
472                         }
473                 }
474         }
475         file_lock->unlock();
476
477         for(int i = 0; i < ring_buffers; i++)
478         {
479                 last_buffer[i] = 0;
480         }
481
482         is_writing = 1;
483         done = 0;
484         Thread::start();
485         return 0;
486 }
487
488 int FileThread::start_reading()
489 {
490         if(!is_reading)
491         {
492                 is_reading = 1;
493                 disable_read = 1;
494                 done = 0;
495         }
496         return 0;
497 }
498
499 int FileThread::stop_reading()
500 {
501         if(is_reading && Thread::running())
502         {
503                 done = 1;
504                 read_wait_lock->unlock();
505                 Thread::join();
506         }
507         return 0;
508 }
509
510 int FileThread::set_video_position(int64_t position)
511 {
512 // If the new position can't be added to the buffer without restarting,
513 // disable reading.
514         if((position < this->start_position ||
515                 position >= this->start_position + MAX_READ_FRAMES) && 
516                 !disable_read)
517         {
518                 disable_read = 1;
519                 read_wait_lock->unlock();
520                 Thread::join();
521
522                 total_frames = 0;
523                 for(int i = 0; i < MAX_READ_FRAMES; i++)
524                         read_frames[i]->valid = 0;
525                 this->start_position = position;
526         }
527         else
528 // If a sequential read, enable reading
529         if(this->start_position + 1 == position && disable_read)
530         {
531                 this->start_position = position;
532                 disable_read = 0;
533                 Thread::start();
534         }
535         else
536         if(disable_read)
537         {
538                 this->start_position = position;
539         }
540
541         this->read_position = position;
542         return 0;
543 }
544
545 int FileThread::set_layer(int layer)
546 {
547         if(layer != this->layer)
548         {
549                 disable_read = 1;
550                 read_wait_lock->unlock();
551                 Thread::join();
552                 total_frames = 0;
553         }
554         this->layer = layer;
555         return 0;
556 }
557
558 int FileThread::read_frame(VFrame *frame)
559 {
560         FileThreadFrame *local_frame = 0;
561         int got_it = 0;
562         int number = 0;
563
564 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
565
566 // Search thread for frame
567         while(!got_it && !disable_read)
568         {
569                 frame_lock->lock("FileThread::read_frame 1");
570 // printf("FileThread::read_frame: 1 read_position=" _LD " ", read_position);
571 // for(int i = 0; i < total_frames; i++)
572 // printf("" _LD " ", read_frames[i]->position);
573 // printf("\n");
574                 for(int i = 0; i < total_frames; i++)
575                 {
576                         local_frame = read_frames[i];
577                         if(local_frame->position == read_position &&
578                                 local_frame->layer == layer &&
579                                 local_frame->frame &&
580                                 local_frame->frame->equal_stacks(frame) &&
581                                 local_frame->valid)
582                         {
583                                 got_it = 1;
584                                 number = i;
585                                 break;
586                         }
587                 }
588                 frame_lock->unlock();
589
590 // Not decoded yet but thread active
591                 if(!got_it && !disable_read)
592                 {
593                         user_wait_lock->lock("FileThread::read_frame");
594                 }
595         }
596
597 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
598
599         if(got_it)
600         {
601 // printf("FileThread::read_frame 1 color_model=%d disable_read=%d\n", 
602 // frame->get_color_model(), 
603 // disable_read);
604 // Copy image
605                 if(frame->get_color_model() != local_frame->frame->get_color_model() ||
606                         frame->get_w() != local_frame->frame->get_w() ||
607                         frame->get_h() != local_frame->frame->get_h())
608                 {
609 // printf("FileThread::read_frame %d this=%p out cmodel=%d h=%d in cmodel=%d h=%d\n", 
610 // __LINE__, 
611 // this,
612 // frame->get_color_model(),
613 // frame->get_w(),
614 // local_frame->frame->get_color_model(),
615 // local_frame->frame->get_w());
616                         BC_CModels::transfer(frame->get_rows(), 
617                                 local_frame->frame->get_rows(),
618                                 frame->get_y(),
619                                 frame->get_u(),
620                                 frame->get_v(),
621                                 local_frame->frame->get_y(),
622                                 local_frame->frame->get_u(),
623                                 local_frame->frame->get_v(),
624                                 0, 
625                                 0, 
626                                 local_frame->frame->get_w(), 
627                                 local_frame->frame->get_h(),
628                                 0, 
629                                 0, 
630                                 frame->get_w(), 
631                                 frame->get_h(),
632                                 local_frame->frame->get_color_model(), 
633                                 frame->get_color_model(),
634                                 0,
635                                 local_frame->frame->get_w(),
636                                 frame->get_w());
637 //for(int i = 0; i < 3000 * 1000 * 4; i++)
638 //((float*)frame->get_rows()[0])[i] = 1;
639 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
640                 }
641                 else
642                 {
643 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
644                         frame->copy_from(local_frame->frame);
645 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
646                 }
647
648 // Can't copy stacks because the stack is needed by the plugin requestor.
649                 frame->copy_params(local_frame->frame);
650 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
651
652 // Recycle all frames before current one but not including current one.
653 // This handles redrawing of a single frame but because FileThread has no
654 // notion of a still frame, it has to call read_frame for those.
655                 frame_lock->lock("FileThread::read_frame 1");
656                 FileThreadFrame *new_table[MAX_READ_FRAMES];
657                 int k = 0;
658                 for(int j = number; j < total_frames; j++, k++)
659                 {
660                         new_table[k] = read_frames[j];
661                 }
662                 for(int j = 0; j < number; j++, k++)
663                 {
664                         new_table[k] = read_frames[j];
665                 }
666                 memcpy(read_frames, new_table, sizeof(FileThreadFrame*) * total_frames);
667 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
668                 total_frames -= number;
669
670                 start_position = read_position;
671                 read_position++;
672                 frame_lock->unlock();
673                 read_wait_lock->unlock();
674                 return 0;
675         }
676         else
677         {
678 // printf("FileThread::read_frame 2 color_model=%d disable_read=%d\n", 
679 // frame->get_color_model(), 
680 // disable_read);
681 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
682 // Use traditional read function
683                 file->set_layer(layer, 1);
684                 file->set_video_position(read_position, 1);
685                 read_position++;
686                 int result = file->read_frame(frame, 1);
687 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
688                 return result;
689         }
690
691
692 //printf("FileThread::read_frame %d this=%p\n", __LINE__, this);
693 }
694
695 int64_t FileThread::get_memory_usage()
696 {
697         frame_lock->lock("FileThread::get_memory_usage");
698         int64_t result = 0;
699         for(int i = 0; i < MAX_READ_FRAMES; i++)
700                 if(read_frames[i] && read_frames[i]->frame)
701                         result += read_frames[i]->frame->get_data_size();
702         frame_lock->unlock();
703         return result;
704 }
705
706
707 Samples** FileThread::get_audio_buffer()
708 {
709         swap_buffer();
710
711         input_lock[current_buffer]->lock("FileThread::get_audio_buffer");
712         return audio_buffer[current_buffer];
713 }
714
715 VFrame*** FileThread::get_video_buffer()
716 {
717         swap_buffer();
718
719         input_lock[current_buffer]->lock("FileThread::get_video_buffer");
720         return video_buffer[current_buffer];
721 }
722
723 VFrame*** FileThread::get_last_video_buffer()
724 {
725         return video_buffer[current_buffer];
726 }
727
728 int FileThread::write_buffer(long size)
729 {
730         output_size[current_buffer] = size;
731
732 // unlock the output lock
733         output_lock[current_buffer]->unlock();
734
735         return return_value;
736 }
737
738 int FileThread::swap_buffer()
739 {
740         current_buffer++;
741         if(current_buffer >= ring_buffers) current_buffer = 0;
742         return 0;
743 }
744
745