00001 #include "asset.h"
00002 #include "bcsignals.h"
00003 #include "condition.h"
00004 #include "file.h"
00005 #include "filethread.h"
00006 #include "mutex.h"
00007 #include "vframe.h"
00008 #include "videodevice.inc"
00009
00010 #include <string.h>
00011 #include <unistd.h>
00012
00013
00014 FileThreadFrame::FileThreadFrame()
00015 {
00016 position = 0;
00017 frame = 0;
00018 }
00019
00020 FileThreadFrame::~FileThreadFrame()
00021 {
00022 if(frame) delete frame;
00023 }
00024
00025
00026
00027 FileThread::FileThread(File *file, int do_audio, int do_video)
00028 : Thread(1, 0, 0)
00029 {
00030 reset();
00031 create_objects(file,
00032 do_audio,
00033 do_video);
00034 }
00035
00036 FileThread::~FileThread()
00037 {
00038 delete_objects();
00039
00040
00041 }
00042
00043 void FileThread::reset()
00044 {
00045 audio_buffer = 0;
00046 video_buffer = 0;
00047 output_size = 0;
00048 input_lock = 0;
00049 output_lock = 0;
00050 last_buffer = 0;
00051 is_writing = 0;
00052 is_reading = 0;
00053 file_lock = 0;
00054
00055 read_wait_lock = 0;
00056 user_wait_lock = 0;
00057 frame_lock = 0;
00058 total_frames = 0;
00059 done = 0;
00060 disable_read = 1;
00061 start_position = -1;
00062 read_position = 0;
00063 bzero(read_frames, sizeof(FileThreadFrame*) * MAX_READ_FRAMES);
00064 }
00065
00066
00067 void FileThread::create_objects(File *file,
00068 int do_audio,
00069 int do_video)
00070 {
00071 this->file = file;
00072 this->do_audio = do_audio;
00073 this->do_video = do_video;
00074 file_lock = new Mutex("FileThread::file_lock");
00075 read_wait_lock = new Condition(0, "FileThread::read_wait_lock");
00076 user_wait_lock = new Condition(0, "FileThread::user_wait_lock");
00077 frame_lock = new Mutex("FileThread::frame_lock");
00078 for(int i = 0; i < MAX_READ_FRAMES; i++)
00079 read_frames[i] = new FileThreadFrame;
00080 }
00081
00082
00083 void FileThread::delete_objects()
00084 {
00085 if(output_lock)
00086 {
00087 for(int i = 0; i < ring_buffers; i++)
00088 {
00089 delete output_lock[i];
00090 }
00091 delete [] output_lock;
00092 }
00093
00094 if(input_lock)
00095 {
00096 for(int i = 0; i < ring_buffers; i++)
00097 {
00098 delete input_lock[i];
00099 }
00100 delete [] input_lock;
00101 }
00102
00103
00104 if(last_buffer)
00105 delete [] last_buffer;
00106
00107
00108 delete [] output_size;
00109
00110 delete file_lock;
00111
00112
00113 delete read_wait_lock;
00114 delete user_wait_lock;
00115 delete frame_lock;
00116
00117 reset();
00118 }
00119
00120 void FileThread::run()
00121 {
00122 int i, j, result;
00123
00124 if(is_reading)
00125 {
00126
00127 while(!done && !disable_read)
00128 {
00129 frame_lock->lock("FileThread::run 1");
00130 int local_total_frames = total_frames;
00131 frame_lock->unlock();
00132
00133 if(local_total_frames >= MAX_READ_FRAMES)
00134 {
00135 read_wait_lock->lock("FileThread::run");
00136 continue;
00137 }
00138
00139 if(done || disable_read) break;
00140
00141
00142 FileThreadFrame *local_frame = 0;
00143 int64_t local_position = 0;
00144 int local_layer;
00145
00146 frame_lock->lock("FileThread::run 2");
00147
00148 if(total_frames)
00149 local_position = read_frames[total_frames - 1]->position + 1;
00150 else
00151 local_position = start_position;
00152
00153
00154
00155 local_total_frames = total_frames;
00156 local_frame = read_frames[local_total_frames];
00157 local_layer = layer;
00158 frame_lock->unlock();
00159
00160
00161 if(local_frame)
00162 {
00163 file->set_video_position(local_position, -1, 1);
00164 file->set_layer(local_layer, 1);
00165 int supported_colormodel =
00166 file->get_best_colormodel(PLAYBACK_ASYNCHRONOUS);
00167
00168
00169
00170 if(local_frame->frame &&
00171 !local_frame->frame->params_match(file->asset->width,
00172 file->asset->height,
00173 supported_colormodel))
00174 {
00175 delete local_frame->frame;
00176 local_frame->frame = 0;
00177 }
00178
00179 if(!local_frame->frame)
00180 {
00181 local_frame->frame = new VFrame(0,
00182 file->asset->width,
00183 file->asset->height,
00184 supported_colormodel);
00185 }
00186
00187
00188
00189 file->read_frame(local_frame->frame, 1);
00190 local_frame->position = local_position;
00191 local_frame->layer = local_layer;
00192
00193
00194
00195
00196 frame_lock->lock("FileThread::run 3");
00197 FileThreadFrame *old_frame = read_frames[total_frames];
00198 read_frames[local_total_frames] = old_frame;
00199 read_frames[total_frames++] = local_frame;
00200 frame_lock->unlock();
00201
00202
00203 user_wait_lock->unlock();
00204 }
00205 }
00206 }
00207 else
00208 {
00209 while(!done)
00210 {
00211 output_lock[local_buffer]->lock("FileThread::run 1");
00212 return_value = 0;
00213
00214
00215
00216
00217 if(!last_buffer[local_buffer])
00218 {
00219 if(output_size[local_buffer])
00220 {
00221 file_lock->lock("FileThread::run 2");
00222 if(do_audio)
00223 {
00224 result = file->write_samples(audio_buffer[local_buffer],
00225 output_size[local_buffer]);
00226 }
00227 else
00228 if(do_video)
00229 {
00230 result = 0;
00231 if(compressed)
00232 {
00233 for(j = 0; j < file->asset->layers && !result; j++)
00234 for(i = 0; i < output_size[local_buffer] && !result; i++)
00235 result = file->write_compressed_frame(video_buffer[local_buffer][j][i]);
00236 }
00237 else
00238 {
00239 result = file->write_frames(video_buffer[local_buffer],
00240 output_size[local_buffer]);
00241 }
00242 }
00243
00244 file_lock->unlock();
00245 return_value = result;
00246 }
00247 else
00248 return_value = 0;
00249
00250 output_size[local_buffer] = 0;
00251 }
00252 else
00253 done = 1;
00254
00255 input_lock[local_buffer]->unlock();
00256 local_buffer++;
00257 if(local_buffer >= ring_buffers) local_buffer = 0;
00258 }
00259 }
00260 }
00261
00262
00263
00264 int FileThread::stop_writing()
00265 {
00266 if(is_writing)
00267 {
00268 int i, buffer, layer, frame;
00269
00270 swap_buffer();
00271 input_lock[current_buffer]->lock("FileThread::stop_writing 1");
00272
00273 last_buffer[current_buffer] = 1;
00274
00275 for(i = 0; i < ring_buffers; i++)
00276 output_lock[i]->unlock();
00277
00278 swap_buffer();
00279
00280
00281 Thread::join();
00282
00283
00284 file_lock->lock("FileThread::stop_writing 2");
00285 if(do_audio)
00286 {
00287 for(buffer = 0; buffer < ring_buffers; buffer++)
00288 {
00289 for(i = 0; i < file->asset->channels; i++)
00290 delete [] audio_buffer[buffer][i];
00291 delete [] audio_buffer[buffer];
00292 }
00293 delete [] audio_buffer;
00294 audio_buffer = 0;
00295 }
00296
00297
00298
00299
00300
00301
00302 if(do_video)
00303 {
00304 for(buffer = 0; buffer < ring_buffers; buffer++)
00305 {
00306 for(layer = 0; layer < file->asset->layers; layer++)
00307 {
00308 for(frame = 0; frame < buffer_size; frame++)
00309 {
00310 delete video_buffer[buffer][layer][frame];
00311 }
00312 delete [] video_buffer[buffer][layer];
00313 }
00314 delete [] video_buffer[buffer];
00315 }
00316 delete [] video_buffer;
00317 video_buffer = 0;
00318 }
00319
00320 file_lock->unlock();
00321 }
00322 return 0;
00323 }
00324
00325 int FileThread::start_writing(long buffer_size,
00326 int color_model,
00327 int ring_buffers,
00328 int compressed)
00329 {
00330
00331 int buffer, layer, frame;
00332 long bytes_per_frame;
00333
00334 this->ring_buffers = ring_buffers;
00335 this->buffer_size = buffer_size;
00336 this->color_model = color_model;
00337 this->compressed = compressed;
00338 this->current_buffer = ring_buffers - 1;
00339 return_value = 0;
00340 local_buffer = 0;
00341
00342 file_lock->lock("FileThread::start_writing 1");
00343
00344
00345
00346
00347
00348 last_buffer = new int[ring_buffers];
00349 output_size = new long[ring_buffers];
00350
00351
00352 output_lock = new Condition*[ring_buffers];
00353 input_lock = new Condition*[ring_buffers];
00354 for(int i = 0; i < ring_buffers; i++)
00355 {
00356 output_lock[i] = new Condition(0, "FileThread::output_lock");
00357 input_lock[i] = new Condition(1, "FileThread::input_lock");
00358 last_buffer[i] = 0;
00359 output_size[i] = 0;
00360 }
00361
00362
00363
00364 if(do_audio)
00365 {
00366 audio_buffer = new double**[ring_buffers];
00367 for(buffer = 0; buffer < ring_buffers; buffer++)
00368 {
00369 audio_buffer[buffer] = new double*[file->asset->channels];
00370
00371 for(int channel = 0; channel < file->asset->channels; channel++)
00372 {
00373 audio_buffer[buffer][channel] = new double[buffer_size];
00374 }
00375 }
00376 }
00377
00378 if(do_video)
00379 {
00380 this->color_model = color_model;
00381 bytes_per_frame = VFrame::calculate_data_size(file->asset->width,
00382 file->asset->height,
00383 -1,
00384 color_model);
00385
00386 video_buffer = new VFrame***[ring_buffers];
00387
00388
00389
00390
00391
00392 for(buffer = 0; buffer < ring_buffers; buffer++)
00393 {
00394 video_buffer[buffer] = new VFrame**[file->asset->layers];
00395 for(layer = 0; layer < file->asset->layers; layer++)
00396 {
00397 video_buffer[buffer][layer] = new VFrame*[buffer_size];
00398 for(frame = 0; frame < buffer_size; frame++)
00399 {
00400 if(compressed)
00401 video_buffer[buffer][layer][frame] = new VFrame;
00402 else
00403 {
00404 video_buffer[buffer][layer][frame] =
00405 new VFrame(0,
00406 file->asset->width,
00407 file->asset->height,
00408 color_model);
00409
00410
00411
00412
00413
00414 }
00415 }
00416 }
00417 }
00418 }
00419 file_lock->unlock();
00420
00421 for(int i = 0; i < ring_buffers; i++)
00422 {
00423 last_buffer[i] = 0;
00424 }
00425
00426 is_writing = 1;
00427 done = 0;
00428 Thread::start();
00429 return 0;
00430 }
00431
00432 int FileThread::start_reading()
00433 {
00434 if(!is_reading)
00435 {
00436 is_reading = 1;
00437 disable_read = 1;
00438 done = 0;
00439 }
00440 return 0;
00441 }
00442
00443 int FileThread::stop_reading()
00444 {
00445 if(is_reading && Thread::running())
00446 {
00447 done = 1;
00448 read_wait_lock->unlock();
00449 Thread::join();
00450 }
00451 return 0;
00452 }
00453
00454 int FileThread::set_video_position(int64_t position)
00455 {
00456
00457
00458 if((position < this->start_position ||
00459 position >= this->start_position + MAX_READ_FRAMES) &&
00460 !disable_read)
00461 {
00462 disable_read = 1;
00463 read_wait_lock->unlock();
00464 Thread::join();
00465
00466 total_frames = 0;
00467 this->start_position = position;
00468 }
00469 else
00470
00471 if(this->start_position + 1 == position && disable_read)
00472 {
00473 this->start_position = position;
00474 disable_read = 0;
00475 Thread::start();
00476 }
00477 else
00478 if(disable_read)
00479 {
00480 this->start_position = position;
00481 }
00482
00483 this->read_position = position;
00484 return 0;
00485 }
00486
00487 int FileThread::set_layer(int layer)
00488 {
00489 if(layer != this->layer)
00490 {
00491 disable_read = 1;
00492 read_wait_lock->unlock();
00493 Thread::join();
00494 total_frames = 0;
00495 }
00496 this->layer = layer;
00497 return 0;
00498 }
00499
00500 int FileThread::read_frame(VFrame *frame)
00501 {
00502 FileThreadFrame *local_frame = 0;
00503 int got_it = 0;
00504 int number = 0;
00505
00506
00507
00508
00509 while(!got_it && !disable_read)
00510 {
00511 frame_lock->lock("FileThread::read_frame 1");
00512
00513
00514
00515
00516 for(int i = 0; i < total_frames; i++)
00517 {
00518 local_frame = read_frames[i];
00519 if(local_frame->position == read_position &&
00520 local_frame->layer == layer &&
00521 local_frame->frame &&
00522 local_frame->frame->equal_stacks(frame))
00523 {
00524 got_it = 1;
00525 number = i;
00526
00527 break;
00528 }
00529 }
00530 frame_lock->unlock();
00531
00532
00533 if(!got_it && !disable_read)
00534 {
00535 user_wait_lock->lock("FileThread::read_frame");
00536 }
00537 }
00538
00539
00540 if(got_it)
00541 {
00542
00543 cmodel_transfer(frame->get_rows(),
00544 local_frame->frame->get_rows(),
00545 frame->get_y(),
00546 frame->get_u(),
00547 frame->get_v(),
00548 local_frame->frame->get_y(),
00549 local_frame->frame->get_u(),
00550 local_frame->frame->get_v(),
00551 0,
00552 0,
00553 local_frame->frame->get_w(),
00554 local_frame->frame->get_h(),
00555 0,
00556 0,
00557 frame->get_w(),
00558 frame->get_h(),
00559 local_frame->frame->get_color_model(),
00560 frame->get_color_model(),
00561 0,
00562 local_frame->frame->get_w(),
00563 frame->get_w());
00564
00565 frame->copy_params(local_frame->frame);
00566
00567
00568
00569
00570 frame_lock->lock("FileThread::read_frame 1");
00571 FileThreadFrame *new_table[MAX_READ_FRAMES];
00572 int k = 0;
00573 for(int j = number; j < total_frames; j++, k++)
00574 {
00575 new_table[k] = read_frames[j];
00576 }
00577 for(int j = 0; j < number; j++, k++)
00578 {
00579 new_table[k] = read_frames[j];
00580 }
00581 memcpy(read_frames, new_table, sizeof(FileThreadFrame*) * total_frames);
00582 total_frames -= number;
00583
00584 start_position = read_position;
00585 read_position++;
00586 frame_lock->unlock();
00587 read_wait_lock->unlock();
00588 return 0;
00589 }
00590 else
00591 {
00592
00593
00594
00595
00596 file->set_video_position(read_position, -1, 1);
00597 file->set_layer(layer, 1);
00598 read_position++;
00599 return file->read_frame(frame, 1);
00600 }
00601
00602 }
00603
00604 int64_t FileThread::get_memory_usage()
00605 {
00606 frame_lock->lock("FileThread::get_memory_usage");
00607 int64_t result = 0;
00608 for(int i = 0; i < MAX_READ_FRAMES; i++)
00609 if(read_frames[i] && read_frames[i]->frame)
00610 result += read_frames[i]->frame->get_data_size();
00611 frame_lock->unlock();
00612 return result;
00613 }
00614
00615
00616 double** FileThread::get_audio_buffer()
00617 {
00618 swap_buffer();
00619
00620 input_lock[current_buffer]->lock("FileThread::get_audio_buffer");
00621 return audio_buffer[current_buffer];
00622 }
00623
00624 VFrame*** FileThread::get_video_buffer()
00625 {
00626 swap_buffer();
00627
00628 input_lock[current_buffer]->lock("FileThread::get_video_buffer");
00629 return video_buffer[current_buffer];
00630 }
00631
00632 int FileThread::write_buffer(long size)
00633 {
00634 output_size[current_buffer] = size;
00635
00636
00637 output_lock[current_buffer]->unlock();
00638
00639 return return_value;
00640 }
00641
00642 int FileThread::swap_buffer()
00643 {
00644 current_buffer++;
00645 if(current_buffer >= ring_buffers) current_buffer = 0;
00646 }
00647
00648