r956: README.BUILD - add more library recommendations
[cinelerra_cv/ct.git] / cinelerra / filethread.C
blob51d53361977b15dc232652b19ea99d628e2a3fba
1 #include "asset.h"
2 #include "bcsignals.h"
3 #include "condition.h"
4 #include "file.h"
5 #include "filethread.h"
6 #include "mutex.h"
7 #include "vframe.h"
8 #include "videodevice.inc"
10 #include <string.h>
11 #include <unistd.h>
14 FileThreadFrame::FileThreadFrame()
16         position = 0;
17         frame = 0;
20 FileThreadFrame::~FileThreadFrame()
22         if(frame) delete frame;
27 FileThread::FileThread(File *file, int do_audio, int do_video)
28  : Thread(1, 0, 0)
30         reset();
31         create_objects(file,
32                 do_audio,
33                 do_video);
36 FileThread::~FileThread()
38         delete_objects();
43 void FileThread::reset()
45         audio_buffer = 0;
46         video_buffer = 0;
47         output_size = 0;
48         input_lock = 0;
49         output_lock = 0;
50         last_buffer = 0;
51         is_writing = 0;
52         is_reading = 0;
53         file_lock = 0;
55         read_wait_lock = 0;
56         user_wait_lock = 0;
57         frame_lock = 0;
58         total_frames = 0;
59         done = 0;
60         disable_read = 1;
61         start_position = -1;
62         read_position = 0;
63         bzero(read_frames, sizeof(FileThreadFrame*) * MAX_READ_FRAMES);
67 void FileThread::create_objects(File *file, 
68                 int do_audio, 
69                 int do_video)
71         this->file = file;
72         this->do_audio = do_audio;
73         this->do_video = do_video;
74         file_lock = new Mutex("FileThread::file_lock");
75         read_wait_lock = new Condition(0, "FileThread::read_wait_lock");
76         user_wait_lock = new Condition(0, "FileThread::user_wait_lock");
77         frame_lock = new Mutex("FileThread::frame_lock");
78         for(int i = 0; i < MAX_READ_FRAMES; i++)
79                 read_frames[i] = new FileThreadFrame;
83 void FileThread::delete_objects()
85         if(output_lock)
86         {
87                 for(int i = 0; i < ring_buffers; i++)
88                 {
89                         delete output_lock[i];
90                 }
91                 delete [] output_lock;
92         }
94         if(input_lock)
95         {
96                 for(int i = 0; i < ring_buffers; i++)
97                 {
98                         delete input_lock[i];
99                 }
100                 delete [] input_lock;
101         }
104         if(last_buffer)
105                 delete [] last_buffer;
108         delete [] output_size;
110         delete file_lock;
113         delete read_wait_lock;
114         delete user_wait_lock;
115         delete frame_lock;
117         reset();
120 void FileThread::run()
122         int i, j, result;
124         if(is_reading)
125         {
126                 
127                 while(!done && !disable_read)
128                 {
129                         frame_lock->lock("FileThread::run 1");
130                         int local_total_frames = total_frames;
131                         frame_lock->unlock();
133                         if(local_total_frames >= MAX_READ_FRAMES)
134                         {
135                                 read_wait_lock->lock("FileThread::run");
136                                 continue;
137                         }
139                         if(done || disable_read) break;
141 // Make local copes of the locked parameters
142                         FileThreadFrame *local_frame = 0;
143                         int64_t local_position = 0;
144                         int local_layer;
146                         frame_lock->lock("FileThread::run 2");
147 // Get position of next frame to read
148                         if(total_frames)
149                                 local_position = read_frames[total_frames - 1]->position + 1;
150                         else
151                                 local_position = start_position;
152 //printf("FileThread::run 1 %d %lld\n", total_frames, local_position);
154 // Get first available frame
155                         local_total_frames = total_frames;
156                         local_frame = read_frames[local_total_frames];
157                         local_layer = layer;
158                         frame_lock->unlock();
160 // Read frame
161                         if(local_frame)
162                         {
163                                 file->set_video_position(local_position, -1, 1);
164                                 file->set_layer(local_layer, 1);
165                                 int supported_colormodel = 
166                                         file->get_best_colormodel(PLAYBACK_ASYNCHRONOUS);
169 // Allocate frame
170                                 if(local_frame->frame &&
171                                         !local_frame->frame->params_match(file->asset->width,
172                                                 file->asset->height,
173                                                 supported_colormodel))
174                                 {
175                                         delete local_frame->frame;
176                                         local_frame->frame = 0;
177                                 }
179                                 if(!local_frame->frame)
180                                 {
181                                         local_frame->frame = new VFrame(0,
182                                                 file->asset->width,
183                                                 file->asset->height,
184                                                 supported_colormodel);
185                                 }
187 // Read it
188 //printf("FileThread::run %lld\n", local_position);
189                                 file->read_frame(local_frame->frame, 1);
190                                 local_frame->position = local_position;
191                                 local_frame->layer = local_layer;
193 // Put frame in last position but since the last position now may be
194 // lower than it was when we got the frame, swap the current
195 // last position with the previous last position.
196                                 frame_lock->lock("FileThread::run 3");
197                                 FileThreadFrame *old_frame = read_frames[total_frames];
198                                 read_frames[local_total_frames] = old_frame;
199                                 read_frames[total_frames++] = local_frame;
200                                 frame_lock->unlock();
202 // Que the user
203                                 user_wait_lock->unlock();
204                         }
205                 }
206         }
207         else
208         {
209                 while(!done)
210                 {
211                         output_lock[local_buffer]->lock("FileThread::run 1");
212                         return_value = 0;
215 // Timer timer;
216 // timer.update();
217                         if(!last_buffer[local_buffer])
218                         {
219                                 if(output_size[local_buffer])
220                                 {
221                                         file_lock->lock("FileThread::run 2");
222                                         if(do_audio)
223                                         {
224                                                         result = file->write_samples(audio_buffer[local_buffer], 
225                                                         output_size[local_buffer]);
226                                         }
227                                         else
228                                         if(do_video)
229                                         {
230                                                 result = 0;
231                                                 if(compressed)
232                                                 {
233                                                         for(j = 0; j < file->asset->layers && !result; j++)
234                                                                 for(i = 0; i < output_size[local_buffer] && !result; i++)
235                                                                         result = file->write_compressed_frame(video_buffer[local_buffer][j][i]);
236                                                 }
237                                                 else
238                                                 {
239                                                         result = file->write_frames(video_buffer[local_buffer], 
240                                                                 output_size[local_buffer]);
241                                                 }
242                                         }
244                                         file_lock->unlock();
245                                         return_value = result;
246                                 }
247                                 else
248                                         return_value = 0;
250                                 output_size[local_buffer] = 0;
251                         }
252                         else
253                                 done = 1;
255                         input_lock[local_buffer]->unlock();
256                         local_buffer++;
257                         if(local_buffer >= ring_buffers) local_buffer = 0;
258                 }
259         }
264 int FileThread::stop_writing()
266         if(is_writing)
267         {
268                 int i, buffer, layer, frame;
270                 swap_buffer();
271                 input_lock[current_buffer]->lock("FileThread::stop_writing 1");
273                 last_buffer[current_buffer] = 1;
275                 for(i = 0; i < ring_buffers; i++)
276                         output_lock[i]->unlock();
278                 swap_buffer();
280 // wait for thread to finish
281                 Thread::join();
283 // delete buffers
284                 file_lock->lock("FileThread::stop_writing 2");
285                 if(do_audio)
286                 {
287                         for(buffer = 0; buffer < ring_buffers; buffer++)
288                         {
289                                 for(i = 0; i < file->asset->channels; i++)
290                                         delete [] audio_buffer[buffer][i];
291                                 delete [] audio_buffer[buffer];
292                         }
293                         delete [] audio_buffer;
294                         audio_buffer = 0;
295                 }
297 // printf("FileThread::stop_writing %d %d %d %d\n", 
298 // do_video,
299 // ring_buffers,
300 // file->asset->layers,
301 // buffer_size);
302                 if(do_video)
303                 {
304                         for(buffer = 0; buffer < ring_buffers; buffer++)
305                         {
306                                 for(layer = 0; layer < file->asset->layers; layer++)
307                                 {
308                                         for(frame = 0; frame < buffer_size; frame++)
309                                         {
310                                                 delete video_buffer[buffer][layer][frame];
311                                         }
312                                         delete [] video_buffer[buffer][layer];
313                                 }
314                                 delete [] video_buffer[buffer];
315                         }
316                         delete [] video_buffer;
317                         video_buffer = 0;
318                 }
320                 file_lock->unlock();
321         }
322         return 0;
325 int FileThread::start_writing(long buffer_size, 
326                 int color_model, 
327                 int ring_buffers, 
328                 int compressed)
330 // allocate buffers
331         int buffer, layer, frame;
332         long bytes_per_frame;
334         this->ring_buffers = ring_buffers;
335         this->buffer_size = buffer_size;
336         this->color_model = color_model;
337         this->compressed = compressed;
338         this->current_buffer = ring_buffers - 1;
339         return_value = 0;
340         local_buffer = 0;
342         file_lock->lock("FileThread::start_writing 1");
347 // Buffer is swapped before first get
348         last_buffer = new int[ring_buffers];
349         output_size = new long[ring_buffers];
352         output_lock = new Condition*[ring_buffers];
353         input_lock = new Condition*[ring_buffers];
354         for(int i = 0; i < ring_buffers; i++)
355         {
356                 output_lock[i] = new Condition(0, "FileThread::output_lock");
357                 input_lock[i] = new Condition(1, "FileThread::input_lock");
358                 last_buffer[i] = 0;
359                 output_size[i] = 0;
360         }
364         if(do_audio)
365         {
366                 audio_buffer = new double**[ring_buffers];
367                 for(buffer = 0; buffer < ring_buffers; buffer++)
368                 {
369                         audio_buffer[buffer] = new double*[file->asset->channels];
371                         for(int channel = 0; channel < file->asset->channels; channel++)
372                         {
373                                 audio_buffer[buffer][channel] = new double[buffer_size];
374                         }
375                 }
376         }
378         if(do_video)
379         {
380                 this->color_model = color_model;
381                 bytes_per_frame = VFrame::calculate_data_size(file->asset->width,
382                         file->asset->height,
383                         -1,
384                         color_model);
386                 video_buffer = new VFrame***[ring_buffers];
387 // printf("FileThread::start_writing 1 %d %d %d %p\n", 
388 // ring_buffers,
389 // file->asset->layers,
390 // buffer_size,
391 // video_buffer);
392                 for(buffer = 0; buffer < ring_buffers; buffer++)
393                 {
394                         video_buffer[buffer] = new VFrame**[file->asset->layers];
395                         for(layer = 0; layer < file->asset->layers; layer++)
396                         {
397                                 video_buffer[buffer][layer] = new VFrame*[buffer_size];
398                                 for(frame = 0; frame < buffer_size; frame++)
399                                 {
400                                         if(compressed)
401                                                 video_buffer[buffer][layer][frame] = new VFrame;
402                                         else
403                                         {
404                                                 video_buffer[buffer][layer][frame] = 
405                                                         new VFrame(0, 
406                                                                 file->asset->width, 
407                                                                 file->asset->height, 
408                                                                 color_model);
409 // printf("FileThread::start_writing 4 %d %d %d %p\n", 
410 // buffer, 
411 // layer, 
412 // frame, 
413 // video_buffer[buffer][layer]);
414                                         }
415                                 }
416                         }
417                 }
418         }
419         file_lock->unlock();
421         for(int i = 0; i < ring_buffers; i++)
422         {
423                 last_buffer[i] = 0;
424         }
426         is_writing = 1;
427         done = 0;
428         Thread::start();
429         return 0;
432 int FileThread::start_reading()
434         if(!is_reading)
435         {
436                 is_reading = 1;
437                 disable_read = 1;
438                 done = 0;
439         }
440         return 0;
443 int FileThread::stop_reading()
445         if(is_reading && Thread::running())
446         {
447                 done = 1;
448                 read_wait_lock->unlock();
449                 Thread::join();
450         }
451         return 0;
454 int FileThread::set_video_position(int64_t position)
456 // If the new position can't be added to the buffer without restarting,
457 // disable reading.
458         if((position < this->start_position ||
459                 position >= this->start_position + MAX_READ_FRAMES) && 
460                 !disable_read)
461         {
462                 disable_read = 1;
463                 read_wait_lock->unlock();
464                 Thread::join();
466                 total_frames = 0;
467                 this->start_position = position;
468         }
469         else
470 // If a sequential read, enable reading
471         if(this->start_position + 1 == position && disable_read)
472         {
473                 this->start_position = position;
474                 disable_read = 0;
475                 Thread::start();
476         }
477         else
478         if(disable_read)
479         {
480                 this->start_position = position;
481         }
483         this->read_position = position;
484         return 0;
487 int FileThread::set_layer(int layer)
489         if(layer != this->layer)
490         {
491                 disable_read = 1;
492                 read_wait_lock->unlock();
493                 Thread::join();
494                 total_frames = 0;
495         }
496         this->layer = layer;
497         return 0;
500 int FileThread::read_frame(VFrame *frame)
502         FileThreadFrame *local_frame = 0;
503         int got_it = 0;
504         int number = 0;
506 //printf("FileThread::read_frame 1\n");
508 // Search thread for frame
509         while(!got_it && !disable_read)
510         {
511                 frame_lock->lock("FileThread::read_frame 1");
512 // printf("FileThread::read_frame: 1 read_position=%lld ", read_position);
513 // for(int i = 0; i < total_frames; i++)
514 // printf("%lld ", read_frames[i]->position);
515 // printf("\n");
516                 for(int i = 0; i < total_frames; i++)
517                 {
518                         local_frame = read_frames[i];
519                         if(local_frame->position == read_position &&
520                                 local_frame->layer == layer &&
521                                 local_frame->frame &&
522                                 local_frame->frame->equal_stacks(frame))
523                         {
524                                 got_it = 1;
525                                 number = i;
526 //printf("FileThread::read_frame 1 %lld\n", local_frame->position);
527                                 break;
528                         }
529                 }
530                 frame_lock->unlock();
532 // Not decoded yet but thread active
533                 if(!got_it && !disable_read)
534                 {
535                         user_wait_lock->lock("FileThread::read_frame");
536                 }
537         }
538 //printf("FileThread::read_frame 2\n");
540         if(got_it)
541         {
542 // Copy image
543                 cmodel_transfer(frame->get_rows(), 
544                         local_frame->frame->get_rows(),
545                         frame->get_y(),
546                         frame->get_u(),
547                         frame->get_v(),
548                         local_frame->frame->get_y(),
549                         local_frame->frame->get_u(),
550                         local_frame->frame->get_v(),
551                         0, 
552                         0, 
553                         local_frame->frame->get_w(), 
554                         local_frame->frame->get_h(),
555                         0, 
556                         0, 
557                         frame->get_w(), 
558                         frame->get_h(),
559                         local_frame->frame->get_color_model(), 
560                         frame->get_color_model(),
561                         0,
562                         local_frame->frame->get_w(),
563                         frame->get_w());
564 // Can't copy stacks because the stack is needed by the plugin requestor.
565                 frame->copy_params(local_frame->frame);
567 // Recycle all frames before current one but not including current one.
568 // This handles redrawing of a single frame but because FileThread has no
569 // notion of a still frame, it has to call read_frame for those.
570                 frame_lock->lock("FileThread::read_frame 1");
571                 FileThreadFrame *new_table[MAX_READ_FRAMES];
572                 int k = 0;
573                 for(int j = number; j < total_frames; j++, k++)
574                 {
575                         new_table[k] = read_frames[j];
576                 }
577                 for(int j = 0; j < number; j++, k++)
578                 {
579                         new_table[k] = read_frames[j];
580                 }
581                 memcpy(read_frames, new_table, sizeof(FileThreadFrame*) * total_frames);
582                 total_frames -= number;
584                 start_position = read_position;
585                 read_position++;
586                 frame_lock->unlock();
587                 read_wait_lock->unlock();
588                 return 0;
589         }
590         else
591         {
592 // printf("FileThread::read_frame 1 color_model=%d disable_read=%d\n", 
593 // frame->get_color_model(), 
594 // disable_read);
595 // Use traditional read function
596                 file->set_video_position(read_position, -1, 1);
597                 file->set_layer(layer, 1);
598                 read_position++;
599                 return file->read_frame(frame, 1);
600         }
601 //printf("FileThread::read_frame 100\n");
604 int64_t FileThread::get_memory_usage()
606         frame_lock->lock("FileThread::get_memory_usage");
607         int64_t result = 0;
608         for(int i = 0; i < MAX_READ_FRAMES; i++)
609                 if(read_frames[i] && read_frames[i]->frame)
610                         result += read_frames[i]->frame->get_data_size();
611         frame_lock->unlock();
612         return result;
616 double** FileThread::get_audio_buffer()
618         swap_buffer();
620         input_lock[current_buffer]->lock("FileThread::get_audio_buffer");
621         return audio_buffer[current_buffer];
624 VFrame*** FileThread::get_video_buffer()
626         swap_buffer();
628         input_lock[current_buffer]->lock("FileThread::get_video_buffer");
629         return video_buffer[current_buffer];
632 int FileThread::write_buffer(long size)
634         output_size[current_buffer] = size;
636 // unlock the output lock
637         output_lock[current_buffer]->unlock();
639         return return_value;
642 int FileThread::swap_buffer()
644         current_buffer++;
645         if(current_buffer >= ring_buffers) current_buffer = 0;