Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

iec61883output.C

Go to the documentation of this file.
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 // Crazy DV internals
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 // Set PAL mode based on frame height
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 // Create buffers
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 // Next frame
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 // No video.  Put in a fake frame for audio only
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 // Calculate number of samples needed based on given pattern for 
00240 // norm.
00241                 int samples_per_frame = 2048;
00242 
00243 // Encode audio
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 // Write next chunk of current frame
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 // Advance buffer number if possible
00287                         increment_counter(&current_outbuffer);
00288 
00289 // Reuse same buffer next time
00290                         if(!buffer_valid[current_outbuffer])
00291                         {
00292                                 decrement_counter(&current_outbuffer);
00293                         }
00294                         else
00295 // Wait for user to reach current buffer before unlocking any more.
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 //printf("IEC61883Output::write_frame 1\n");
00314 
00315         if(fd <= 0) return;
00316         if(interrupted) return;
00317 
00318 // Encode frame to DV
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 // Exact resolution match.  Don't do colorspace conversion
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 // Convert resolution and color model before compressing
00345                 {
00346                         if(!temp_frame2)
00347                         {
00348                                 int h = input->get_h();
00349 // Default to NTSC if unknown
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(), /* Leave NULL if non existent */
00366                                 input->get_rows(),
00367                                 temp_frame2->get_y(), /* Leave NULL if non existent */
00368                                 temp_frame2->get_u(),
00369                                 temp_frame2->get_v(),
00370                                 input->get_y(), /* Leave NULL if non existent */
00371                                 input->get_u(),
00372                                 input->get_v(),
00373                                 0,        /* Dimensions to capture from input frame */
00374                                 0, 
00375                                 MIN(temp_frame2->get_w(), input->get_w()),
00376                                 MIN(temp_frame2->get_h(), input->get_h()),
00377                                 0,       /* Dimensions to project on output frame */
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,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
00384                                 input->get_bytes_per_line(),       /* For planar use the luma rowspan */
00385                                 temp_frame2->get_bytes_per_line());     /* For planar use the luma rowspan */
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 // Take over buffer table
00412         buffer_lock->lock("IEC61883Output::write_frame 1");
00413         have_video = 1;
00414 // Wait for buffer to become available with timeout
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 // Write buffer if there's room
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(&current_inbuffer);
00435         }
00436         else
00437 // Ignore it if there isn't room.
00438         {
00439                 ;
00440         }
00441 
00442         buffer_lock->unlock();
00443         start_lock->unlock();
00444 //printf("IEC61883Output::write_frame 100\n");
00445 }
00446 
00447 void IEC61883Output::write_samples(char *data, int samples)
00448 {
00449 //printf("IEC61883Output::write_samples 1\n");
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 //printf("IEC61883Output::write_samples 2\n");
00458 
00459 // Check for maximum sample count exceeded
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 //printf("IEC61883Output::write_samples 3\n");
00469 // Take over buffer table
00470         buffer_lock->lock("IEC61883Output::write_samples 1");
00471 // Wait for buffer to become available with timeout
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 //printf("IEC61883Output::write_samples 4 %d\n", audio_samples);
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 //printf("IEC61883Output::write_samples 100\n");
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 // Break write_samples out of a lock
00504         video_lock->unlock();
00505         audio_lock->unlock();
00506 // Playback should stop when the object is deleted.
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 

Generated on Sun Jan 8 13:38:56 2006 for Cinelerra-svn by  doxygen 1.4.4