void * loop_out(void * arg) { loop_handle * hd = (loop_handle *) arg; sv_fifo_bufferinfo infodst; sv_fifo_info status_dst; int lastdrop_dst = 0; int displaytick = 0; int res = SV_OK; int bufferid; int fifo_running = FALSE; int flip = 0; dvs_cond_wait(&hd->common.ready, &hd->common.lock, FALSE); while (hd->running) { // check for sync is detected and if genlocked when sync is on the refin while((res == SV_ERROR_SYNC_MISSING) || sv_fifo_sanitycheck(hd->svdst, hd->fifodst) == SV_ERROR_SYNC_MISSING && hd->running) { if(fifo_running) { fifo_running = FALSE; printf("WARNING: lost genlock! Output fifo stopped.\n"); res = sv_fifo_stop(hd->svdst, hd->fifodst, SV_FIFO_FLAG_FLUSH); if(res != SV_OK) { printf("sv_fifo_stop(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } res = sv_fifo_reset(hd->svdst, hd->fifodst); if(res != SV_OK) { printf("sv_fifo_reset(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } } sv_fifo_vsyncwait(hd->svdst, hd->fifodst); } if(!fifo_running) { printf("====> Restarting output fifo. <=====\n"); #if 0 res = sv_fifo_free(hd->svdst, hd->fifodst); if(res != SV_OK) { printf("sv_fifo_reset(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } // Init output FIFO. res = sv_fifo_init(hd->svdst, &hd->fifodst, FALSE, FALSE, TRUE, (hd->bancstreamer ? SV_FIFO_FLAG_ANC : 0), 0 ); if(res != SV_OK) { printf("sv_fifo_init(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; return; } res = sv_fifo_sanitylevel(hd->svdst, hd->fifodst, SV_FIFO_SANITY_LEVEL_FATAL, SV_FIFO_SANITY_VERSION_1); if(res != SV_OK) { printf("sv_fifo_sanitylevel(dst) failed %d '%s'\n", res, sv_geterrortext(res)); } #endif res = sv_fifo_startex(hd->svdst, hd->fifodst, &displaytick, NULL, NULL, NULL); if(res != SV_OK) { printf("sv_fifo_start(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } fifo_running = TRUE; } res = sv_fifo_getbuffer(hd->svdst, hd->fifodst, &hd->bufdst, NULL, SV_FIFO_FLAG_NODMAADDR | (hd->bancstreamer ? SV_FIFO_FLAG_ANC : 0) | (hd->bvideoonly ? SV_FIFO_FLAG_VIDEOONLY : 0) | (hd->baudioonly ? SV_FIFO_FLAG_AUDIOONLY : 0) | (hd->bfieldbased ? SV_FIFO_FLAG_FIELD : 0) | // enable field-based mode (hd->bvideoonly ? 0 : SV_FIFO_FLAG_SETAUDIOSIZE) | (hd->bottom2top ? SV_FIFO_FLAG_STORAGEMODE : 0) ); switch(res) { case SV_ERROR_SYNC_MISSING: continue; break; default: if(res != SV_OK) { printf("sv_fifo_getbuffer(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } break; } if(hd->bottom2top) { hd->bufdst->storage.storagemode = hd->storage.videomode & (SV_MODE_COLOR_MASK|SV_MODE_NBIT_MASK|SV_MODE_STORAGE_FRAME|SV_MODE_STORAGE_BOTTOM2TOP); hd->bufdst->storage.xsize = hd->storage.storagexsize; hd->bufdst->storage.ysize = hd->storage.storageysize; if(flip) { hd->bufdst->storage.storagemode |= SV_MODE_STORAGE_BOTTOM2TOP; } else { hd->bufdst->storage.storagemode &= ~SV_MODE_STORAGE_BOTTOM2TOP; } flip = (displaytick / 100) & 1; } dvs_mutex_enter(&hd->common.lock); bufferid = get_bufferid(hd, displaytick, hd->ndelay ); dvs_mutex_leave(&hd->common.lock); fill_buffer(hd, FALSE, hd->bufdst, bufferid); if(hd->banc && (bufferid >= 0)) { //Get list anc_element_t * current_element = &hd->anclist[bufferid]; //Try to get anc packets while( current_element->valid ) { current_element->valid = 0; res = sv_fifo_anc( hd->svsrc, hd->fifodst, hd->bufdst, ¤t_element->ancbuffer ); if( res == SV_OK ) { //Log if( hd->bverbose ) { printf("Displayed anc_element. Buffer:%d, DID:0x%x, SDID:0x%x\n", bufferid, current_element->ancbuffer.did, current_element->ancbuffer.sdid ); } if( current_element->next ) { current_element = current_element->next; } } } } res = sv_fifo_putbuffer(hd->svdst, hd->fifodst, hd->bufdst, &infodst); if(res != SV_OK) { printf("sv_fifo_putbuffer(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; break; } // Calculate next output tick. displaytick = infodst.when + hd->vinterlace; res = sv_fifo_status(hd->svdst, hd->fifodst, &status_dst); if(res != SV_OK) { printf("sv_fifo_status(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; break; } // Save output delay hd->outdelay_info = infodst.when - status_dst.displaytick; if(!hd->bverbose) { printf("\rDmaloop: %s in-delay:%2d/%d ticks out-delay:%2d ticks ", (bufferid!=-1) ? "running" : "no buffer", hd->indelay_info, hd->inavail_info, hd->outdelay_info); } if(hd->bverbose || (status_dst.dropped > lastdrop_dst)) { printf("ID %2d - out %06d %d %d %d (%u)\n", bufferid, infodst.when, status_dst.nbuffers, status_dst.availbuffers, status_dst.dropped - lastdrop_dst, infodst.clock_low); } // Report dropped frames in output FIFO. if(status_dst.dropped > lastdrop_dst) { printf("output fifo dropped - delay might have changed\n"); } lastdrop_dst = status_dst.dropped; /* * Wait until I need a new buffer */ if(hd->bfieldbased || hd->bdualsdi) { while(hd->running && ((status_dst.nbuffers - status_dst.availbuffers) > 3/*Fields*/)) { // Wait for next vsync res = sv_fifo_vsyncwait(hd->svdst, hd->fifodst); if(res != SV_OK) { printf("sv_fifo_vsyncwait(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } // Check buffer count res = sv_fifo_status(hd->svdst, hd->fifodst, &status_dst); if(res != SV_OK) { printf("sv_fifo_status(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } } } else { while(hd->running && ((status_dst.nbuffers - status_dst.availbuffers) > 2 /*Frames*/)) { // Wait for next vsync res = sv_fifo_vsyncwait(hd->svdst, hd->fifodst); if(res != SV_OK) { printf("sv_fifo_vsyncwait(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } // Check buffer count res = sv_fifo_status(hd->svdst, hd->fifodst, &status_dst); if(res != SV_OK) { printf("sv_fifo_status(dst) failed %d '%s'\n", res, sv_geterrortext(res)); hd->running = FALSE; } } } } res = sv_fifo_stop(hd->svdst, hd->fifodst, SV_FIFO_FLAG_FLUSH); if(res != SV_OK) { printf("sv_fifo_stop(dst) failed %d '%s'\n", res, sv_geterrortext(res)); } hd->exitcode = TRUE; dvs_thread_exit(&hd->exitcode, &hd->finish); return NULL; }
// card number passed as void * (using cast) static void * sdi_monitor(void *arg) { long card = (long)arg; sv_handle *sv = a_sv[card]; sv_fifo *poutput; sv_info status_info; sv_storageinfo storage_info; printf("card = %ld\n", card); SV_CHECK( sv_status( sv, &status_info) ); SV_CHECK( sv_storage_status(sv, 0, NULL, &storage_info, sizeof(storage_info), 0) ); SV_CHECK( sv_fifo_init( sv, &poutput, // FIFO handle FALSE, // bInput (FALSE for playback) TRUE, // bShared (TRUE for input/output share memory) TRUE, // bDMA FALSE, // reserved 0) ); // nFrames (0 means use maximum) SV_CHECK( sv_fifo_start(sv, poutput) ); // Loop forever reading frames and displaying. // This will not use 99% CPU since sv_fifo_getbuffer() will block // until a hardware buffer frame is available. int last_res = -1; while (1) { int res; if ((res = read_picture(card, sv, poutput)) != SV_OK) { // Display error only when things change if (res != last_res) { fprintf(stderr, "card %ld: failed to capture video: (%d) %s\n", card, res, res == SV_ERROR_INPUT_VIDEO_NOSIGNAL ? "INPUT_VIDEO_NOSIGNAL" : sv_geterrortext(res)); // reset FIFO if error indicates FIFO problem if (res == SV_ERROR_FIFO_PUTBUFFER) { fprintf(stderr, "SV_ERROR_FIFO_PUTBUFFER: restarting fifo\n"); SV_CHECK( sv_fifo_reset(sv, poutput) ); SV_CHECK( sv_fifo_start(sv, poutput) ); } } last_res = res; usleep( 2 * 1000 * 1000); // 2 second poll continue; } // Only display OK message once if (res != last_res && res == SV_OK) { fprintf(stderr, "card %ld: Video signal OK\n", card); } last_res = res; } return NULL; }
int loop_init(loop_handle * hd) { sv_fifo_configinfo config; int modesrc = 0; int modedst = 0; int syncmode = 0; int res; int i; char anclayout[1024]; // Open first card. hd->svsrc = sv_open(""); if (hd->svsrc == NULL) { printf("loop_init: sv_open(\"\") failed\n"); loop_exit(hd); return FALSE; } if(hd->buse2cards) { // Open second card. hd->svdst = sv_open("PCI,card:1"); if(hd->svdst == NULL) { printf("loop_init: sv_open(\"PCI.card:1\") failed\n"); loop_exit(hd); return FALSE; } } else { // Use first card for output as well. hd->svdst = hd->svsrc; } // Get current videomode from first card. res = sv_option_get(hd->svsrc, SV_OPTION_VIDEOMODE, &modesrc); if(res != SV_OK) { printf("loop_init: sv_option_get() failed\n"); loop_exit(hd); return FALSE; } // Get current videomode from second card. res = sv_option_get(hd->svdst, SV_OPTION_VIDEOMODE, &modedst); if(res != SV_OK) { printf("loop_init: sv_option_get() failed\n"); loop_exit(hd); return FALSE; } // Compare if both videomodes do match. if((modesrc & SV_MODE_MASK) != (modedst & SV_MODE_MASK)) { printf("loop_init: Raster of source and destination board do not match.\n"); loop_exit(hd); return FALSE; } // Check sync mode res = sv_query(hd->svsrc, SV_QUERY_SYNCMODE, 0, &syncmode); if(res != SV_OK) { printf("loop_init: sv_query(SV_QUERY_SYNCMODE) failed\n"); loop_exit(hd); return FALSE; } if(syncmode == SV_SYNC_INTERNAL) { printf("Error:\tPlease configure another sync mode,\n\tit is not possible to have a stable in to out delay with SV_SYNC_INTERNAL.\n"); loop_exit(hd); return FALSE; } switch(modesrc & SV_MODE_MASK) { case SV_MODE_SMPTE274_47P: case SV_MODE_SMPTE274_48P: case SV_MODE_SMPTE274_50P: case SV_MODE_SMPTE274_59P: case SV_MODE_SMPTE274_60P: case SV_MODE_SMPTE274_71P: case SV_MODE_SMPTE274_72P: hd->bdualsdi = TRUE; break; } // Get information about current raster. res = sv_storage_status(hd->svsrc, 0, NULL, &hd->storage, sizeof(sv_storageinfo), 0); if(res != SV_OK) { printf("loop_init: sv_storage_status() failed = %d '%s'\n", res, sv_geterrortext(res)); } // How many ticks does a frame last? hd->vinterlace = hd->storage.vinterlace; //frame to field correction hd->ndelay = hd->ndelay * hd->storage.vinterlace; //fieldbased correction if(hd->bfieldbased) { hd->vinterlace = 1; } if(hd->banc) { // Disable the fifo ancgenerator because else you will get double packets in loopback res = sv_option_set(hd->svdst, SV_OPTION_ANCGENERATOR, SV_ANCDATA_DISABLE ); if(res != SV_OK) { printf("loop_init: sv_option_set() failed\n"); loop_exit(hd); return FALSE; } } // Init input FIFO. res = sv_fifo_init(hd->svsrc, &hd->fifosrc, TRUE, // input FIFO FALSE, TRUE, // enable DMA mode (hd->bancstreamer ? SV_FIFO_FLAG_ANC : 0) | (hd->bfieldbased ? SV_FIFO_FLAG_FIELD : 0), // enable field-based mode 0 // use maximum available buffers ); if(res != SV_OK) { printf("sv_fifo_init(src) failed %d '%s'\n", res, sv_geterrortext(res)); loop_exit(hd); return FALSE; } res = sv_fifo_sanitylevel(hd->svsrc, hd->fifosrc, SV_FIFO_SANITY_LEVEL_FATAL, SV_FIFO_SANITY_VERSION_1); if(res != SV_OK) { printf("sv_fifo_sanitylevel(dst) failed %d '%s'\n", res, sv_geterrortext(res)); } // Init output FIFO. res = sv_fifo_init(hd->svdst, &hd->fifodst, FALSE, // output FIFO FALSE, TRUE, // enable DMA mode (hd->bancstreamer ? SV_FIFO_FLAG_ANC : 0), 0 // use maximum available buffers ); if(res != SV_OK) { printf("sv_fifo_init(dst) failed %d '%s'\n", res, sv_geterrortext(res)); loop_exit(hd); return FALSE; } res = sv_fifo_sanitylevel(hd->svdst, hd->fifodst, SV_FIFO_SANITY_LEVEL_FATAL, SV_FIFO_SANITY_VERSION_1); if(res != SV_OK) { printf("sv_fifo_sanitylevel(dst) failed %d '%s'\n", res, sv_geterrortext(res)); } if(hd->bverbose && hd->bancstreamer) { int required = 0; res = sv_fifo_anclayout(hd->svsrc, hd->fifosrc, anclayout, sizeof(anclayout), &required); if(res == SV_ERROR_BUFFERSIZE) { printf("sv_fifo_anclayout(src) buffer too small (required %d)\n", required); } else if(res != SV_OK) { printf("sv_fifo_anclayout(src) failed %d '%s'\n", res, sv_geterrortext(res)); } else { printf("ANC layout (input):\n%s\n", anclayout); } res = sv_fifo_anclayout(hd->svdst, hd->fifodst, anclayout, sizeof(anclayout), &required); if(res == SV_ERROR_BUFFERSIZE) { printf("sv_fifo_anclayout(dst) buffer too small (required %d)\n", required); } else if(res != SV_OK) { printf("sv_fifo_anclayout(dst) failed %d '%s'\n", res, sv_geterrortext(res)); } else { printf("ANC layout (output):\n%s\n", anclayout); } } // Fetch some information about FIFO buffer sizes. res = sv_fifo_configstatus(hd->svsrc, hd->fifosrc, &config); if(res != SV_OK) { printf("sv_fifo_configstatus(src) failed %d '%s'\n", res, sv_geterrortext(res)); loop_exit(hd); return FALSE; } // Allocate sufficient memory for video and audio data. for(i = 0; i < MAX_ID; i++) { memset( &hd->anclist[i], 0, sizeof(hd->anclist[i]) ); hd->livebuffer_org[i] = malloc(config.vbuffersize + config.abuffersize + (config.dmaalignment-1)); hd->livebuffer[i] = (char *)((uintptr)(hd->livebuffer_org[i] + (config.dmaalignment-1)) & ~(uintptr)(config.dmaalignment-1)); if(!hd->livebuffer_org[i]) { printf("malloc(%d) livebuffer %d failed\n", config.vbuffersize + config.abuffersize + (config.dmaalignment-1), i); loop_exit(hd); return FALSE; } if(config.ancbuffersize && hd->bancstreamer) { hd->ancbuffer_org[i] = malloc(config.ancbuffersize + (config.dmaalignment-1)); hd->ancbuffer[i] = (char *)((uintptr)(hd->ancbuffer_org[i] + (config.dmaalignment-1)) & ~(uintptr)(config.dmaalignment-1)); if(!hd->ancbuffer_org[i]) { printf("malloc(%d) ancbuffer %d failed\n", config.ancbuffersize + (config.dmaalignment-1), i); loop_exit(hd); return FALSE; } } } // Allocate sufficient memory for video and audio data. hd->blackbuffer_org = malloc(config.vbuffersize + config.abuffersize + (config.dmaalignment-1)); hd->blackbuffer = (char *)((uintptr)(hd->blackbuffer_org + (config.dmaalignment-1)) & ~(uintptr)(config.dmaalignment-1)); if(!hd->blackbuffer_org) { printf("malloc(%d) blackbuffer failed\n", config.vbuffersize + config.abuffersize + (config.dmaalignment-1)); loop_exit(hd); return FALSE; } memset(hd->blackbuffer_org, 0, config.vbuffersize + config.abuffersize + (config.dmaalignment-1)); // Allocate sufficient memory for video and audio data. hd->nobuffer_org = malloc(config.vbuffersize + config.abuffersize + (config.dmaalignment-1)); hd->nobuffer = (char *)((uintptr)(hd->nobuffer_org + (config.dmaalignment-1)) & ~(uintptr)(config.dmaalignment-1)); if(!hd->nobuffer_org) { printf("malloc(%d) nobuffer failed\n", config.vbuffersize + config.abuffersize + (config.dmaalignment-1)); loop_exit(hd); return FALSE; } memset(hd->nobuffer_org, 0xff, config.vbuffersize + config.abuffersize + (config.dmaalignment-1)); dvs_mutex_init(&hd->common.lock); dvs_cond_init(&hd->common.ready); return TRUE; }