// Listen for the list_devices property to be set static void on_property_changed( void*, mlt_properties properties, const char *name ) { IDeckLinkIterator* decklinkIterator = NULL; IDeckLink* decklink = NULL; IDeckLinkInput* decklinkInput = NULL; int i = 0; if ( name && !strcmp( name, "list_devices" ) ) mlt_event_block( (mlt_event) mlt_properties_get_data( properties, "list-devices-event", NULL ) ); else return; #ifdef WIN32 if ( FAILED( CoInitialize( NULL ) ) ) return; if ( FAILED( CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator ) ) ) return; #else if ( !( decklinkIterator = CreateDeckLinkIteratorInstance() ) ) return; #endif for ( ; decklinkIterator->Next( &decklink ) == S_OK; i++ ) { if ( decklink->QueryInterface( IID_IDeckLinkInput, (void**) &decklinkInput ) == S_OK ) { DLString name = NULL; if ( decklink->GetModelName( &name ) == S_OK ) { char *name_cstr = getCString( name ); const char *format = "device.%d"; char *key = (char*) calloc( 1, strlen( format ) + 1 ); sprintf( key, format, i ); mlt_properties_set( properties, key, name_cstr ); free( key ); freeDLString( name ); freeCString( name_cstr ); } SAFE_RELEASE( decklinkInput ); } SAFE_RELEASE( decklink ); } SAFE_RELEASE( decklinkIterator ); mlt_properties_set_int( properties, "devices", i ); }
virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( IDeckLinkVideoInputFrame* video, IDeckLinkAudioInputPacket* audio ) { if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "preview" ) && mlt_producer_get_speed( getProducer() ) == 0.0 && !mlt_deque_count( m_queue )) { pthread_cond_broadcast( &m_condition ); return S_OK; } // Create mlt_frame mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) ); // Copy video if ( video ) { if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) ) { int size = video->GetRowBytes() * ( video->GetHeight() + m_vancLines ); void* image = mlt_pool_alloc( size ); void* buffer = 0; unsigned char* p = (unsigned char*) image; int n = size / 2; \ // Initialize VANC lines to nominal black while ( --n ) { *p ++ = 16; *p ++ = 128; } // Capture VANC if ( m_vancLines > 0 ) { IDeckLinkVideoFrameAncillary* vanc = 0; if ( video->GetAncillaryData( &vanc ) == S_OK && vanc ) { for ( int i = 1; i < m_vancLines + 1; i++ ) { if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK ) swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() ); else mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i ); } SAFE_RELEASE(vanc); } } // Capture image video->GetBytes( &buffer ); if ( image && buffer ) { size = video->GetRowBytes() * video->GetHeight(); swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size ); mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release ); } else if ( image ) { mlt_log_verbose( getProducer(), "no video\n" ); mlt_pool_release( image ); } } else { mlt_log_verbose( getProducer(), "no signal\n" ); mlt_frame_close( frame ); frame = 0; } // Get timecode IDeckLinkTimecode* timecode = 0; if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode ) { DLString timecodeString = 0; if ( timecode->GetString( &timecodeString ) == S_OK ) { char* s = getCString( timecodeString ); mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", s ); mlt_log_debug( getProducer(), "timecode %s\n", s ); freeCString( s ); } freeDLString( timecodeString ); SAFE_RELEASE( timecode ); } } else { mlt_log_verbose( getProducer(), "no video\n" ); mlt_frame_close( frame ); frame = 0; } // Copy audio if ( frame && audio ) { int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ); int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t); mlt_audio_format format = mlt_audio_s16; void* pcm = mlt_pool_alloc( size ); void* buffer = 0; audio->GetBytes( &buffer ); if ( buffer ) { memcpy( pcm, buffer, size ); mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release ); mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() ); } else { mlt_log_verbose( getProducer(), "no audio\n" ); mlt_pool_release( pcm ); } } else { mlt_log_verbose( getProducer(), "no audio\n" ); } // Put frame in queue if ( frame ) { int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" ); pthread_mutex_lock( &m_mutex ); if ( mlt_deque_count( m_queue ) < queueMax ) { mlt_deque_push_back( m_queue, frame ); pthread_cond_broadcast( &m_condition ); } else { mlt_frame_close( frame ); mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped ); mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped ); } pthread_mutex_unlock( &m_mutex ); } return S_OK; }
U_CDECL_BEGIN void readTestFile(const char *testFilePath, TestCaseCallback callback) { #if !UCONFIG_NO_REGULAR_EXPRESSIONS UErrorCode status = U_ZERO_ERROR; UXMLParser *parser = UXMLParser::createParser(status); UXMLElement *root = parser->parseFile(testFilePath, status); if (root == NULL) { log_err("Could not open the test data file: %s\n", testFilePath); delete parser; return; } UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case"); UnicodeString test_text = UNICODE_STRING_SIMPLE("test-text"); UnicodeString test_font = UNICODE_STRING_SIMPLE("test-font"); UnicodeString result_glyphs = UNICODE_STRING_SIMPLE("result-glyphs"); UnicodeString result_indices = UNICODE_STRING_SIMPLE("result-indices"); UnicodeString result_positions = UNICODE_STRING_SIMPLE("result-positions"); // test-case attributes UnicodeString id_attr = UNICODE_STRING_SIMPLE("id"); UnicodeString script_attr = UNICODE_STRING_SIMPLE("script"); UnicodeString lang_attr = UNICODE_STRING_SIMPLE("lang"); // test-font attributes UnicodeString name_attr = UNICODE_STRING_SIMPLE("name"); UnicodeString ver_attr = UNICODE_STRING_SIMPLE("version"); UnicodeString cksum_attr = UNICODE_STRING_SIMPLE("checksum"); const UXMLElement *testCase; int32_t tc = 0; while((testCase = root->nextChildElement(tc)) != NULL) { if (testCase->getTagName().compare(test_case) == 0) { char *id = getCString(testCase->getAttribute(id_attr)); char *script = getCString(testCase->getAttribute(script_attr)); char *lang = getCString(testCase->getAttribute(lang_attr)); char *fontName = NULL; char *fontVer = NULL; char *fontCksum = NULL; const UXMLElement *element; int32_t ec = 0; int32_t charCount = 0; // int32_t typoFlags = 3; // kerning + ligatures... UScriptCode scriptCode; le_int32 languageCode = -1; UnicodeString text, glyphs, indices, positions; int32_t glyphCount = 0, indexCount = 0, positionCount = 0; TestResult expected = {0, NULL, NULL, NULL}; uscript_getCode(script, &scriptCode, 1, &status); if (LE_FAILURE(status)) { log_err("invalid script name: %s.\n", script); goto free_c_strings; } if (lang != NULL) { languageCode = getLanguageCode(lang); if (languageCode < 0) { log_err("invalid language name: %s.\n", lang); goto free_c_strings; } } while((element = testCase->nextChildElement(ec)) != NULL) { UnicodeString tag = element->getTagName(); // TODO: make sure that each element is only used once. if (tag.compare(test_font) == 0) { fontName = getCString(element->getAttribute(name_attr)); fontVer = getCString(element->getAttribute(ver_attr)); fontCksum = getCString(element->getAttribute(cksum_attr)); } else if (tag.compare(test_text) == 0) { text = element->getText(TRUE); charCount = text.length(); } else if (tag.compare(result_glyphs) == 0) { glyphs = element->getText(TRUE); } else if (tag.compare(result_indices) == 0) { indices = element->getText(TRUE); } else if (tag.compare(result_positions) == 0) { positions = element->getText(TRUE); } else { // an unknown tag... char *cTag = getCString(&tag); log_info("Test %s: unknown element with tag \"%s\"\n", id, cTag); freeCString(cTag); } } expected.glyphs = (LEGlyphID *) getHexArray(glyphs, glyphCount); expected.indices = (le_int32 *) getHexArray(indices, indexCount); expected.positions = getFloatArray(positions, positionCount); expected.glyphCount = glyphCount; if (glyphCount < charCount || indexCount != glyphCount || positionCount < glyphCount * 2 + 2) { log_err("Test %s: inconsistent input data: charCount = %d, glyphCount = %d, indexCount = %d, positionCount = %d\n", id, charCount, glyphCount, indexCount, positionCount); goto free_expected; }; (*callback)(id, fontName, fontVer, fontCksum, scriptCode, languageCode, text.getBuffer(), charCount, &expected); free_expected: DELETE_ARRAY(expected.positions); DELETE_ARRAY(expected.indices); DELETE_ARRAY(expected.glyphs); free_c_strings: freeCString(fontCksum); freeCString(fontVer); freeCString(fontName); freeCString(lang); freeCString(script); freeCString(id); } } delete root; delete parser; #endif }