scan.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:28k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * scan.c: DVB scanner helpers
  3.  *****************************************************************************
  4.  * Copyright (C) 2008 the VideoLAN team
  5.  *
  6.  * Authors: Laurent Aimar <fenrir@videolan.org>
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  21.  *****************************************************************************/
  22. /*****************************************************************************
  23.  * Preamble
  24.  *****************************************************************************/
  25. #ifdef HAVE_CONFIG_H
  26. # include "config.h"
  27. #endif
  28. #include <vlc_common.h>
  29. #include <vlc_plugin.h>
  30. #include <vlc_access.h>
  31. #include <vlc_dialog.h>
  32. #ifdef HAVE_UNISTD_H
  33. #   include <unistd.h>
  34. #endif
  35. #include <fcntl.h>
  36. #include <sys/types.h>
  37. #include <sys/poll.h>
  38. #include <errno.h>
  39. /* Include dvbpsi headers */
  40. #ifdef HAVE_DVBPSI_DR_H
  41. #   include <dvbpsi/dvbpsi.h>
  42. #   include <dvbpsi/descriptor.h>
  43. #   include <dvbpsi/pat.h>
  44. #   include <dvbpsi/pmt.h>
  45. #   include <dvbpsi/dr.h>
  46. #   include <dvbpsi/psi.h>
  47. #   include <dvbpsi/demux.h>
  48. #   include <dvbpsi/sdt.h>
  49. #else
  50. #   include "dvbpsi.h"
  51. #   include "descriptor.h"
  52. #   include "tables/pat.h"
  53. #   include "tables/pmt.h"
  54. #   include "descriptors/dr.h"
  55. #   include "psi.h"
  56. #   include "demux.h"
  57. #   include "tables/sdt.h"
  58. #endif
  59. #ifdef ENABLE_HTTPD
  60. #   include "vlc_httpd.h"
  61. #endif
  62. #include "dvb.h"
  63. /* */
  64. scan_service_t *scan_service_New( int i_program, const scan_configuration_t *p_cfg  )
  65. {
  66.     scan_service_t *p_srv = malloc( sizeof(*p_srv) );
  67.     if( !p_srv )
  68.         return NULL;
  69.     p_srv->i_program = i_program;
  70.     p_srv->cfg = *p_cfg;
  71.     p_srv->i_snr = -1;
  72.     p_srv->type = SERVICE_UNKNOWN;
  73.     p_srv->psz_name = NULL;
  74.     p_srv->i_channel = -1;
  75.     p_srv->b_crypted = false;
  76.     p_srv->i_network_id = -1;
  77.     p_srv->i_nit_version = -1;
  78.     p_srv->i_sdt_version = -1;
  79.     return p_srv;
  80. }
  81. void scan_service_Delete( scan_service_t *p_srv )
  82. {
  83.     free( p_srv->psz_name );
  84.     free( p_srv );
  85. }
  86. /* */
  87. int scan_Init( vlc_object_t *p_obj, scan_t *p_scan, const scan_parameter_t *p_parameter )
  88. {
  89.     if( p_parameter->type == SCAN_DVB_T )
  90.     {
  91.         msg_Dbg( p_obj, "DVB-T scanning:" );
  92.         msg_Dbg( p_obj, " - frequency [%d, %d]",
  93.                  p_parameter->frequency.i_min, p_parameter->frequency.i_max );
  94.         msg_Dbg( p_obj, " - bandwidth [%d,%d]",
  95.                  p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
  96.         msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
  97.     }
  98.     else if( p_parameter->type == SCAN_DVB_C )
  99.     {
  100.         msg_Dbg( p_obj, "DVB-C scanning:" );
  101.         msg_Dbg( p_obj, " - frequency [%d, %d]",
  102.                  p_parameter->frequency.i_min, p_parameter->frequency.i_max );
  103.         msg_Dbg( p_obj, " - bandwidth [%d,%d]",
  104.                  p_parameter->bandwidth.i_min, p_parameter->bandwidth.i_max );
  105.         msg_Dbg( p_obj, " - exhaustive mode %s", p_parameter->b_exhaustive ? "on" : "off" );
  106.     }
  107.     else
  108.     {
  109.         return VLC_EGENERIC;
  110.     }
  111.     p_scan->p_obj = VLC_OBJECT(p_obj);
  112.     p_scan->i_index = 0;
  113.     p_scan->p_dialog = NULL;
  114.     TAB_INIT( p_scan->i_service, p_scan->pp_service );
  115.     p_scan->parameter = *p_parameter;
  116.     p_scan->i_time_start = mdate();
  117.     return VLC_SUCCESS;
  118. }
  119. void scan_Clean( scan_t *p_scan )
  120. {
  121.     if( p_scan->p_dialog != NULL )
  122.         dialog_ProgressDestroy( p_scan->p_dialog );
  123.     for( int i = 0; i < p_scan->i_service; i++ )
  124.         scan_service_Delete( p_scan->pp_service[i] );
  125.     TAB_CLEAN( p_scan->i_service, p_scan->pp_service );
  126. }
  127. static int ScanDvbCNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
  128. {
  129.     msg_Dbg( p_scan->p_obj, "Scan index %"PRId64, p_scan->i_index );
  130.     /* Values taken from dvb-scan utils frequency-files, sorted by how
  131.      * often they appear. This hopefully speeds up finding services. */
  132.     static const unsigned short frequencies[] = {
  133.      410, 426, 418, 394, 402, 362,
  134.      370, 354, 346, 442, 434, 386,
  135.      378, 450, 306, 162, 154, 474,
  136.      466, 458, 338, 754, 714, 586,
  137.      562, 546, 514, 490, 314, 170,
  138.      113, 770, 762, 746, 738, 730,
  139.      722, 706, 690, 682, 674, 666,
  140.      650, 642, 634, 554, 538, 530,
  141.      506, 498, 330, 322, 283, 850,
  142.      842, 834, 818, 810, 802, 794,
  143.      786, 778, 748, 732, 728, 724,
  144.      720, 698, 660, 658, 656, 610,
  145.      594, 578, 570, 522, 482, 377,
  146.      372, 347, 339, 323, 315, 299,
  147.      298, 291, 275, 267, 259, 255,
  148.      251, 243, 235, 232, 227, 219,
  149.      211, 203, 195, 187, 179, 171,
  150.      163, 155, 147, 146, 143, 139,
  151.      131, 123, 121
  152.     };
  153.     enum { num_frequencies = (sizeof(frequencies)/sizeof(*frequencies)) };
  154.     if( p_scan->i_index < num_frequencies )
  155.     {
  156.         p_cfg->i_frequency = 1000000 * ( frequencies[ p_scan->i_index ] );
  157.         *pf_pos = (double)p_scan->i_index / num_frequencies;
  158.         return VLC_SUCCESS;
  159.     }
  160.     return VLC_EGENERIC;
  161. }
  162. static int ScanDvbTNextExhaustive( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
  163. {
  164.     if( p_scan->i_index > p_scan->parameter.frequency.i_count * p_scan->parameter.bandwidth.i_count )
  165.         return VLC_EGENERIC;
  166.     const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
  167.     const int i_fi = p_scan->i_index / p_scan->parameter.bandwidth.i_count;
  168.     p_cfg->i_frequency = p_scan->parameter.frequency.i_min + i_fi * p_scan->parameter.frequency.i_step;
  169.     p_cfg->i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
  170.     *pf_pos = (double)p_scan->i_index / p_scan->parameter.frequency.i_count;
  171.     return VLC_SUCCESS;
  172. }
  173. static int ScanDvbTNextFast( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
  174. {
  175.     static const int i_band_count = 2;
  176.     static const struct
  177.     {
  178.         const char *psz_name;
  179.         int i_min;
  180.         int i_max;
  181.     }
  182.     band[2] =
  183.     {
  184.         { "VHF", 174, 230 },
  185.         { "UHF", 470, 862 },
  186.     };
  187.     const int i_offset_count = 5;
  188.     const int i_mhz = 1000000;
  189.     /* We will probe the whole band divided in all bandwidth possibility trying 
  190.      * i_offset_count offset around the position
  191.      */
  192.     for( ;; p_scan->i_index++ )
  193.     {
  194.         const int i_bi = p_scan->i_index % p_scan->parameter.bandwidth.i_count;
  195.         const int i_oi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) % i_offset_count;
  196.         const int i_fi = (p_scan->i_index / p_scan->parameter.bandwidth.i_count) / i_offset_count;
  197.         const int i_bandwidth = p_scan->parameter.bandwidth.i_min + i_bi * p_scan->parameter.bandwidth.i_step;
  198.         int i;
  199.         for( i = 0; i < i_band_count; i++ )
  200.         {
  201.             if( i_fi >= band[i].i_min && i_fi <= band[i].i_max )
  202.                 break;
  203.         }
  204.         if( i >=i_band_count )
  205.         {
  206.             if( i_fi > band[i_band_count-1].i_max )
  207.                 return VLC_EGENERIC;
  208.             continue;
  209.         }
  210.         const int i_frequency_min = band[i].i_min*i_mhz + i_bandwidth*i_mhz/2;
  211.         const int i_frequency_base = i_fi*i_mhz;
  212.         if( i_frequency_base >= i_frequency_min && ( i_frequency_base - i_frequency_min ) % ( i_bandwidth*i_mhz ) == 0 )
  213.         {
  214.             const int i_frequency = i_frequency_base + ( i_oi - i_offset_count/2 ) * p_scan->parameter.frequency.i_step;
  215.             if( i_frequency < p_scan->parameter.frequency.i_min ||
  216.                 i_frequency > p_scan->parameter.frequency.i_max )
  217.                 continue;
  218.             p_cfg->i_frequency = i_frequency;
  219.             p_cfg->i_bandwidth = i_bandwidth;
  220.             int i_current = 0, i_total = 0;
  221.             for( int i = 0; i < i_band_count; i++ )
  222.             {
  223.                 const int i_frag = band[i].i_max-band[i].i_min;
  224.                 if( i_fi >= band[i].i_min )
  225.                     i_current += __MIN( i_fi - band[i].i_min, i_frag );
  226.                 i_total += i_frag;
  227.             }
  228.             *pf_pos = (double)( i_current + (double)i_oi / i_offset_count ) / i_total;
  229.             return VLC_SUCCESS;
  230.         }
  231.     }
  232. }
  233. static int ScanDvbCNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
  234. {
  235.     if( p_scan->parameter.b_exhaustive )
  236.         return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
  237.     else
  238.         return ScanDvbCNextFast( p_scan, p_cfg, pf_pos );
  239. }
  240. static int ScanDvbTNext( scan_t *p_scan, scan_configuration_t *p_cfg, double *pf_pos )
  241. {
  242.     if( p_scan->parameter.b_exhaustive )
  243.         return ScanDvbTNextExhaustive( p_scan, p_cfg, pf_pos );
  244.     else
  245.         return ScanDvbTNextFast( p_scan, p_cfg, pf_pos );
  246. }
  247. int scan_Next( scan_t *p_scan, scan_configuration_t *p_cfg )
  248. {
  249.     double f_position;
  250.     int i_ret;
  251.     if( scan_IsCancelled( p_scan ) )
  252.         return VLC_EGENERIC;
  253.     memset( p_cfg, 0, sizeof(*p_cfg) );
  254.     switch( p_scan->parameter.type )
  255.     {
  256.     case SCAN_DVB_T:
  257.         i_ret = ScanDvbTNext( p_scan, p_cfg, &f_position );
  258.         break;
  259.     case SCAN_DVB_C:
  260.         i_ret = ScanDvbCNext( p_scan, p_cfg, &f_position );
  261.         break;
  262.     default:
  263.         i_ret = VLC_EGENERIC;
  264.         break;
  265.     }
  266.     if( i_ret )
  267.         return i_ret;
  268.     char *psz_text;
  269.     int i_service = 0;
  270.     for( int i = 0; i < p_scan->i_service; i++ )
  271.     {
  272.         if( p_scan->pp_service[i]->type != SERVICE_UNKNOWN )
  273.             i_service++;
  274.     }
  275.     if( asprintf( &psz_text, _("%.1f MHz (%d services)"), 
  276.                   (double)p_cfg->i_frequency / 1000000, i_service ) >= 0 )
  277.     {
  278.         const mtime_t i_eta = f_position > 0.005 ? (mdate() - p_scan->i_time_start) * ( 1.0 / f_position - 1.0 ) : -1;
  279.         char psz_eta[MSTRTIME_MAX_SIZE];
  280.         if( i_eta >= 0 )
  281.             msg_Info( p_scan->p_obj, "Scan ETA %s | %f", secstotimestr( psz_eta, i_eta/1000000 ), f_position * 100 );
  282.         if( p_scan->p_dialog == NULL )
  283.             p_scan->p_dialog = dialog_ProgressCreate( p_scan->p_obj, _("Scanning DVB-T"), psz_text, _("Cancel") );
  284.         if( p_scan->p_dialog != NULL )
  285.             dialog_ProgressSet( p_scan->p_dialog, psz_text, f_position );
  286.         free( psz_text );
  287.     }
  288.     p_scan->i_index++;
  289.     return VLC_SUCCESS;
  290. }
  291. bool scan_IsCancelled( scan_t *p_scan )
  292. {
  293.     return p_scan->p_dialog && dialog_ProgressCancelled( p_scan->p_dialog );
  294. }
  295. static scan_service_t *ScanFindService( scan_t *p_scan, int i_service_start, int i_program )
  296. {
  297.     for( int i = i_service_start; i < p_scan->i_service; i++ )
  298.     {
  299.         if( p_scan->pp_service[i]->i_program == i_program )
  300.             return p_scan->pp_service[i];
  301.     }
  302.     return NULL;
  303. }
  304. /* FIXME handle properly string (convert to utf8) */
  305. static void PATCallBack( scan_session_t *p_session, dvbpsi_pat_t *p_pat )
  306. {
  307.     vlc_object_t *p_obj = p_session->p_obj;
  308.     msg_Dbg( p_obj, "PATCallBack" );
  309.     /* */
  310.     if( p_session->p_pat && p_session->p_pat->b_current_next )
  311.     {
  312.         dvbpsi_DeletePAT( p_session->p_pat );
  313.         p_session->p_pat = NULL;
  314.     }
  315.     if( p_session->p_pat )
  316.     {
  317.         dvbpsi_DeletePAT( p_pat );
  318.         return;
  319.     }
  320.     dvbpsi_pat_program_t *p_program;
  321.     /* */
  322.     p_session->p_pat = p_pat;
  323.     /* */
  324.     msg_Dbg( p_obj, "new PAT ts_id=%d version=%d current_next=%d",
  325.              p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
  326.     for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
  327.     {
  328.         msg_Dbg( p_obj, "  * number=%d pid=%d", p_program->i_number, p_program->i_pid );
  329.         if( p_program->i_number == 0 )
  330.             p_session->i_nit_pid = p_program->i_pid;
  331.     }
  332. }
  333. static void SDTCallBack( scan_session_t *p_session, dvbpsi_sdt_t *p_sdt )
  334. {
  335.     vlc_object_t *p_obj = p_session->p_obj;
  336.     msg_Dbg( p_obj, "SDTCallBack" );
  337.     if( p_session->p_sdt && p_session->p_sdt->b_current_next )
  338.     {
  339.         dvbpsi_DeleteSDT( p_session->p_sdt );
  340.         p_session->p_sdt = NULL;
  341.     }
  342.     if( p_session->p_sdt )
  343.     {
  344.         dvbpsi_DeleteSDT( p_sdt );
  345.         return;
  346.     }
  347.     /* */
  348.     p_session->p_sdt = p_sdt;
  349.     /* */
  350.     msg_Dbg( p_obj, "new SDT ts_id=%d version=%d current_next=%d network_id=%d",
  351.              p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
  352.              p_sdt->i_network_id );
  353.     dvbpsi_sdt_service_t *p_srv;
  354.     for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
  355.     {
  356.         dvbpsi_descriptor_t *p_dr;
  357.         msg_Dbg( p_obj, "  * service id=%d eit schedule=%d present=%d running=%d free_ca=%d",
  358.                  p_srv->i_service_id, p_srv->b_eit_schedule,
  359.                  p_srv->b_eit_present, p_srv->i_running_status,
  360.                  p_srv->b_free_ca );
  361.         for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
  362.         {
  363.             if( p_dr->i_tag == 0x48 )
  364.             {
  365.                 dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
  366.                 char str2[257];
  367.                 memcpy( str2, pD->i_service_name, pD->i_service_name_length );
  368.                 str2[pD->i_service_name_length] = '';
  369.                 msg_Dbg( p_obj, "    - type=%d name=%s",
  370.                          pD->i_service_type, str2 );
  371.             }
  372.             else
  373.             {
  374.                 msg_Dbg( p_obj, "    * dsc 0x%x", p_dr->i_tag );
  375.             }
  376.         }
  377.     }
  378. }
  379. #ifdef DVBPSI_USE_NIT
  380. static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit )
  381. {
  382.     vlc_object_t *p_obj = p_session->p_obj;
  383.     msg_Dbg( p_obj, "NITCallBack" );
  384.     msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d",
  385.              p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next );
  386.     /* */
  387.     if( p_session->p_nit && p_session->p_nit->b_current_next )
  388.     {
  389.         dvbpsi_DeleteNIT( p_session->p_nit );
  390.         p_session->p_nit = NULL;
  391.     }
  392.     if( p_session->p_nit )
  393.     {
  394.         dvbpsi_DeleteNIT( p_nit );
  395.         return;
  396.     }
  397.     /* */
  398.     p_session->p_nit = p_nit;
  399.     dvbpsi_descriptor_t *p_dsc;
  400.     for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
  401.     {
  402.         if( p_dsc->i_tag == 0x40 )
  403.         {
  404.             msg_Dbg( p_obj, "   * network name descriptor" );
  405.             char str1[257];
  406.             memcpy( str1, p_dsc->p_data, p_dsc->i_length );
  407.             str1[p_dsc->i_length] = '';
  408.             msg_Dbg( p_obj, "       * name %s", str1 );
  409.         }
  410.         else if( p_dsc->i_tag == 0x4a )
  411.         {
  412.             msg_Dbg( p_obj, "   * linkage descriptor" );
  413.             uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] );
  414.             uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] );
  415.             uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] );
  416.             int i_linkage_type = p_dsc->p_data[6];
  417.             msg_Dbg( p_obj, "       * ts_id %d", i_ts_id );
  418.             msg_Dbg( p_obj, "       * on_id %d", i_on_id );
  419.             msg_Dbg( p_obj, "       * service_id %d", i_service_id );
  420.             msg_Dbg( p_obj, "       * linkage_type %d", i_linkage_type );
  421.         }
  422.         else 
  423.         {
  424.             msg_Dbg( p_obj, "   * dsc 0x%x", p_dsc->i_tag );
  425.         }
  426.     }
  427.     dvbpsi_nit_ts_t *p_ts;
  428.     for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
  429.     {
  430.         msg_Dbg( p_obj, "   * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id );
  431.         uint32_t i_private_data_id = 0;
  432.         dvbpsi_descriptor_t *p_dsc;
  433.         for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
  434.         {
  435.             if( p_dsc->i_tag == 0x41 )
  436.             {
  437.                 msg_Dbg( p_obj, "       * service list descriptor" );
  438.                 for( int i = 0; i < p_dsc->i_length/3; i++ )
  439.                 {
  440.                     uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] );
  441.                     uint8_t  i_service_type = p_dsc->p_data[3*i+2];
  442.                     msg_Dbg( p_obj, "           * service_id=%d type=%d", i_service_id, i_service_type );
  443.                 }
  444.             }
  445.             else if( p_dsc->i_tag == 0x5a )
  446.             {
  447.                 dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc );
  448.                 msg_Dbg( p_obj, "       * terrestrial delivery system" );
  449.                 msg_Dbg( p_obj, "           * centre_frequency 0x%x", p_t->i_centre_frequency  );
  450.                 msg_Dbg( p_obj, "           * bandwidth %d", 8 - p_t->i_bandwidth );
  451.                 msg_Dbg( p_obj, "           * constellation %d", p_t->i_constellation );
  452.                 msg_Dbg( p_obj, "           * hierarchy %d", p_t->i_hierarchy_information );
  453.                 msg_Dbg( p_obj, "           * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream );
  454.                 msg_Dbg( p_obj, "           * guard_interval %d", p_t->i_guard_interval );
  455.                 msg_Dbg( p_obj, "           * transmission_mode %d", p_t->i_transmission_mode );
  456.                 msg_Dbg( p_obj, "           * other_frequency_flag %d", p_t->i_other_frequency_flag );
  457.             }
  458.             else if( p_dsc->i_tag == 0x5f )
  459.             {
  460.                 msg_Dbg( p_obj, "       * private data specifier descriptor" );
  461.                 i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
  462.                 msg_Dbg( p_obj, "           * value 0x%8.8x", i_private_data_id );
  463.             }
  464.             else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
  465.             {
  466.                 msg_Dbg( p_obj, "       * logical channel descriptor (EICTA)" );
  467.                 for( int i = 0; i < p_dsc->i_length/4; i++ )
  468.                 {
  469.                     uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
  470.                     int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
  471.                     msg_Dbg( p_obj, "           * service_id=%d channel_number=%d", i_service_id, i_channel_number );
  472.                 }
  473.             }
  474.             else
  475.             {
  476.                 msg_Warn( p_obj, "       * dsc 0x%x", p_dsc->i_tag );
  477.             }
  478.         }
  479.     }
  480. }
  481. #endif
  482. static void PSINewTableCallBack( scan_session_t *p_session, dvbpsi_handle h, uint8_t  i_table_id, uint16_t i_extension )
  483. {
  484.     if( i_table_id == 0x42 )
  485.         dvbpsi_AttachSDT( h, i_table_id, i_extension, (dvbpsi_sdt_callback)SDTCallBack, p_session );
  486. #ifdef DVBPSI_USE_NIT
  487.     else if( i_table_id == 0x40 )
  488.         dvbpsi_AttachNIT( h, i_table_id, i_extension, (dvbpsi_nit_callback)NITCallBack, p_session );
  489. #endif
  490. }
  491. int scan_session_Init( vlc_object_t *p_obj, scan_session_t *p_session, const scan_configuration_t *p_cfg )
  492. {
  493.     /* */
  494.     memset( p_session, 0, sizeof(*p_session) );
  495.     p_session->p_obj = p_obj;
  496.     p_session->cfg = *p_cfg;
  497.     p_session->i_snr = -1;
  498.     p_session->pat = NULL;
  499.     p_session->p_pat = NULL;
  500.     p_session->i_nit_pid = -1;
  501.     p_session->sdt = NULL;
  502.     p_session->p_sdt = NULL;
  503. #ifdef DVBPSI_USE_NIT
  504.     p_session->nit = NULL;
  505.     p_session->p_nit = NULL;
  506. #endif
  507.     return VLC_SUCCESS;
  508. }
  509. void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session )
  510. {
  511.     const int i_service_start = p_scan->i_service;
  512.     dvbpsi_pat_t *p_pat = p_session->p_pat;
  513.     dvbpsi_sdt_t *p_sdt = p_session->p_sdt;
  514. #ifdef DVBPSI_USE_NIT
  515.     dvbpsi_nit_t *p_nit = p_session->p_nit;
  516. #endif
  517.     if( p_pat )
  518.     {
  519.         /* Parse PAT */
  520.         dvbpsi_pat_program_t *p_program;
  521.         for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
  522.         {
  523.             if( p_program->i_number == 0 )  /* NIT */
  524.                 continue;
  525.             scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg );
  526.             TAB_APPEND( p_scan->i_service, p_scan->pp_service, s );
  527.         }
  528.     }
  529.     /* Parse SDT */
  530.     if( p_pat && p_sdt )
  531.     {
  532.         dvbpsi_sdt_service_t *p_srv;
  533.         for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
  534.         {
  535.             scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id );
  536.             dvbpsi_descriptor_t *p_dr;
  537.             if( s )
  538.                 s->b_crypted = p_srv->b_free_ca;
  539.             for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
  540.             {
  541.                 if( p_dr->i_tag == 0x48 )
  542.                 {
  543.                     dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
  544.                     if( s )
  545.                     {
  546.                         if( !s->psz_name )
  547.                             s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length );
  548.                         if( s->type == SERVICE_UNKNOWN )
  549.                         {
  550.                             switch( pD->i_service_type )
  551.                             {
  552.                             case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break;
  553.                             case 0x02: s->type = SERVICE_DIGITAL_RADIO; break;
  554.                             case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break;
  555.                             case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break;
  556.                             }
  557.                         }
  558.                     }
  559.                 }
  560.             }
  561.         }
  562.     }
  563. #ifdef DVBPSI_USE_NIT
  564.     /* Parse NIT */
  565.     if( p_pat && p_nit )
  566.     {
  567.         dvbpsi_nit_ts_t *p_ts;
  568.         for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next )
  569.         {
  570.             uint32_t i_private_data_id = 0;
  571.             dvbpsi_descriptor_t *p_dsc;
  572.             if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id )
  573.                 continue;
  574.             for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next )
  575.             {
  576.                 if( p_dsc->i_tag == 0x5f )
  577.                 {
  578.                     i_private_data_id = GetDWBE( &p_dsc->p_data[0] );
  579.                 }
  580.                 else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 )
  581.                 {
  582.                     for( int i = 0; i < p_dsc->i_length/4; i++ )
  583.                     {
  584.                         uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] );
  585.                         int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff;
  586.                         scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id );
  587.                         if( s && s->i_channel < 0 )
  588.                             s->i_channel = i_channel_number;
  589.                     }
  590.                 }
  591.             }
  592.         }
  593.     }
  594. #endif
  595.     /* */
  596.     for( int i = i_service_start; i < p_scan->i_service; i++ )
  597.     {
  598.         scan_service_t *p_srv = p_scan->pp_service[i];
  599.         p_srv->i_snr = p_session->i_snr;
  600.         if( p_sdt )
  601.             p_srv->i_sdt_version = p_sdt->i_version;
  602. #ifdef DVBPSI_USE_NIT
  603.         if( p_nit )
  604.         {
  605.             p_srv->i_network_id = p_nit->i_network_id;
  606.             p_srv->i_nit_version = p_nit->i_version;
  607.         }
  608. #endif
  609.     }
  610.     /* */
  611.     if( p_session->pat )
  612.         dvbpsi_DetachPAT( p_session->pat );
  613.     if( p_session->p_pat )
  614.         dvbpsi_DeletePAT( p_session->p_pat );
  615.     if( p_session->sdt )
  616.         dvbpsi_DetachDemux( p_session->sdt );
  617.     if( p_session->p_sdt )
  618.         dvbpsi_DeleteSDT( p_session->p_sdt );
  619. #ifdef DVBPSI_USE_NIT
  620.     if( p_session->nit )
  621.         dvbpsi_DetachDemux( p_session->nit );
  622.     if( p_session->p_nit )
  623.         dvbpsi_DeleteNIT( p_session->p_nit );
  624. #endif
  625. }
  626. static int ScanServiceCmp( const void *a, const void *b )
  627. {
  628.     scan_service_t *sa = *(scan_service_t**)a;
  629.     scan_service_t *sb = *(scan_service_t**)b;
  630.     if( sa->i_channel == sb->i_channel )
  631.     {
  632.         if( sa->psz_name && sb->psz_name )
  633.             return strcmp( sa->psz_name, sb->psz_name );
  634.         return 0;
  635.     }
  636.     if( sa->i_channel == -1 )
  637.         return 1;
  638.     else if( sb->i_channel == -1 )
  639.         return -1;
  640.     if( sa->i_channel < sb->i_channel )
  641.         return -1;
  642.     else if( sa->i_channel > sb->i_channel )
  643.         return 1;
  644.     return 0;
  645. }
  646. static block_t *BlockString( const char *psz )
  647. {
  648.     block_t *p = block_Alloc( strlen(psz) );
  649.     if( p )
  650.         memcpy( p->p_buffer, psz, p->i_buffer );
  651.     return p;
  652. }
  653. block_t *scan_GetM3U( scan_t *p_scan )
  654. {
  655.     vlc_object_t *p_obj = p_scan->p_obj;
  656.     block_t *p_playlist = NULL;
  657.     if( p_scan->i_service <= 0 )
  658.         return NULL;
  659.     /* */
  660.     qsort( p_scan->pp_service, p_scan->i_service, sizeof(scan_service_t*), ScanServiceCmp );
  661.     /* */
  662.     p_playlist = BlockString( "#EXTM3Unn" );/* */
  663.     for( int i = 0; i < p_scan->i_service; i++ )
  664.     {
  665.         scan_service_t *s = p_scan->pp_service[i];
  666.         if( s->type == SERVICE_UNKNOWN )
  667.         {
  668.             /* We should only select service that have been described by SDT */
  669.             msg_Dbg( p_obj, "scan_GetM3U: ignoring service number %d", s->i_program );
  670.             continue;
  671.         }
  672.         const char *psz_type;
  673.         switch( s->type )
  674.         {
  675.         case SERVICE_DIGITAL_TELEVISION:       psz_type = "Digital television"; break;
  676.         case SERVICE_DIGITAL_TELEVISION_AC_SD: psz_type = "Digital television advanced codec SD"; break;
  677.         case SERVICE_DIGITAL_TELEVISION_AC_HD: psz_type = "Digital television advanced codec HD"; break;
  678.         case SERVICE_DIGITAL_RADIO:            psz_type = "Digital radio"; break;
  679.         default:
  680.             psz_type = "Unknown";
  681.             break;
  682.         }
  683.         msg_Warn( p_obj, "scan_GetM3U: service number %d type '%s' name '%s' channel %d cypted=%d| network_id %d (nit:%d sdt:%d)| f=%d bw=%d snr=%d",
  684.                   s->i_program, psz_type, s->psz_name, s->i_channel, s->b_crypted,
  685.                   s->i_network_id, s->i_nit_version, s->i_sdt_version,
  686.                   s->cfg.i_frequency, s->cfg.i_bandwidth, s->i_snr );
  687.         char *psz;
  688.         if( asprintf( &psz, "#EXTINF:,,%sn"
  689.                         "#EXTVLCOPT:program=%dn"
  690.                         "dvb://frequency=%d:bandwidth=%dn"
  691.                         "n",
  692.                       s->psz_name && * s->psz_name ? s->psz_name : "Unknown",
  693.                       s->i_program,
  694.                       s->cfg.i_frequency, s->cfg.i_bandwidth ) < 0 )
  695.             psz = NULL;
  696.         if( psz )
  697.         {
  698.             block_t *p_block = BlockString( psz );
  699.             if( p_block )
  700.                 block_ChainAppend( &p_playlist, p_block );
  701.         }
  702.     }
  703.     return p_playlist ? block_ChainGather( p_playlist ) : NULL;
  704. }
  705. bool scan_session_Push( scan_session_t *p_scan, block_t *p_block )
  706. {
  707.     if( p_block->i_buffer < 188 || p_block->p_buffer[0] != 0x47 )
  708.     {
  709.         block_Release( p_block );
  710.         return false;
  711.     }
  712.     /* */
  713.     const int i_pid = ( (p_block->p_buffer[1]&0x1f)<<8) | p_block->p_buffer[2];
  714.     if( i_pid == 0x00 )
  715.     {
  716.         if( !p_scan->pat )
  717.             p_scan->pat = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack, p_scan );
  718.         if( p_scan->pat )
  719.             dvbpsi_PushPacket( p_scan->pat, p_block->p_buffer );
  720.     }
  721.     else if( i_pid == 0x11 )
  722.     {
  723.         if( !p_scan->sdt )
  724.             p_scan->sdt = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
  725.         if( p_scan->sdt )
  726.             dvbpsi_PushPacket( p_scan->sdt, p_block->p_buffer );
  727.     }
  728.     else if( i_pid == p_scan->i_nit_pid )
  729.     {
  730. #ifdef DVBPSI_USE_NIT
  731.         if( !p_scan->nit )
  732.             p_scan->nit = dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack, p_scan );
  733.         if( p_scan->nit )
  734.             dvbpsi_PushPacket( p_scan->nit, p_block->p_buffer );
  735. #endif
  736.     }
  737.     block_Release( p_block );
  738.     return p_scan->p_pat && p_scan->p_sdt && 
  739. #ifdef DVBPSI_USE_NIT
  740.         p_scan->p_nit;
  741. #else
  742.         true;
  743. #endif
  744. }
  745. void scan_service_SetSNR( scan_session_t *p_session, int i_snr )
  746. {
  747.     p_session->i_snr = i_snr;
  748. }