Package: tvtime Version: 1.0.2-6 Severity: normal Tags: patch Justification: Policy 9.3.2 User: ubuntu-de...@lists.ubuntu.com Usertags: origin-ubuntu maverick ubuntu-patch
Hi, in ubuntu we applied the following changes: - Add quilt support. - debian/patches/tvtime-1.0.1-savematte.patch: tvtime does not rebember matte settings (LP: #313570). - debian/patches/desktop_file.patch: Fix docs/net-tvtime.desktop as Freedesktop.org's per-spec. - Add tvtime-1.0.2-alsa.patch to enable audio routing from external TV card; - debian/control: Build-depend on autoconf, automake, libasound2-dev, libtool. - debian/rules: Call autoreconf to re-generate the configure script. And we think you should too. Attaching the patches.
Description: Fix broken behaviour, tvtime doesn't remember matte settings. Origin: http://sourceforge.net/tracker/?func=detail&atid=506989&aid=1634306&group_id=64301 Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/tvtime/+bug/313570 Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=526639 Reviewed-by: Alessio Treglia <quadris...@ubuntu.com> Last-Update: 2009-09-27 --- src/commands.c | 9 + src/commands.h | 1 src/tvtime.c | 266 +++++++++++++++++++++++++------------------------------ src/tvtimeconf.c | 29 +++++ src/tvtimeconf.h | 1 src/videoinput.c | 17 +++ src/videoinput.h | 2 src/xvoutput.c | 2 8 files changed, 182 insertions(+), 145 deletions(-) --- tvtime-1.0.2.orig/src/commands.c +++ tvtime-1.0.2/src/commands.c @@ -128,6 +128,7 @@ struct commands_s { int togglepulldowndetection; int togglematte; int togglequiet; + int changedoverscan; int framerate; int scan_channels; int pause; @@ -2900,7 +2901,7 @@ void commands_handle( commands_t *cmd, i case TVTIME_OVERSCAN_DOWN: cmd->overscan = cmd->overscan + ( (tvtime_cmd == TVTIME_OVERSCAN_UP) ? 0.0025 : -0.0025 ); if( cmd->overscan > 0.4 ) cmd->overscan = 0.4; if( cmd->overscan < 0.0 ) cmd->overscan = 0.0; - + cmd->changedoverscan = 1; if( cmd->osd ) { char message[ 200 ]; snprintf( message, sizeof( message ), _("Overscan: %.1f%%"), @@ -3492,6 +3493,7 @@ void commands_next_frame( commands_t *cm cmd->togglepulldowndetection = 0; cmd->togglematte = 0; cmd->togglequiet = 0; + cmd->changedoverscan = 0; cmd->resizewindow = 0; cmd->setdeinterlacer = 0; cmd->setfreqtable = 0; @@ -3539,6 +3541,11 @@ int commands_toggle_aspect( commands_t * return cmd->toggleaspect; } +int commands_get_changed_overscan( commands_t *cmd ) +{ + return cmd->changedoverscan; +} + int commands_toggle_alwaysontop( commands_t *cmd ) { return cmd->togglealwaysontop; --- tvtime-1.0.2.orig/src/commands.h +++ tvtime-1.0.2/src/commands.h @@ -64,6 +64,7 @@ void commands_set_pulldown_alg( commands int commands_quit( commands_t *cmd ); int commands_toggle_fullscreen( commands_t *cmd ); int commands_toggle_aspect( commands_t *cmd ); +int commands_get_changed_overscan( commands_t *cmd ); int commands_toggle_deinterlacer( commands_t *cmd ); int commands_toggle_pulldown_detection( commands_t *cmd ); int commands_toggle_matte( commands_t *cmd ); --- tvtime-1.0.2.orig/src/tvtime.c +++ tvtime-1.0.2/src/tvtime.c @@ -1062,84 +1062,55 @@ static void build_matte_menu( menu_t *me char string[ 128 ]; menu_set_back_command( menu, TVTIME_SHOW_MENU, "output" ); - if( sixteennine ) { - snprintf( string, sizeof( string ), (mode == 0) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("16:9 + Overscan") ); - menu_set_text( menu, 1, string ); - menu_set_enter_command( menu, 1, TVTIME_SET_MATTE, "16:9" ); - snprintf( string, sizeof( string ), (mode == 1) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("1.85:1") ); - menu_set_text( menu, 2, string ); - menu_set_enter_command( menu, 2, TVTIME_SET_MATTE, "1.85:1" ); - snprintf( string, sizeof( string ), (mode == 2) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("2.35:1") ); - menu_set_text( menu, 3, string ); - menu_set_enter_command( menu, 3, TVTIME_SET_MATTE, "2.35:1" ); - snprintf( string, sizeof( string ), (mode == 3) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("4:3 centre") ); - menu_set_text( menu, 4, string ); - menu_set_enter_command( menu, 4, TVTIME_SET_MATTE, "4:3" ); - snprintf( string, sizeof( string ), (mode == 4) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("16:10") ); - menu_set_text( menu, 5, string ); - menu_set_enter_command( menu, 5, TVTIME_SET_MATTE, "16:10" ); - } else { - snprintf( string, sizeof( string ), (mode == 0) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("4:3 + Overscan") ); - menu_set_text( menu, 1, string ); - menu_set_enter_command( menu, 1, TVTIME_SET_MATTE, "4:3" ); - snprintf( string, sizeof( string ), (mode == 1) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("16:9") ); - menu_set_text( menu, 2, string ); - menu_set_enter_command( menu, 2, TVTIME_SET_MATTE, "16:9" ); - snprintf( string, sizeof( string ), (mode == 2) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("16:10") ); - menu_set_text( menu, 3, string ); - menu_set_enter_command( menu, 3, TVTIME_SET_MATTE, "16:10" ); - snprintf( string, sizeof( string ), (mode == 3) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("1.85:1") ); - menu_set_text( menu, 4, string ); - menu_set_enter_command( menu, 4, TVTIME_SET_MATTE, "1.85:1" ); - snprintf( string, sizeof( string ), (mode == 4) ? - TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", - _("2.35:1") ); - menu_set_text( menu, 5, string ); - menu_set_enter_command( menu, 5, TVTIME_SET_MATTE, "2.35:1" ); - } + + snprintf( string, sizeof( string ), (mode == 0) ? + TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", + _("4:3") ); + menu_set_text( menu, 1, string ); + menu_set_enter_command( menu, 1, TVTIME_SET_MATTE, "4:3" ); + snprintf( string, sizeof( string ), (mode == 1) ? + TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", + _("16:10") ); + menu_set_text( menu, 2, string ); + menu_set_enter_command( menu, 2, TVTIME_SET_MATTE, "16:10" ); + snprintf( string, sizeof( string ), (mode == 2) ? + TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", + _("16:9") ); + menu_set_text( menu, 3, string ); + menu_set_enter_command( menu, 3, TVTIME_SET_MATTE, "16:9" ); + snprintf( string, sizeof( string ), (mode == 3) ? + TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", + _("1.85:1") ); + menu_set_text( menu, 4, string ); + menu_set_enter_command( menu, 4, TVTIME_SET_MATTE, "1.85:1" ); + snprintf( string, sizeof( string ), (mode == 4) ? + TVTIME_ICON_RADIOON " %s" : TVTIME_ICON_RADIOOFF " %s", + _("2.35:1") ); + menu_set_text( menu, 5, string ); + menu_set_enter_command( menu, 5, TVTIME_SET_MATTE, "2.35:1" ); + snprintf( string, sizeof( string ), TVTIME_ICON_PLAINLEFTARROW " %s", _("Back") ); menu_set_text( menu, 6, string ); menu_set_enter_command( menu, 6, TVTIME_SHOW_MENU, "output" ); } - + static void osd_list_matte( tvtime_osd_t *osd, int mode, int sixteennine ) { tvtime_osd_list_set_lines( osd, 6 ); if( sixteennine ) { tvtime_osd_list_set_text( osd, 0, _("Matte setting (Anamorphic input)") ); - tvtime_osd_list_set_text( osd, 1, _("16:9 + Overscan") ); - tvtime_osd_list_set_text( osd, 2, "1.85:1" ); - tvtime_osd_list_set_text( osd, 3, "2.35:1" ); - tvtime_osd_list_set_text( osd, 4, _("4:3 centre") ); - tvtime_osd_list_set_text( osd, 5, "16:10" ); + } else { tvtime_osd_list_set_text( osd, 0, _("Matte setting (4:3 input)") ); - tvtime_osd_list_set_text( osd, 1, _("4:3 + Overscan") ); - tvtime_osd_list_set_text( osd, 2, "16:9" ); - tvtime_osd_list_set_text( osd, 3, "16:10" ); - tvtime_osd_list_set_text( osd, 4, "1.85:1" ); - tvtime_osd_list_set_text( osd, 5, "2.35:1" ); } + tvtime_osd_list_set_text( osd, 1, "4:3" ); + tvtime_osd_list_set_text( osd, 2, "16:10" ); + tvtime_osd_list_set_text( osd, 3, "16:9" ); + tvtime_osd_list_set_text( osd, 4, "1.85:1" ); + tvtime_osd_list_set_text( osd, 5, "2.35:1" ); + tvtime_osd_list_set_hilight( osd, mode + 1 ); tvtime_osd_show_list( osd, 1, 0 ); } @@ -1204,6 +1175,7 @@ int tvtime_main( rtctimer_t *rtctimer, i int matte_y = 0; int matte_h = 0; int matte_mode = 0; + int matte_changed = 0; int restarttvtime = 0; int return_value = 0; int last_current_id = -1; @@ -1241,6 +1213,7 @@ int tvtime_main( rtctimer_t *rtctimer, i output = get_xv_output(); sixteennine = config_get_aspect( ct ); + matte_mode = config_get_matte( ct ); if( !output || !output->init( config_get_geometry( ct ), sixteennine, config_get_square_pixels( ct ), @@ -1594,6 +1567,15 @@ int tvtime_main( rtctimer_t *rtctimer, i build_fspos_menu( commands_get_menu( commands, "fspos" ), config_get_fullscreen_position( ct ) ); + matte_changed = 1; + double matte = 4.0/3.0; + + /* initialize with safe values until matte is calculated later in the loop. */ + matte_x = 0; + matte_y = 0; + matte_w = width; + matte_h = height; + /* Initialize our timestamps. */ for(;;) { const char *fifo_args = 0; @@ -1607,31 +1589,19 @@ int tvtime_main( rtctimer_t *rtctimer, i int exposed = output->is_exposed(); int current_id; + if( vidin && videoinput_has_tuner( vidin ) ) { current_id = station_get_current_id( stationmgr ); } else { current_id = 0; } - - if( matte_mode ) { + /* Since the matte/overscan calculations changed these could probably + be the same variables, but we'll leave it like this for now. */ output_x = matte_x; output_w = matte_w; output_y = matte_y; output_h = matte_h; - } else { - output_x = (int) ((((double) width) * - commands_get_overscan( commands )) + 0.5); - output_w = (int) ((((double) width) - - (((double) width) * - commands_get_overscan( commands ) * 2.0)) + - 0.5); - output_y = (int) ((((double) height) * - commands_get_overscan( commands )) + 0.5); - output_h = (int) ((((double) height) - - (((double) height) * - commands_get_overscan( commands ) * 2.0)) + - 0.5); - } + if( fifo ) { int cmd; @@ -1766,11 +1736,14 @@ int tvtime_main( rtctimer_t *rtctimer, i quiet_screenshots ); commands_refresh_menu( commands ); } + + if( commands_toggle_aspect( commands ) ) { - matte_mode = 0; - output->set_matte( 0, 0 ); if( output->toggle_aspect() ) { sixteennine = 1; + /* Matte is now always applied so we change it to 16:9 mode too so that + nothing other than overscan is cropped. */ + matte_mode = 2; if( osd ) { tvtime_osd_show_message( osd, _("16:9 display mode active.") ); @@ -1780,6 +1753,7 @@ int tvtime_main( rtctimer_t *rtctimer, i ( ( (double) height ) * (16.0 / 9.0) ); } else { sixteennine = 0; + matte_mode = 0; if( osd ) { tvtime_osd_show_message( osd, _("4:3 display mode active.") ); @@ -1800,9 +1774,7 @@ int tvtime_main( rtctimer_t *rtctimer, i output->is_alwaysontop_supported(), output->is_overscan_supported(), quiet_screenshots ); - build_matte_menu( commands_get_menu( commands, "matte" ), - matte_mode, sixteennine ); - commands_refresh_menu( commands ); + matte_changed = 1; } if( commands_get_fs_pos( commands ) ) { const char *fspos = commands_get_fs_pos( commands ); @@ -1839,84 +1811,92 @@ int tvtime_main( rtctimer_t *rtctimer, i } commands_refresh_menu( commands ); } + + /* Overscan has been changed so it is calculated and applied with the matte. + So changing it now generated this event so that we can tell it to redo the matte. */ + if( commands_get_changed_overscan( commands ) ) { + matte_changed = 1; + } if( commands_toggle_matte( commands ) || commands_get_matte_mode( commands ) ) { - double matte = 4.0 / 3.0; - int sqwidth = sixteennine ? - ((height * 16) / 9) : ((height * 4) / 3); - int sqheight = sixteennine ? - ((width * 9) / 16) : ((width * 3) / 4); - matte_x = 0; - matte_w = width; if( commands_toggle_matte( commands ) ) { matte_mode = (matte_mode + 1) % 5; } else { - if( !strcmp( commands_get_matte_mode( commands ), "16:9" ) ) { - matte_mode = sixteennine ? 0 : 1; - } else if( !strcmp( commands_get_matte_mode( commands ), - "16:10" ) ) { - matte_mode = sixteennine ? 4 : 2; + if( !strcmp( commands_get_matte_mode( commands ), "16:10" ) ) { + matte_mode = 1; + } else if( !strcmp( commands_get_matte_mode( commands ), + "16:9" ) ) { + matte_mode = 2; } else if( !strcmp( commands_get_matte_mode( commands ), "1.85:1" ) ) { - matte_mode = sixteennine ? 1 : 3; + matte_mode = 3; } else if( !strcmp( commands_get_matte_mode( commands ), "2.35:1" ) ) { - matte_mode = sixteennine ? 2 : 4; + matte_mode = 4; } else { - matte_mode = sixteennine ? 3 : 0; + matte_mode = 0; } } - - if( sixteennine ) { - if( matte_mode == 0 ) { - matte = 16.0 / 9.0; - } else if( matte_mode == 1 ) { - matte = 1.85; - } else if( matte_mode == 2 ) { - matte = 2.35; - } else if( matte_mode == 3 ) { - matte = 4.0 / 3.0; - matte_w = (int) (((double) sqheight * matte) + 0.5); - matte_x = (width - matte_w) / 2; - /* We're cropping the sides off so we add overscan to avoid mess - * at the top of the screen. */ - matte_y = commands_get_overscan( commands ) * height / 2; - matte_h = height - matte_y; - output->set_matte( (matte_h * 4) / 3, matte_h ); - } else if( matte_mode == 4 ) { - matte = 1.6; - matte_w = (int) (((double) sqheight * matte) + 0.5); - matte_x = (width - matte_w) / 2; - /* We're cropping the sides off so we add overscan to avoid mess - * at the top of the screen. */ - matte_y = commands_get_overscan( commands ) * height / 2; - matte_h = height - matte_y; - output->set_matte( (matte_h * 16) / 10, matte_h ); - } - } else { - if( matte_mode == 1 ) { - matte = 16.0 / 9.0; - } else if( matte_mode == 2 ) { - matte = 1.6; - } else if( matte_mode == 3 ) { - matte = 1.85; - } else if( matte_mode == 4 ) { - matte = 2.35; - } - } - if( !matte_x ) { - matte_h = (int) ((((double) sqwidth)/matte) + 0.5); - matte_y = (height - matte_h) / 2; - output->set_matte( sqwidth, matte_h ); - } if( osd && !commands_menu_active( commands ) ) { osd_list_matte( osd, matte_mode, sixteennine ); } build_matte_menu( commands_get_menu( commands, "matte" ), matte_mode, sixteennine ); commands_refresh_menu( commands ); + matte_changed = 1; } + if (matte_changed) { + matte_changed = 0; + + /* start with overscan then apply matte */ + matte_x = (int) ((((double) width) * + commands_get_overscan( commands )) + 0.5); + matte_w = (int) ((((double) width) - + (((double) width) * + commands_get_overscan( commands ) * 2.0)) + + 0.5); + matte_y = (int) ((((double) height) * + commands_get_overscan( commands )) + 0.5); + matte_h = (int) ((((double) height) - + (((double) height) * + commands_get_overscan( commands ) * 2.0)) + + 0.5); + + int sqwidth = sixteennine ? + ((matte_h * 16) / 9) : ((matte_h * 4) / 3); + int sqheight = sixteennine ? + ((matte_w * 9) / 16) : ((matte_w * 3) / 4); + + if( matte_mode == 0 ) { + matte = 4.0 / 3.0; + config_save( ct, "Matte", "4:3" ); + } else if( matte_mode == 1 ) { + matte = 1.6; + config_save( ct, "Matte", "16:10" ); + } else if( matte_mode == 2 ) { + matte = 16.0/9.0; + config_save( ct, "Matte", "16:9" ); + } else if( matte_mode == 3 ) { + matte = 1.85; + config_save( ct, "Matte", "1.85:1" ); + } else if( matte_mode == 4 ) { + matte = 2.35; + config_save( ct, "Matte", "2.35:1" ); + } + + if( sixteennine && matte < (16.0/9.0) ) + { + matte_w = (int) (((double) sqheight * matte) + 0.5); + matte_x = (width - matte_w) / 2; + output->set_matte( matte_w, sqheight ); + } else { + matte_h = (int) ((((double) sqwidth)/matte) + 0.5); + matte_y = (height - matte_h) / 2; + output->set_matte( sqwidth, matte_h ); + } + } + if( commands_toggle_pulldown_detection( commands ) ) { if( height == 480 ) { tvtime->pulldown_alg = --- tvtime-1.0.2.orig/src/tvtimeconf.c +++ tvtime-1.0.2/src/tvtimeconf.c @@ -56,6 +56,7 @@ struct config_s char *geometry; int verbose; int aspect; + int matte; int squarepixels; int debug; int fullscreen; @@ -290,6 +291,22 @@ static void parse_option( config_t *ct, ct->aspect = atoi( curval ); } + if( !xmlStrcasecmp( name, BAD_CAST "Matte" ) ) { + if(!strcmp( curval, "4:3")) { + ct->matte = 0; + } else if(!strcmp( curval, "16:10")) { + ct->matte = 1; + } else if(!strcmp( curval, "16:9")) { + ct->matte = 2; + } else if(!strcmp( curval, "1.85:1")) { + ct->matte = 3; + } else if(!strcmp( curval, "2.35:1")) { + ct->matte = 4; + } + /* No valid matte if found ct->matte will be -1 and config_get_matte will choose + a default based on the aspect ratio. */ + } + if( !xmlStrcasecmp( name, BAD_CAST "DebugMode" ) ) { ct->debug = atoi( curval ); } @@ -712,6 +729,7 @@ config_t *config_new( void ) ct->geometry = strdup( "0x576" ); ct->verbose = 0; ct->aspect = 0; + ct->matte = -1; ct->squarepixels = 1; ct->debug = 0; ct->fullscreen = 0; @@ -807,6 +825,10 @@ config_t *config_new( void ) ct->keymap[ 'a' ] = TVTIME_TOGGLE_ASPECT; ct->keymap[ 'f' ] = TVTIME_TOGGLE_FULLSCREEN; ct->keymap[ 'i' ] = TVTIME_TOGGLE_INPUT; + ct->keymap[ 'a' ] = TVTIME_TOGGLE_ASPECT; + ct->keymap[ I_INSERT ] = TVTIME_TOGGLE_MATTE; + ct->keymap[ ',' ] = TVTIME_OVERSCAN_DOWN; + ct->keymap[ '.' ] = TVTIME_OVERSCAN_DOWN; ct->keymap[ 's' ] = TVTIME_SCREENSHOT; ct->keymap[ ',' ] = TVTIME_MIXER_TOGGLE_MUTE; ct->keymap[ 'e' ] = TVTIME_TOGGLE_AUDIO_MODE; @@ -1451,6 +1473,13 @@ int config_get_aspect( config_t *ct ) return ct->aspect; } +int config_get_matte( config_t *ct ) +{ + /* If matte is not set then default to 0 for normal or 2 for widescreen. */ + if (ct->matte == -1) return ct->aspect * 2; + return ct->matte; +} + int config_get_start_channel( config_t *ct ) { return ct->start_channel; --- tvtime-1.0.2.orig/src/tvtimeconf.h +++ tvtime-1.0.2/src/tvtimeconf.h @@ -151,6 +151,7 @@ int config_get_debug( config_t *ct ); const char *config_get_geometry( config_t *ct ); int config_get_inputwidth( config_t *ct ); int config_get_aspect( config_t *ct ); +int config_get_matte( config_t *ct ); int config_get_inputnum( config_t *ct ); const char *config_get_v4l_device( config_t *ct ); const char *config_get_v4l_norm( config_t *ct ); --- tvtime-1.0.2.orig/src/videoinput.c +++ tvtime-1.0.2/src/videoinput.c @@ -376,6 +376,7 @@ uint8_t *videoinput_next_frame( videoinp wait_for_frame_v4l2( vidin ); + videoinput_get_aspect( vidin ); cur_buf.type = vidin->capbuffers[ 0 ].vidbuf.type; if( ioctl( vidin->grab_fd, VIDIOC_DQBUF, &cur_buf ) < 0 ) { /* some drivers return EIO when there is no signal */ @@ -1148,6 +1149,22 @@ void videoinput_set_saturation_relative( } } +float videoinput_get_aspect( videoinput_t *vidin ) +{ + float aspect = 1.0; + + if( vidin->isv4l2 ) { + struct v4l2_cropcap cropcap; + /* on success 0 is returned */ + if( !ioctl( vidin->grab_fd, VIDIOC_CROPCAP, &cropcap ) ) { + aspect = (float)cropcap.pixelaspect.numerator / (float)cropcap.pixelaspect.denominator; + fprintf( stderr, "videoinput: Aspect ratio: %f\n", aspect); + } + } + + return aspect; +} + static void videoinput_do_mute( videoinput_t *vidin, int mute ) { if( vidin->hasaudio && mute != vidin->hw_muted ) { --- tvtime-1.0.2.orig/src/videoinput.h +++ tvtime-1.0.2/src/videoinput.h @@ -71,6 +71,8 @@ typedef struct videoinput_s videoinput_t #define VIDEOINPUT_LANG1 4 #define VIDEOINPUT_LANG2 8 +float videoinput_get_aspect( videoinput_t *vidin ); + /** * Possible PAL audio modes, for the cx88 driver that cannot autodetect. */ --- tvtime-1.0.2.orig/src/xvoutput.c +++ tvtime-1.0.2/src/xvoutput.c @@ -233,7 +233,7 @@ static int xv_alloc_frame( void ) { int size; uint8_t *alloc; - + size = input_width * input_height * 2; if( use_shm ) { alloc = create_shm( size );
Description: Fix desktop file as per Freedesktop.org spec. Author: Alessio Treglia <quadris...@ubuntu.com> --- docs/net-tvtime.desktop | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) --- tvtime-1.0.2.orig/docs/net-tvtime.desktop +++ tvtime-1.0.2/docs/net-tvtime.desktop @@ -1,10 +1,9 @@ [Desktop Entry] -Encoding=UTF-8 Comment=High quality video deinterlacer -Icon=tvtime.png +Icon=tvtime Exec=tvtime Name=TVtime Television Viewer GenericName=Television Viewer Terminal=false Type=Application -Categories=Application;AudioVideo; +Categories=AudioVideo;
Origin: Ubuntu Description: Add support for ALSA in combination with USB audio devices. Bug: https://bugs.launchpad.net/bugs/340769 --- src/Makefile.am | 4 src/audiolib.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/audiolib.h | 38 ++++++ src/tvtime.c | 30 ++++ src/videoinput.c | 19 +++ src/videoinput.h | 14 ++ 6 files changed, 445 insertions(+), 2 deletions(-) --- /dev/null +++ tvtime-1.0.2/src/audiolib.c @@ -0,0 +1,342 @@ +/* + Copyright 2008 Empia Technology Inc. + Copyright 2008 Markus Rechberger <mrechber...@empiatech.com> + + alsa_set_params is derived from aplay.c + + TODO: + more sysfs hacking for determining the empia audio device + +*/ + +#include <stdio.h> +#include "audiolib.h" + +static int alsa_set_params(snd_pcm_t *handle, struct alsa_stream_format *fmt, int start_delay); + +char *get_empia_device() { + int err; + int card = -1; + char dev[64]; + int pcm_device = -1; + snd_ctl_t *ctl; + snd_pcm_info_t *pcm_info; + char *card_name; + do { + err = snd_card_next(&card); + if (card > -1) { + sprintf(dev, "hw:%i", card); + snd_ctl_open(&ctl, dev, 0); + snd_card_get_name(card, &card_name); + snd_pcm_info_alloca(&pcm_info); + + for (;;) + { + char device[500], descr[1024]; + + if ((err = snd_ctl_pcm_next_device(ctl, &pcm_device)) < 0) + pcm_device = -1; + + if (pcm_device < 0) + break; + + snd_pcm_info_set_subdevice(pcm_info, 0); + snd_pcm_info_set_device(pcm_info, pcm_device); + snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_CAPTURE); + if ((err = snd_ctl_pcm_info(ctl, pcm_info))==0) { + sprintf(device,"hw:%d,%d", card, pcm_device); + sprintf(descr,"%s : %s (%s)", card_name, snd_pcm_info_get_name(pcm_info),device); + if(strcmp(snd_pcm_info_get_name(pcm_info), "USB Audio") == 0) { + printf("Found \"%s\"\n", descr); + snd_ctl_close(ctl); + return strdup(device); + + } + } + } + snd_ctl_close(ctl); + } + + } while(card > -1); + return NULL; +} + +int alsa_get_state(struct alsa_device *dev) +{ + return dev->state; +} + +void alsa_set_state(struct alsa_device *dev, enum alsa_state state) +{ + dev->state = state; +} + +struct alsa_device *alsa_open(char *input, char *output, unsigned long format, int channels, unsigned int rate) +{ + int result; + struct alsa_device *dev = malloc(sizeof(struct alsa_device)); + + dev->fmt.format = format; + dev->fmt.channels = channels; + dev->fmt.rate = rate; + dev->state = ALSA_STATE_STOPPED; + + if (dev == NULL) + return NULL; + + + if ((result = snd_pcm_open( &dev->playback, output, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK))<0) + { + free(dev); + return NULL; + } + +// snd_pcm_nonblock( dev->playback, 1); + + alsa_set_params(dev->playback, &dev->fmt, 0); + + if ((result = snd_pcm_open( &dev->capture, input, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK))<0) + { + free(dev); + return NULL; + } + +// snd_pcm_nonblock(dev->playback, 1); + + alsa_set_params(dev->capture, &dev->fmt, 1); + + return dev; +} + +void alsa_close(struct alsa_device **dev) +{ + struct alsa_device *cdev = *dev; + snd_pcm_drain(cdev->playback); + snd_pcm_close(cdev->playback); + snd_pcm_drain(cdev->capture); + snd_pcm_close(cdev->capture); + free(*dev); + snd_config_update_free_global(); + *dev = NULL; +} + +#define TRANSFER_BUFSIZE 256 + +void *alsa_start_thread(void *data) +{ + struct alsa_device *dev = data; + alsa_loop(dev); + return NULL; +} + +int alsa_start_threaded_loop(struct alsa_device *dev) +{ + int pret = 0; + if (dev->state == ALSA_STATE_STOPPED) + { + dev->state = ALSA_STATE_RUNNING; + pthread_create(&dev->athread, NULL, alsa_start_thread, dev); + } + return pret; +} + +int alsa_join_threaded_loop(struct alsa_device *dev) +{ + if (dev->state == ALSA_STATE_RUNNING) + { + dev->state = ALSA_STATE_STOPPED; + pthread_join(dev->athread, NULL); + } + return 0; +} + +int alsa_loop(struct alsa_device *dev) +{ + int length, ret; + unsigned char buf[TRANSFER_BUFSIZE]; + snd_pcm_uframes_t frames = TRANSFER_BUFSIZE/dev->fmt.bits_per_sample; + dev->state = ALSA_STATE_RUNNING; + while (dev->state == ALSA_STATE_RUNNING) { + length = snd_pcm_readi(dev->capture, buf, frames); + switch(length) { + case -EAGAIN: + snd_pcm_wait(dev->capture, 5); + continue; + case -EPIPE: + snd_pcm_drain(dev->capture); + snd_pcm_prepare(dev->capture); + continue; + default: + break; + } + if (length>0) { + ret = snd_pcm_writei(dev->playback, buf, length); + switch (ret) { + case -EPIPE: + snd_pcm_drain(dev->playback); + snd_pcm_prepare(dev->playback); + continue; + default: + break; + } + } + } + snd_pcm_drain(dev->capture); + snd_pcm_drain(dev->playback); + return 0; +} + +/* set start_delay to 1 for capture */ +/* taken from aplay.c */ +static int alsa_set_params(snd_pcm_t *handle, struct alsa_stream_format *fmt, int start_delay) +{ + snd_pcm_uframes_t chunk_size = 0; + snd_pcm_hw_params_t *params; + snd_pcm_sw_params_t *swparams; + snd_pcm_uframes_t buffer_size; + + unsigned buffer_time = 0; + unsigned period_time = 0; + snd_pcm_uframes_t buffer_frames = 0; + snd_pcm_uframes_t period_frames = 0; + + int err; + size_t n; + snd_pcm_uframes_t xfer_align; + unsigned int rate; + int avail_min = -1; + int stop_delay = 0; + + snd_pcm_uframes_t start_threshold, stop_threshold; + snd_pcm_hw_params_alloca(¶ms); + snd_pcm_sw_params_alloca(&swparams); + err = snd_pcm_hw_params_any(handle, params); + if (err < 0) { + printf("Broken configuration for this PCM: no configurations available"); + exit(EXIT_FAILURE); + } + + + snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof()); + snd_pcm_access_mask_none(mask); + snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_RW_INTERLEAVED); + err = snd_pcm_hw_params_set_access_mask(handle, params, mask); + + if (err < 0) { + printf("Access type not available"); + exit(EXIT_FAILURE); + } + err = snd_pcm_hw_params_set_format(handle, params, fmt->format); + if (err < 0) { + printf("Sample format non available"); + exit(EXIT_FAILURE); + } + err = snd_pcm_hw_params_set_channels(handle, params, fmt->channels); + if (err < 0) { + printf("Channels count non available"); + exit(EXIT_FAILURE); + } + + rate = fmt->rate; + err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0); + + assert(err >= 0); + + rate = fmt->rate; + + if (buffer_time == 0 && buffer_frames == 0) { + err = snd_pcm_hw_params_get_buffer_time_max(params, + &buffer_time, 0); + assert(err >= 0); + if (buffer_time > 500000) + buffer_time = 500000; + } + + if (period_time == 0 && period_frames == 0) { + if (buffer_time > 0) + period_time = buffer_time / 4; + else + period_frames = buffer_frames / 4; + } + + if (period_time > 0) + err = snd_pcm_hw_params_set_period_time_near(handle, params, + &period_time, 0); + else + err = snd_pcm_hw_params_set_period_size_near(handle, params, + &period_frames, 0); + + assert(err >= 0); + if (buffer_time > 0) + err = snd_pcm_hw_params_set_buffer_time_near(handle, params, + &buffer_time, 0); + else + err = snd_pcm_hw_params_set_buffer_size_near(handle, params, + &buffer_frames); + + assert(err >= 0); + err = snd_pcm_hw_params(handle, params); + if (err < 0) { + printf("Unable to install hw params"); + return -EINVAL; + } + snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); + snd_pcm_hw_params_get_buffer_size(params, &buffer_size); + + if (chunk_size == buffer_size) { + printf("Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); + return -EINVAL; + } + + snd_pcm_sw_params_current(handle, swparams); + err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align); + if (err < 0) { + printf("Unable to obtain xfer align\n"); + exit(EXIT_FAILURE); + } + + err = snd_pcm_sw_params_set_sleep_min(handle, swparams, 0); + + assert(err >= 0); + if (avail_min < 0) + n = chunk_size; + else + n = (double) rate * avail_min / 1000000; + + err = snd_pcm_sw_params_set_avail_min(handle, swparams, n); + + /* round up to closest transfer boundary */ + n = (buffer_size / xfer_align) * xfer_align; + if (start_delay <= 0) { + start_threshold = n + (double) rate * start_delay / 1000000; + } else + start_threshold = (double) rate * start_delay / 1000000; + if (start_threshold < 1) + start_threshold = 1; + if (start_threshold > n) + start_threshold = n; + + err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); + assert(err >= 0); + + if (stop_delay <= 0) + stop_threshold = buffer_size + (double) rate * stop_delay / 1000000; + else + stop_threshold = (double) rate * stop_delay / 1000000; + + err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); + assert(err >= 0); + + err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align); + assert(err >= 0); + + if (snd_pcm_sw_params(handle, swparams) < 0) { + printf("unable to install sw params"); + return -EINVAL; + } + + fmt->bits_per_sample = snd_pcm_format_physical_width(fmt->format); + fmt->bits_per_frame = fmt->bits_per_sample * fmt->channels; + fmt->chunk_bytes = chunk_size * fmt->bits_per_frame / 8; + return 0; +} --- /dev/null +++ tvtime-1.0.2/src/audiolib.h @@ -0,0 +1,38 @@ +#ifndef _AUDIO_LIB_H +#define _AUDIO_LIB_H +#include <alsa/asoundlib.h> +#include <pthread.h> + +struct alsa_stream_format { + unsigned long format; + int channels; + unsigned int rate; + size_t bits_per_sample; + size_t bits_per_frame; + size_t chunk_bytes; +}; + +enum alsa_state { + ALSA_STATE_STOPPED, + ALSA_STATE_RUNNING +}; + +struct alsa_device { + snd_pcm_t *capture; + snd_pcm_t *playback; + enum alsa_state state; + struct alsa_stream_format fmt; + pthread_t athread; +}; + +struct alsa_device *alsa_open(char *input, char *output, unsigned long format, int channels, unsigned int rate); +char *get_empia_device(); +int alsa_loop(struct alsa_device *dev); +int alsa_get_state(struct alsa_device *dev); +void alsa_close(struct alsa_device **dev); +int alsa_get_state(struct alsa_device *dev); +void alsa_set_state(struct alsa_device *dev, enum alsa_state state); +int alsa_start_threaded_loop(struct alsa_device *dev); +int alsa_join_threaded_loop(struct alsa_device *dev); + +#endif // _AUDIO_LIB_H --- tvtime-1.0.2.orig/src/Makefile.am +++ tvtime-1.0.2/src/Makefile.am @@ -40,7 +40,7 @@ COMMON_SRCS = mixer.c videoinput.c rtcti utils.h utils.c pulldown.h pulldown.c hashtable.h hashtable.c \ cpuinfo.h cpuinfo.c videodev.h videodev2.h menu.c menu.h \ outputfilter.h outputfilter.c xmltv.h xmltv.c gettext.h tvtimeglyphs.h \ - copyfunctions.h copyfunctions.c + copyfunctions.h copyfunctions.c audiolib.h audiolib.c if ARCH_X86 DSCALER_SRCS = $(top_srcdir)/plugins/dscalerapi.h \ @@ -77,7 +77,7 @@ tvtime_CFLAGS = $(TTF_CFLAGS) $(PNG_CFLA $(PLUGIN_CFLAGS) $(X11_CFLAGS) $(XML2_FLAG) \ $(FONT_CFLAGS) $(AM_CFLAGS) tvtime_LDFLAGS = $(TTF_LIBS) $(ZLIB_LIBS) $(PNG_LIBS) \ - $(X11_LIBS) $(XML2_LIBS) -lm -lstdc++ + $(X11_LIBS) $(XML2_LIBS) -lm -lstdc++ -lasound tvtime_command_SOURCES = utils.h utils.c tvtimeconf.h tvtimeconf.c \ tvtime-command.c --- tvtime-1.0.2.orig/src/tvtime.c +++ tvtime-1.0.2/src/tvtime.c @@ -77,6 +77,7 @@ #include "mm_accel.h" #include "menu.h" #include "tvtimeglyphs.h" +#include "audiolib.h" /** * This is how many frames to wait until deciding if the pulldown phase @@ -1181,6 +1182,7 @@ int tvtime_main( rtctimer_t *rtctimer, i int last_current_id = -1; int quiet_screenshots = 0; char prevloc[ 256 ]; + char *empia_device; int i; ct = config_new(); @@ -1576,6 +1578,8 @@ int tvtime_main( rtctimer_t *rtctimer, i matte_w = width; matte_h = height; + empia_device = get_empia_device(); + /* Initialize our timestamps. */ for(;;) { const char *fifo_args = 0; @@ -2049,9 +2053,30 @@ int tvtime_main( rtctimer_t *rtctimer, i if( tuner_state == TUNER_STATE_HAS_SIGNAL ) { has_signal = 1; + /* reopen the device for now, there are several issues which don't allow pausing the + audio data transfer. + + TODO: + The driver(?) seems to crash when setting up the alsa parameters again during the same + session. + */ + + if (empia_device && videoinput_get_audio(vidin) == NULL) { + videoinput_set_audio(vidin, alsa_open(empia_device, "default", SND_PCM_FORMAT_S16_LE, 2 /* 2 channels */, 48000 /* rate */)); + if (videoinput_get_audio(vidin)) { + alsa_start_threaded_loop(videoinput_get_audio(vidin)); + } + } + if( osd ) tvtime_osd_signal_present( osd, 1 ); } else if( tuner_state == TUNER_STATE_NO_SIGNAL ) { if( osd ) tvtime_osd_signal_present( osd, 0 ); + if (videoinput_get_audio(vidin)) { + alsa_join_threaded_loop(videoinput_get_audio(vidin)); + alsa_close(videoinput_get_audio_p(vidin)); + videoinput_set_audio(vidin, NULL); + } + if( fadepos < 256 ) { crossfade_frame( fadeframe, saveframe, blueframe, width, height, width*2, width*2, width*2, fadepos ); @@ -2491,6 +2516,11 @@ int tvtime_main( rtctimer_t *rtctimer, i /* Return to normal scheduling. */ set_default_priority(); + if (videoinput_get_audio(vidin)) { + alsa_join_threaded_loop(videoinput_get_audio(vidin)); + alsa_close(videoinput_get_audio_p(vidin)); + } + /* Remember to save our settings if we were scanning. */ if( scanning ) { station_writeconfig( stationmgr ); --- tvtime-1.0.2.orig/src/videoinput.c +++ tvtime-1.0.2/src/videoinput.c @@ -39,6 +39,7 @@ #include "videodev2.h" #include "videoinput.h" #include "mixer.h" +#include "audiolib.h" /** * How long to wait when we lose a signal, or acquire a signal. @@ -231,8 +232,25 @@ struct videoinput_s /* V4L1 read-mode state. */ int grab_size; uint8_t *grab_data; + + struct alsa_device *adev; }; +struct alsa_device *videoinput_get_audio( videoinput_t *vidin ) +{ + return vidin->adev; +} + +struct alsa_device **videoinput_get_audio_p (videoinput_t *vidin ) +{ + return &vidin->adev; +} + +void videoinput_set_audio( videoinput_t *vidin, struct alsa_device *dev) +{ + vidin->adev = dev; +} + const char *videoinput_get_audio_mode_name( videoinput_t *vidin, int mode ) { if( mode == VIDEO_SOUND_MONO ) { @@ -456,6 +474,7 @@ videoinput_t *videoinput_new( const char vidin->norm = norm; vidin->volume = volume; vidin->amode = 0; + vidin->adev = NULL; vidin->height = videoinput_get_norm_height( norm ); vidin->cur_tuner_state = TUNER_STATE_NO_SIGNAL; --- tvtime-1.0.2.orig/src/videoinput.h +++ tvtime-1.0.2/src/videoinput.h @@ -280,6 +280,20 @@ int videoinput_get_pal_audio_mode( video const char *videoinput_get_driver_name( videoinput_t *vidin ); /** + * Returns the audio handle of the device struct. + */ +struct alsa_device *videoinput_get_audio( videoinput_t *vidin ); + +/** + * Returns a pointer to the alsa_device pointer, used for cleaning up + */ +struct alsa_device **videoinput_get_audio_p (videoinput_t *vidin ); + +/** + * Set adev for vidin + */ +void videoinput_set_audio( videoinput_t *vidin, struct alsa_device *dev); +/** * Sets the capture card volume to use as a percentage from 0-100. * If the value is negative, the capture card volume will remain unset. */