00001 #ifdef HAVE_FIREWIRE
00002
00003
00004
00005 #include "audiodevice.h"
00006 #include "condition.h"
00007 #include "iec61883output.h"
00008 #include "mutex.h"
00009 #include "playbackconfig.h"
00010 #include "bctimer.h"
00011 #include "vframe.h"
00012 #include "videodevice.h"
00013
00014 #include <errno.h>
00015 #include <fcntl.h>
00016 #include <string.h>
00017 #include <sys/ioctl.h>
00018 #include <sys/mman.h>
00019 #include <unistd.h>
00020 #include <sys/utsname.h>
00021
00022
00023
00024
00025
00026
00027 #define CIP_N_NTSC 2436
00028 #define CIP_D_NTSC 38400
00029 #define CIP_N_PAL 1
00030 #define CIP_D_PAL 16
00031 #define OUTPUT_SAMPLES 262144
00032 #define BUFFER_TIMEOUT 500000
00033
00034
00035 IEC61883Output::IEC61883Output(AudioDevice *adevice)
00036 : Thread(1, 0, 0)
00037 {
00038 reset();
00039 this->adevice = adevice;
00040 }
00041
00042 IEC61883Output::IEC61883Output(VideoDevice *vdevice)
00043 : Thread(1, 0, 0)
00044 {
00045 reset();
00046 this->vdevice = vdevice;
00047 }
00048
00049 IEC61883Output::~IEC61883Output()
00050 {
00051 if(Thread::running())
00052 {
00053 done = 1;
00054 start_lock->unlock();
00055 Thread::cancel();
00056 Thread::join();
00057 }
00058
00059 if(buffer)
00060 {
00061 for(int i = 0; i < total_buffers; i++)
00062 {
00063 if(buffer[i]) delete [] buffer[i];
00064 }
00065 delete [] buffer;
00066 delete [] buffer_size;
00067 delete [] buffer_valid;
00068 }
00069
00070 if(audio_lock) delete audio_lock;
00071 if(video_lock) delete video_lock;
00072 if(start_lock) delete start_lock;
00073 if(audio_buffer) delete [] audio_buffer;
00074
00075 if(temp_frame) delete temp_frame;
00076 if(temp_frame2) delete temp_frame2;
00077 if(video_encoder) dv_delete(video_encoder);
00078 if(audio_encoder) dv_delete(audio_encoder);
00079 if(buffer_lock) delete buffer_lock;
00080 if(position_lock) delete position_lock;
00081 if(frame) iec61883_dv_close(frame);
00082 if(handle) raw1394_destroy_handle(handle);
00083 }
00084
00085
00086 void IEC61883Output::reset()
00087 {
00088 handle = 0;
00089 fd = 0;
00090 frame = 0;
00091 out_position = 0;
00092 out_buffer = 0;
00093 out_size = 0;
00094
00095 buffer = 0;
00096 buffer_size = 0;
00097 total_buffers = 0;
00098 current_inbuffer = 0;
00099 current_outbuffer = 0;
00100 done = 0;
00101 audio_lock = 0;
00102 video_lock = 0;
00103 start_lock = 0;
00104 buffer_lock = 0;
00105 position_lock = 0;
00106 video_encoder = 0;
00107 audio_encoder = 0;
00108 audio_buffer = 0;
00109 audio_samples = 0;
00110 temp_frame = 0;
00111 temp_frame2 = 0;
00112 audio_position = 0;
00113 interrupted = 0;
00114 have_video = 0;
00115 adevice = 0;
00116 vdevice = 0;
00117 is_pal = 0;
00118 }
00119
00120
00121
00122 static int read_frame_static(unsigned char *data, int n, unsigned int dropped, void *ptr)
00123 {
00124 IEC61883Output *output = (IEC61883Output*)ptr;
00125 return output->read_frame(data, n, dropped);
00126 }
00127
00128
00129
00130
00131
00132 int IEC61883Output::open(int port,
00133 int channel,
00134 int length,
00135 int channels,
00136 int bits,
00137 int samplerate,
00138 int syt)
00139 {
00140 this->channels = channels;
00141 this->bits = bits;
00142 this->samplerate = samplerate;
00143 this->total_buffers = length;
00144 this->syt = syt;
00145
00146
00147 if(vdevice) is_pal = (vdevice->out_h == 576);
00148
00149
00150
00151
00152 if(!handle)
00153 {
00154 handle = raw1394_new_handle_on_port(port);
00155 if(handle)
00156 {
00157 frame = iec61883_dv_xmit_init(handle,
00158 is_pal,
00159 read_frame_static,
00160 (void *)this);
00161 if(frame)
00162 {
00163 if(!iec61883_dv_xmit_start(frame, channel))
00164 {
00165 fd = raw1394_get_fd(handle);
00166 }
00167 }
00168 }
00169
00170
00171 buffer = new char*[total_buffers];
00172 for(int i = 0; i < length; i++)
00173 buffer[i] = new char[DV_PAL_SIZE];
00174 buffer_size = new int[total_buffers];
00175 buffer_valid = new int[total_buffers];
00176 bzero(buffer_size, sizeof(int) * total_buffers);
00177 bzero(buffer_valid, sizeof(int) * total_buffers);
00178 bzero(buffer, sizeof(char*) * total_buffers);
00179 video_lock = new Condition(0, "IEC61883Output::video_lock");
00180 audio_lock = new Condition(0, "IEC61883Output::audio_lock");
00181 start_lock = new Condition(0, "IEC61883Output::start_lock");
00182 buffer_lock = new Mutex("IEC61883Output::buffer_lock");
00183 position_lock = new Mutex("IEC61883Output::position_lock");
00184 encoder = dv_new();
00185 audio_buffer = new char[OUTPUT_SAMPLES * channels * bits / 8];
00186 Thread::start();
00187 }
00188 return 0;
00189 }
00190
00191 void IEC61883Output::run()
00192 {
00193 Thread::enable_cancel();
00194 start_lock->lock("IEC61883Output::run");
00195 Thread::disable_cancel();
00196
00197 while(!done)
00198 {
00199 struct timeval tv;
00200 fd_set rfds;
00201 FD_ZERO (&rfds);
00202 FD_SET (fd, &rfds);
00203 tv.tv_sec = 0;
00204 tv.tv_usec = 20000;
00205 if(select(fd + 1, &rfds, 0, 0, &tv) > 0)
00206 raw1394_loop_iterate (handle);
00207 }
00208 }
00209
00210
00211
00212 int IEC61883Output::read_frame(unsigned char *data, int n, unsigned int dropped)
00213 {
00214
00215 if(!out_buffer || out_position + 480 > out_size)
00216 {
00217 buffer_lock->lock("IEC61883Output read_frame 1");
00218
00219 out_buffer = buffer[current_outbuffer];
00220 out_size = buffer_size[current_outbuffer];
00221 out_position = 0;
00222
00223
00224
00225 if(!have_video)
00226 {
00227 #include "data/fake_ntsc_dv.h"
00228 out_size = sizeof(fake_ntsc_dv) - 4;
00229 out_buffer = (char*)fake_ntsc_dv + 4;
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 int samples_per_frame = 2048;
00242
00243
00244 if(audio_samples > samples_per_frame)
00245 {
00246 int samples_written = dv_write_audio(encoder,
00247 (unsigned char*)out_buffer,
00248 (unsigned char*)audio_buffer,
00249 samples_per_frame,
00250 channels,
00251 bits,
00252 samplerate,
00253 is_pal ? DV_PAL : DV_NTSC);
00254 memcpy(audio_buffer,
00255 audio_buffer + samples_written * bits * channels / 8,
00256 (audio_samples - samples_written) * bits * channels / 8);
00257 audio_samples -= samples_written;
00258 position_lock->lock("IEC61883Output::run");
00259 audio_position += samples_written;
00260 position_lock->unlock();
00261
00262
00263 audio_lock->unlock();
00264 }
00265
00266
00267 buffer_lock->unlock();
00268 }
00269
00270
00271
00272
00273
00274 if(out_buffer && out_position + 480 <= out_size)
00275 {
00276 memcpy(data, out_buffer + out_position, 480);
00277 out_position += 480;
00278
00279
00280
00281 if(out_position >= out_size)
00282 {
00283 buffer_lock->lock("IEC61883Output read_frame 2");
00284 buffer_valid[current_outbuffer] = 0;
00285
00286
00287 increment_counter(¤t_outbuffer);
00288
00289
00290 if(!buffer_valid[current_outbuffer])
00291 {
00292 decrement_counter(¤t_outbuffer);
00293 }
00294 else
00295
00296 {
00297 video_lock->unlock();
00298 }
00299
00300 buffer_lock->unlock();
00301 }
00302 }
00303 }
00304
00305
00306
00307
00308 void IEC61883Output::write_frame(VFrame *input)
00309 {
00310 VFrame *ptr = 0;
00311 int result = 0;
00312
00313
00314
00315 if(fd <= 0) return;
00316 if(interrupted) return;
00317
00318
00319 if(input->get_color_model() != BC_COMPRESSED)
00320 {
00321 if(!temp_frame) temp_frame = new VFrame;
00322 if(!encoder) encoder = dv_new();
00323 ptr = temp_frame;
00324
00325
00326 if(input->get_color_model() == BC_YUV422 &&
00327 input->get_w() == 720 &&
00328 (input->get_h() == 480 ||
00329 input->get_h() == 576))
00330 {
00331 int norm = is_pal ? DV_PAL : DV_NTSC;
00332 int data_size = is_pal ? DV_PAL_SIZE : DV_NTSC_SIZE;
00333 temp_frame->allocate_compressed_data(data_size);
00334 temp_frame->set_compressed_size(data_size);
00335
00336 dv_write_video(encoder,
00337 temp_frame->get_data(),
00338 input->get_rows(),
00339 BC_YUV422,
00340 norm);
00341 ptr = temp_frame;
00342 }
00343 else
00344
00345 {
00346 if(!temp_frame2)
00347 {
00348 int h = input->get_h();
00349
00350 if(h != 480 && h != 576) h = 480;
00351
00352 temp_frame2 = new VFrame(0,
00353 720,
00354 h,
00355 BC_YUV422);
00356
00357 }
00358
00359 int norm = is_pal ? DV_PAL : DV_NTSC;
00360 int data_size = is_pal ? DV_PAL_SIZE : DV_NTSC_SIZE;
00361 temp_frame->allocate_compressed_data(data_size);
00362 temp_frame->set_compressed_size(data_size);
00363
00364
00365 cmodel_transfer(temp_frame2->get_rows(),
00366 input->get_rows(),
00367 temp_frame2->get_y(),
00368 temp_frame2->get_u(),
00369 temp_frame2->get_v(),
00370 input->get_y(),
00371 input->get_u(),
00372 input->get_v(),
00373 0,
00374 0,
00375 MIN(temp_frame2->get_w(), input->get_w()),
00376 MIN(temp_frame2->get_h(), input->get_h()),
00377 0,
00378 0,
00379 MIN(temp_frame2->get_w(), input->get_w()),
00380 MIN(temp_frame2->get_h(), input->get_h()),
00381 input->get_color_model(),
00382 BC_YUV422,
00383 0,
00384 input->get_bytes_per_line(),
00385 temp_frame2->get_bytes_per_line());
00386
00387 dv_write_video(encoder,
00388 temp_frame->get_data(),
00389 temp_frame2->get_rows(),
00390 BC_YUV422,
00391 norm);
00392
00393
00394
00395 ptr = temp_frame;
00396 }
00397 }
00398 else
00399 ptr = input;
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 buffer_lock->lock("IEC61883Output::write_frame 1");
00413 have_video = 1;
00414
00415 while(buffer_valid[current_inbuffer] && !result && !interrupted)
00416 {
00417 buffer_lock->unlock();
00418 result = video_lock->timed_lock(BUFFER_TIMEOUT);
00419 buffer_lock->lock("IEC61883Output::write_frame 2");
00420 }
00421
00422
00423
00424
00425 if(!buffer_valid[current_inbuffer])
00426 {
00427 if(!buffer[current_inbuffer])
00428 {
00429 buffer[current_inbuffer] = new char[ptr->get_compressed_size()];
00430 buffer_size[current_inbuffer] = ptr->get_compressed_size();
00431 }
00432 memcpy(buffer[current_inbuffer], ptr->get_data(), ptr->get_compressed_size());
00433 buffer_valid[current_inbuffer] = 1;
00434 increment_counter(¤t_inbuffer);
00435 }
00436 else
00437
00438 {
00439 ;
00440 }
00441
00442 buffer_lock->unlock();
00443 start_lock->unlock();
00444
00445 }
00446
00447 void IEC61883Output::write_samples(char *data, int samples)
00448 {
00449
00450 int result = 0;
00451 int timeout = (int64_t)samples *
00452 (int64_t)1000000 *
00453 (int64_t)2 /
00454 (int64_t)samplerate;
00455 if(interrupted) return;
00456
00457
00458
00459
00460 if(samples > OUTPUT_SAMPLES)
00461 {
00462 printf("IEC61883Output::write_samples samples=%d > OUTPUT_SAMPLES=%d\n",
00463 samples,
00464 OUTPUT_SAMPLES);
00465 return;
00466 }
00467
00468
00469
00470 buffer_lock->lock("IEC61883Output::write_samples 1");
00471
00472 while(audio_samples > OUTPUT_SAMPLES - samples && !result && !interrupted)
00473 {
00474 buffer_lock->unlock();
00475 result = audio_lock->timed_lock(BUFFER_TIMEOUT);
00476 buffer_lock->lock("IEC61883Output::write_samples 2");
00477 }
00478
00479 if(!interrupted && audio_samples <= OUTPUT_SAMPLES - samples)
00480 {
00481
00482 memcpy(audio_buffer + audio_samples * channels * bits / 8,
00483 data,
00484 samples * channels * bits / 8);
00485 audio_samples += samples;
00486 }
00487 buffer_lock->unlock();
00488 start_lock->unlock();
00489
00490 }
00491
00492 long IEC61883Output::get_audio_position()
00493 {
00494 position_lock->lock("IEC61883Output::get_audio_position");
00495 long result = audio_position;
00496 position_lock->unlock();
00497 return result;
00498 }
00499
00500 void IEC61883Output::interrupt()
00501 {
00502 interrupted = 1;
00503
00504 video_lock->unlock();
00505 audio_lock->unlock();
00506
00507 }
00508
00509 void IEC61883Output::flush()
00510 {
00511
00512 }
00513
00514 void IEC61883Output::increment_counter(int *counter)
00515 {
00516 (*counter)++;
00517 if(*counter >= total_buffers) *counter = 0;
00518 }
00519
00520 void IEC61883Output::decrement_counter(int *counter)
00521 {
00522 (*counter)--;
00523 if(*counter < 0) *counter = total_buffers - 1;
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 #endif // HAVE_FIREWIRE
00537
00538
00539
00540
00541
00542