summaryrefslogtreecommitdiffstats
path: root/kaffeine/src/input
diff options
context:
space:
mode:
Diffstat (limited to 'kaffeine/src/input')
-rw-r--r--kaffeine/src/input/Makefile.am21
-rw-r--r--kaffeine/src/input/audiobrowser/Makefile.am28
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcher.cpp282
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcher.h91
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp254
-rw-r--r--kaffeine/src/input/audiobrowser/googlefetcherdialog.h98
-rw-r--r--kaffeine/src/input/audiobrowser/kaffeineplaylist.rc17
-rw-r--r--kaffeine/src/input/audiobrowser/playlist.cpp2365
-rw-r--r--kaffeine/src/input/audiobrowser/playlist.h336
-rw-r--r--kaffeine/src/input/audiobrowser/playlistitem.cpp268
-rw-r--r--kaffeine/src/input/audiobrowser/playlistitem.h93
-rw-r--r--kaffeine/src/input/audiobrowser/urllistview.cpp347
-rw-r--r--kaffeine/src/input/audiobrowser/urllistview.h92
-rw-r--r--kaffeine/src/input/disc/Makefile.am36
-rw-r--r--kaffeine/src/input/disc/cddb.cpp572
-rw-r--r--kaffeine/src/input/disc/cddb.h77
-rw-r--r--kaffeine/src/input/disc/disc.cpp767
-rw-r--r--kaffeine/src/input/disc/disc.h140
-rw-r--r--kaffeine/src/input/disc/kaffeinedisc.rc24
-rw-r--r--kaffeine/src/input/disc/paranoia.cpp553
-rw-r--r--kaffeine/src/input/disc/paranoia.h108
-rw-r--r--kaffeine/src/input/disc/paranoiasettings.ui252
-rw-r--r--kaffeine/src/input/disc/plugins/Makefile.am24
-rw-r--r--kaffeine/src/input/disc/plugins/kaffeineaudioencoder.cpp30
-rw-r--r--kaffeine/src/input/disc/plugins/kaffeineaudioencoder.desktop4
-rw-r--r--kaffeine/src/input/disc/plugins/kaffeineaudioencoder.h53
-rw-r--r--kaffeine/src/input/disc/plugins/mp3lame/Makefile.am17
-rw-r--r--kaffeine/src/input/disc/plugins/mp3lame/kaffeinemp3lame.desktop12
-rw-r--r--kaffeine/src/input/disc/plugins/mp3lame/klameenc.cpp176
-rw-r--r--kaffeine/src/input/disc/plugins/mp3lame/klameenc.h76
-rw-r--r--kaffeine/src/input/disc/plugins/mp3lame/lameconfig.ui195
-rw-r--r--kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am17
-rw-r--r--kaffeine/src/input/disc/plugins/oggvorbis/kaffeineoggvorbis.desktop9
-rw-r--r--kaffeine/src/input/disc/plugins/oggvorbis/koggenc.cpp236
-rw-r--r--kaffeine/src/input/disc/plugins/oggvorbis/koggenc.h92
-rw-r--r--kaffeine/src/input/disc/plugins/oggvorbis/oggconfig.ui191
-rw-r--r--kaffeine/src/input/dvb/Makefile.am81
-rw-r--r--kaffeine/src/input/dvb/audioeditor.cpp160
-rw-r--r--kaffeine/src/input/dvb/audioeditor.h53
-rw-r--r--kaffeine/src/input/dvb/audioeditorui.ui319
-rw-r--r--kaffeine/src/input/dvb/broadcasteditor.cpp132
-rw-r--r--kaffeine/src/input/dvb/broadcasteditor.h58
-rw-r--r--kaffeine/src/input/dvb/broadcasteditorui.ui315
-rw-r--r--kaffeine/src/input/dvb/channeldesc.cpp184
-rw-r--r--kaffeine/src/input/dvb/channeldesc.h137
-rw-r--r--kaffeine/src/input/dvb/channeleditor.cpp330
-rw-r--r--kaffeine/src/input/dvb/channeleditor.h70
-rw-r--r--kaffeine/src/input/dvb/channeleditorui.ui704
-rw-r--r--kaffeine/src/input/dvb/cleaner.cpp82
-rw-r--r--kaffeine/src/input/dvb/cleaner.h54
-rw-r--r--kaffeine/src/input/dvb/crontimer.cpp109
-rw-r--r--kaffeine/src/input/dvb/crontimer.h58
-rw-r--r--kaffeine/src/input/dvb/crontimerui.ui354
-rw-r--r--kaffeine/src/input/dvb/dvbcam.cpp926
-rw-r--r--kaffeine/src/input/dvb/dvbcam.h52
-rw-r--r--kaffeine/src/input/dvb/dvbconfig.cpp1478
-rw-r--r--kaffeine/src/input/dvb/dvbconfig.h301
-rw-r--r--kaffeine/src/input/dvb/dvbevents.cpp424
-rw-r--r--kaffeine/src/input/dvb/dvbevents.h59
-rw-r--r--kaffeine/src/input/dvb/dvbout.cpp568
-rw-r--r--kaffeine/src/input/dvb/dvbout.h118
-rw-r--r--kaffeine/src/input/dvb/dvbpanel.cpp2673
-rw-r--r--kaffeine/src/input/dvb/dvbpanel.h242
-rw-r--r--kaffeine/src/input/dvb/dvbsection.h26
-rw-r--r--kaffeine/src/input/dvb/dvbsi.cpp866
-rw-r--r--kaffeine/src/input/dvb/dvbsi.h98
-rw-r--r--kaffeine/src/input/dvb/dvbstream.cpp1390
-rw-r--r--kaffeine/src/input/dvb/dvbstream.h163
-rw-r--r--kaffeine/src/input/dvb/gdvb.h30
-rw-r--r--kaffeine/src/input/dvb/kaffeinedvb.rc24
-rw-r--r--kaffeine/src/input/dvb/kevents.cpp478
-rw-r--r--kaffeine/src/input/dvb/kevents.h98
-rw-r--r--kaffeine/src/input/dvb/kgradprogress.cpp136
-rw-r--r--kaffeine/src/input/dvb/kgradprogress.h59
-rw-r--r--kaffeine/src/input/dvb/krecord.cpp295
-rw-r--r--kaffeine/src/input/dvb/krecord.h69
-rw-r--r--kaffeine/src/input/dvb/ktimereditor.cpp231
-rw-r--r--kaffeine/src/input/dvb/ktimereditor.h67
-rw-r--r--kaffeine/src/input/dvb/lib/Makefile.am1
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am11
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/diseqc.c141
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/diseqc.h171
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbca.c159
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbca.h135
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c243
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h202
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c760
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h308
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c99
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h87
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am21
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c81
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h41
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c185
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h129
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c179
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h119
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c615
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h254
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c169
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h116
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c263
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h164
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c166
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h136
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c514
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h210
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c1316
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h571
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c294
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h178
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c293
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h191
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h104
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c139
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h104
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c37
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h105
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h52
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c954
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h212
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c1240
-rw-r--r--kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h231
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h72
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/Makefile.am17
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h70
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/atsc/section.h69
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/crc32.c89
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/crc32.h58
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/descriptor.h129
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile.am19
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h88
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h62
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h204
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h157
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_name_descriptor.h145
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/ait_external_application_authorisation_descriptor.h125
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h67
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h219
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h124
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c77
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h211
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/bouquet_name_descriptor.h82
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/ca_identifier_descriptor.h94
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h70
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h190
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h201
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h147
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h116
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h222
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h120
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_descriptor.h139
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h90
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/default_authority_descriptor.h82
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h198
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.c32
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.h54
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/dsng_descriptor.h80
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c63
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h160
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h232
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h107
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c80
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h245
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h478
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h127
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h110
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h324
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_bouquet_name_descriptor.h145
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_component_descriptor.h149
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_network_name_descriptor.h145
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_service_name_descriptor.h197
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/network_name_descriptor.h82
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c79
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.h207
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/nvod_reference_descriptor.h125
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h135
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h68
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h64
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/private_data_specifier_descriptor.h63
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/related_content_descriptor.h56
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h110
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h87
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rnt_scan_descriptor.h125
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c47
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h111
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h116
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h73
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/scrambling_descriptor.h61
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c60
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h157
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/section.h107
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h98
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h156
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/service_identifier_descriptor.h82
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/service_list_descriptor.h122
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/service_move_descriptor.h67
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/short_event_descriptor.h135
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h87
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c70
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h173
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.c29
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.h77
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/stream_identifier_descriptor.h61
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/stuffing_descriptor.h82
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/subtitling_descriptor.h126
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c33
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.h54
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h150
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h127
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h77
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_event_descriptor.h65
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_service_descriptor.h63
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c50
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.h97
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/transport_stream_descriptor.h82
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c33
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h90
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h124
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/types.c270
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/types.h127
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h186
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h116
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/endianops.h128
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile.am12
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/audio_stream_descriptor.h65
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/ca_descriptor.h91
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c34
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h94
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/content_labelling_descriptor.h356
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/copyright_descriptor.h89
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/data_stream_alignment_descriptor.h73
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/descriptor.h102
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/external_es_id_descriptor.h63
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/fmc_descriptor.h122
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/fmxbuffer_size_descriptor.h83
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/hierarchy_descriptor.h83
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/ibp_descriptor.h65
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/iod_descriptor.h87
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/iso_639_language_descriptor.h124
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/maximum_bitrate_descriptor.h64
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_descriptor.h472
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_pointer_descriptor.h360
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c28
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.h122
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_std_descriptor.h72
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_audio_descriptor.h61
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_video_descriptor.h61
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_descriptor.h65
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_utilization_descriptor.h67
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/muxcode_descriptor.h82
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c80
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h224
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c46
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h118
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c71
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h188
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/private_data_indicator_descriptor.h63
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/registration_descriptor.h91
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h58
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/sl_descriptor.h63
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/smoothing_buffer_descriptor.h66
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/std_descriptor.h62
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/system_clock_descriptor.h65
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/target_background_grid_descriptor.h66
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c35
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h94
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/types.h127
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/video_stream_descriptor.h101
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/mpeg/video_window_descriptor.h64
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/section.h253
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/section_buf.c173
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/section_buf.h125
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/testrecord.txt101
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/transport_packet.c256
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/transport_packet.h195
-rw-r--r--kaffeine/src/input/dvb/lib/libucsi/types.h36
-rw-r--r--kaffeine/src/input/dvb/plugins/Makefile.am1
-rw-r--r--kaffeine/src/input/dvb/plugins/epg/Makefile.am16
-rw-r--r--kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.cpp496
-rw-r--r--kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.h177
-rw-r--r--kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp327
-rw-r--r--kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.h64
-rw-r--r--kaffeine/src/input/dvb/plugins/epg/kaffeineepgplugin.desktop4
-rw-r--r--kaffeine/src/input/dvb/plugins/stream/Makefile.am16
-rw-r--r--kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.cpp30
-rw-r--r--kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.desktop4
-rw-r--r--kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.h52
-rw-r--r--kaffeine/src/input/dvb/scandialog.cpp1019
-rw-r--r--kaffeine/src/input/dvb/scandialog.h106
-rw-r--r--kaffeine/src/input/dvb/scandialogui.ui514
-rw-r--r--kaffeine/src/input/dvb/sender.cpp114
-rw-r--r--kaffeine/src/input/dvb/sender.h59
-rw-r--r--kaffeine/src/input/dvb/subeditor.cpp182
-rw-r--r--kaffeine/src/input/dvb/subeditor.h55
-rw-r--r--kaffeine/src/input/dvb/subeditorui.ui354
-rw-r--r--kaffeine/src/input/dvb/ts2rtp.cpp478
-rw-r--r--kaffeine/src/input/dvb/ts2rtp.h99
-rw-r--r--kaffeine/src/input/dvbclient/Makefile.am23
-rw-r--r--kaffeine/src/input/dvbclient/cdchannel.cpp54
-rw-r--r--kaffeine/src/input/dvbclient/cdchannel.h45
-rw-r--r--kaffeine/src/input/dvbclient/cdcleaner.cpp69
-rw-r--r--kaffeine/src/input/dvbclient/cdcleaner.h56
-rw-r--r--kaffeine/src/input/dvbclient/cddump.cpp362
-rw-r--r--kaffeine/src/input/dvbclient/cddump.h106
-rw-r--r--kaffeine/src/input/dvbclient/cdlisten.cpp113
-rw-r--r--kaffeine/src/input/dvbclient/cdlisten.h62
-rw-r--r--kaffeine/src/input/dvbclient/cdwidget.cpp371
-rw-r--r--kaffeine/src/input/dvbclient/cdwidget.h107
-rw-r--r--kaffeine/src/input/kaffeineinput.cpp31
-rw-r--r--kaffeine/src/input/kaffeineinput.h115
311 files changed, 56874 insertions, 0 deletions
diff --git a/kaffeine/src/input/Makefile.am b/kaffeine/src/input/Makefile.am
new file mode 100644
index 0000000..75b2ab7
--- /dev/null
+++ b/kaffeine/src/input/Makefile.am
@@ -0,0 +1,21 @@
+noinst_LTLIBRARIES = libkaffeineinput.la
+
+if with_dvb
+ DVB_SUBDIR = dvb
+endif
+
+SUBDIRS = . dvbclient audiobrowser disc $(DVB_SUBDIR)
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src \
+ -I$(top_srcdir)/kaffeine/src/player-parts/kaffeine-part $(all_includes)
+
+noinst_HEADERS = kaffeineinput.h
+
+METASOURCES = AUTO
+
+libkaffeineinput_la_SOURCES = kaffeineinput.cpp
+
+libkaffeineinput_la_LDFLAGS = $(KDE_RPATH) \
+ $(all_libraries)
+
+libkaffeineinput_la_LIBADD = $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la
diff --git a/kaffeine/src/input/audiobrowser/Makefile.am b/kaffeine/src/input/audiobrowser/Makefile.am
new file mode 100644
index 0000000..b743ccd
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/Makefile.am
@@ -0,0 +1,28 @@
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libkaffeineaudiobrowser.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \
+ -I$(top_srcdir)/kaffeine/src/ \
+ $(all_includes) \
+ -I$(top_srcdir)/kaffeine/src/player-parts/kaffeine-part
+
+libkaffeineaudiobrowser_la_SOURCES = playlist.cpp \
+ playlistitem.cpp \
+ urllistview.cpp \
+ googlefetcher.cpp \
+ googlefetcherdialog.cpp
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+libkaffeineaudiobrowser_la_LDFLAGS = $(KDE_RPATH) \
+ $(all_libraries) \
+ -L$(top_srcdir)/kaffeine/src/input
+
+libkaffeineaudiobrowser_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \
+ $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la \
+ $(LIB_KHTML)
+
+# this is where the XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kaffeine
+shellrc_DATA = kaffeineplaylist.rc
diff --git a/kaffeine/src/input/audiobrowser/googlefetcher.cpp b/kaffeine/src/input/audiobrowser/googlefetcher.cpp
new file mode 100644
index 0000000..fe88d14
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcher.cpp
@@ -0,0 +1,282 @@
+/*
+ * googlefetcher.cpp
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <dom/html_document.h>
+#include <dom/html_misc.h>
+#include <dom/html_table.h>
+#include <dom/dom_exception.h>
+#include <dom/dom2_traversal.h>
+
+#include <khtml_part.h>
+
+#include <klocale.h>
+#include <kinputdialog.h>
+#include <kurl.h>
+#include <kio/netaccess.h>
+
+#include "googlefetcher.h"
+#include "googlefetcherdialog.h"
+
+GoogleImage::GoogleImage(QString thumbURL, QString size)
+{
+ // thumbURL is in the following format - and we can regex the imageURL
+ // images?q=tbn:hKSEWNB8aNcJ:www.styxnet.com/deyoung/styx/stygians/cp_portrait.jpg
+ m_thumbURL = thumbURL.replace("\"","");
+ m_imageURL = thumbURL.remove(QRegExp("^.*q=tbn:[^:]*:")).replace("\"","");
+ m_size = size.replace("pixels - ", "\n(") + ")";
+}
+
+
+GoogleFetcher::GoogleFetcher( QString artist, QString album, bool gallery )
+{
+ m_artist = artist;
+ m_album = album;
+ m_searchString = artist+" "+album;
+ encoding = 0;
+ galleryImage=galleryPage=0;
+ galleryMode = gallery;
+}
+
+void GoogleFetcher::slotLoadImageURLs(GoogleFetcher::ImageSize size)
+{
+ if(m_loadedQuery == m_searchString && m_loadedSize == size)
+ return;
+
+ m_imageList.clear();
+
+ KURL url("http://images.google.com/images");
+ if ( encoding )
+ url.addQueryItem("q", m_searchString,encoding);
+ else
+ url.addQueryItem("q", m_searchString);
+
+ switch (size) {
+ case XLarge:
+ url.addQueryItem("imgsz", "xlarge|xxlarge");
+ break;
+ case Large:
+ url.addQueryItem("imgsz", "large");
+ break;
+ case Medium:
+ url.addQueryItem("imgsz", "medium");
+ break;
+ case Small:
+ url.addQueryItem("imgsz", "small");
+ break;
+ case Icon:
+ url.addQueryItem("imgsz", "icon");
+ break;
+ default:
+ break;
+ }
+
+ m_loadedQuery = m_searchString;
+ m_loadedSize = size;
+
+ // We don't normally like exceptions but missing DOMException will kill
+ // JuK rather abruptly whether we like it or not so we don't really have a
+ // choice if we're going to screen-scrape Google.
+ try {
+
+ KHTMLPart part;
+
+ // Create empty document.
+
+ part.begin();
+ part.end();
+
+ DOM::Document search = part.document();
+ search.setAsync(false); // Grab the document before proceeding.
+
+ kdDebug() << "Performing Google Search: " << url << endl;
+
+ search.load(url.url()+QString("&start=%1&sa=N").arg(galleryPage*20) );
+
+ QString text = search.toString().string();
+
+ if ( !hasImageResults(text) ) {
+ kdDebug() << "Search returned no results.\n";
+ emit signalNewSearch(m_imageList);
+ return;
+ }
+
+ // Go through each of the top (table) nodes
+
+ int pos = text.find("/imgres?imgurl");
+ int tpos;
+ QString s, c;
+ while ( pos>-1 ) {
+ text = text.right( text.length()-pos-14 );
+ tpos = text.find("&h=");
+ text = text.right( text.length()-tpos-3 );
+ tpos = text.find("&w=");
+ c = "pixels - " + text.left( tpos );
+ text = text.right( text.length()-tpos-3 );
+ tpos = text.find("&sz=");
+ c = c + "x" + text.left( tpos );
+ tpos = text.find("src=");
+ text = text.right( text.length()-tpos-4 );
+ if ( (tpos=text.find("width="))==-1 )
+ break;
+ s = text.left( tpos-1 );
+ text = text.right( text.length()-tpos );
+ if ( (tpos=text.find("></a>"))==-1 )
+ break;
+ m_imageList.append(GoogleImage(s, c));
+ pos = text.find("/imgres?imgurl");
+ }
+ } // try
+ catch (DOM::DOMException &e)
+ {
+ kdError() << "Caught DOM Exception: " << e.code << endl;
+ }
+ catch (...)
+ {
+ kdError() << "Caught unknown exception.\n";
+ }
+
+ emit signalNewSearch(m_imageList);
+}
+
+QImage GoogleFetcher::galleryNext( bool &end )
+{
+ QString file;
+ QImage image;
+ m_loadedSize = All;
+ int tries = 0;
+ end = false;
+
+ while ( tries<3 ) {
+ if( m_imageList.isEmpty() ) {
+ if ( tries==0 ) {
+ encoding = 0;
+ m_loadedQuery = "";
+ ++tries;
+ displayWaitMessage();
+ }
+ else if ( tries==1 ) {
+ encoding = 4; // try iso8859-1
+ m_loadedQuery = "";
+ ++tries;
+ kdDebug() << "Trying iso8859-1" << endl;
+ displayWaitMessage();
+ }
+ else {
+ end = true;
+ return QImage();
+ }
+ }
+ else {
+ if(KIO::NetAccess::download( m_imageList[galleryImage].imageURL(), file, 0))
+ image = QImage(file);
+ else
+ image = QImage();
+ ++galleryImage;
+ if ( galleryImage==(int)m_imageList.count() ) {
+ m_imageList.clear();
+ galleryImage = 0;
+ ++galleryPage;
+ }
+ KIO::NetAccess::removeTempFile(file);
+ return image;
+ }
+ }
+ return QImage();
+}
+
+QPixmap GoogleFetcher::pixmap( bool forceFetch )
+{
+ bool chosen = false;
+ m_loadedSize = All;
+ int tries = 0;
+
+ encoding = 0;
+ displayWaitMessage();
+
+ QPixmap pixmap;
+
+ while(!chosen) {
+
+ if(m_imageList.isEmpty())
+ switch(tries) {
+ case 0:
+ encoding = 4; // try iso8859-1
+ m_loadedQuery = "";
+ ++tries;
+ kdDebug() << "Trying iso8859-1" << endl;
+ displayWaitMessage();
+ break;
+ default :
+ if ( forceFetch == true )
+ chosen = !requestNewSearchTerms(true);
+ else
+ chosen = true;
+ }
+ else {
+ GoogleFetcherDialog dialog("google", m_imageList, m_artist, m_album, 0);
+ connect(&dialog, SIGNAL(sizeChanged(GoogleFetcher::ImageSize)),
+ this, SLOT(slotLoadImageURLs(GoogleFetcher::ImageSize)));
+ connect(this, SIGNAL(signalNewSearch(GoogleImageList &)),
+ &dialog, SLOT(refreshScreen(GoogleImageList &)));
+ dialog.exec();
+ pixmap = dialog.result();
+ chosen = dialog.takeIt();
+
+ if(dialog.newSearch())
+ requestNewSearchTerms();
+ }
+ }
+ return pixmap;
+}
+
+void GoogleFetcher::displayWaitMessage()
+{
+ //KStatusBar *statusBar = static_cast<KMainWindow *>(kapp->mainWidget())->statusBar();
+ //statusBar->message(i18n("Searching for Images. Please Wait..."));
+ slotLoadImageURLs();
+ //statusBar->clear();*/
+}
+
+bool GoogleFetcher::requestNewSearchTerms(bool noResults)
+{
+ bool ok;
+ m_searchString = KInputDialog::getText(i18n("Cover Downloader"),
+ noResults ?
+ i18n("No matching images found, please enter new search terms:") :
+ i18n("Enter new search terms:"),
+ m_searchString, &ok);
+ if(ok && !m_searchString.isEmpty())
+ displayWaitMessage();
+ else
+ m_searchString = m_loadedQuery;
+
+ return ok;
+}
+
+bool GoogleFetcher::hasImageResults( QString &doc )
+{
+ if ( !doc.contains( "/imgres?imgurl" ) )
+ return false;
+
+ return true;
+}
+
+#include "googlefetcher.moc"
diff --git a/kaffeine/src/input/audiobrowser/googlefetcher.h b/kaffeine/src/input/audiobrowser/googlefetcher.h
new file mode 100644
index 0000000..7c90091
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcher.h
@@ -0,0 +1,91 @@
+/*
+ * googlefetcher.h
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef GOOGLEFETCHER_H
+#define GOOGLEFETCHER_H
+
+#include <kdialogbase.h>
+
+#include <qpixmap.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+
+namespace DOM {
+ class HTMLDocument;
+}
+
+class KURL;
+
+class GoogleImage
+{
+public:
+ GoogleImage(QString thumbURL = QString::null, QString size = QString::null);
+
+ QString imageURL() const { return m_imageURL; }
+ QString thumbURL() const { return m_thumbURL; }
+ QString size() const { return m_size; }
+
+private:
+ QString m_imageURL;
+ QString m_thumbURL;
+ QString m_size;
+};
+
+typedef QValueList<GoogleImage> GoogleImageList;
+
+class GoogleFetcher : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum ImageSize { All, Icon, Small, Medium, Large, XLarge };
+
+ GoogleFetcher( QString artist, QString album, bool gallery=false );
+ QPixmap pixmap( bool forceFetch = false );
+ QImage galleryNext( bool &end );
+
+signals:
+ void signalNewSearch(GoogleImageList &images);
+
+private:
+ void displayWaitMessage();
+ bool requestNewSearchTerms(bool noResults = false);
+
+ // Returns true if there are results in the search, otherwise returns false.
+ bool hasImageResults( QString &doc );
+
+private slots:
+ void slotLoadImageURLs(GoogleFetcher::ImageSize size = All);
+
+private:
+ QString m_artist, m_album;
+ QString m_searchString;
+ QString m_loadedQuery;
+ ImageSize m_loadedSize;
+ GoogleImageList m_imageList;
+ uint m_selectedIndex;
+ int encoding;
+ int galleryImage;
+ int galleryPage;
+ bool galleryMode;
+};
+
+#endif /* GOOGLEFETCHER_H */
diff --git a/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp b/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp
new file mode 100644
index 0000000..bda3853
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcherdialog.cpp
@@ -0,0 +1,254 @@
+/*
+ * googlefetcherdialog.cpp
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kapplication.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kcombobox.h>
+
+#include <qhbox.h>
+#include <qimage.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qeventloop.h>
+
+#include "googlefetcherdialog.h"
+
+GoogleFetcherDialog::GoogleFetcherDialog(const QString &name,
+ const GoogleImageList &imageList,
+ const QString &artist,
+ const QString &album,
+ QWidget *parent) :
+ KDialogBase(parent, name.latin1(), true, QString::null,
+ Ok | Cancel | User1 , NoDefault, true),
+ m_pixmap(QPixmap()),
+ m_imageList(imageList),
+ m_takeIt(false),
+ m_newSearch(false)
+{
+ m_artist = artist;
+ m_album = album;
+ disableResize();
+
+ QHBox *mainBox = new QHBox(this);
+ m_iconWidget = new KIconView(mainBox);
+ m_iconWidget->setResizeMode(QIconView::Adjust);
+ m_iconWidget->setSelectionMode(QIconView::Extended);
+ m_iconWidget->setSpacing(10);
+ m_iconWidget->setMode(KIconView::Execute);
+ m_iconWidget->setFixedSize(500,550);
+ m_iconWidget->arrangeItemsInGrid();
+ m_iconWidget->setItemsMovable(FALSE);
+
+ QHBox *imgSize = new QHBox(actionButton(User1)->parentWidget());
+ //QLabel *label = new QLabel(imgSize);
+ //label->setText(i18n("Image size:"));
+
+ KComboBox *combo = new KComboBox(imgSize);
+ combo->insertItem(i18n("All Sizes"));
+ combo->insertItem(i18n("Very Small"));
+ combo->insertItem(i18n("Small"));
+ combo->insertItem(i18n("Medium"));
+ combo->insertItem(i18n("Large"));
+ combo->insertItem(i18n("Very Large"));
+ combo->setCurrentItem(0);
+ connect(combo, SIGNAL(activated(int)), this, SLOT(imgSizeChanged(int)));
+ connect(m_iconWidget, SIGNAL( executed(QIconViewItem*) ), this, SLOT(slotOk()));
+
+ imgSize->adjustSize();
+ setMainWidget(mainBox);
+ setButtonText(User1, i18n("New Search"));
+}
+
+GoogleFetcherDialog::~GoogleFetcherDialog()
+{
+
+}
+
+void GoogleFetcherDialog::setLayout()
+{
+ setCaption(QString("%1 - %2 (%3)")
+ .arg(m_artist)
+ .arg(m_album)
+ .arg(m_imageList.size()));
+
+ m_iconWidget->clear();
+ for(uint i = 0; i < m_imageList.size(); i++)
+ new CoverIconViewItem(m_iconWidget, m_imageList[i]);
+
+ adjustSize();
+}
+
+void GoogleFetcherDialog::setImageList(const GoogleImageList &imageList)
+{
+ m_imageList=imageList;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// public slots
+////////////////////////////////////////////////////////////////////////////////
+
+void GoogleFetcherDialog::refreshScreen(GoogleImageList &imageList)
+{
+ setImageList(imageList);
+ setLayout();
+}
+
+int GoogleFetcherDialog::exec()
+{
+ setLayout();
+ return KDialogBase::exec();
+}
+
+void GoogleFetcherDialog::slotOk()
+{
+ uint selectedIndex = m_iconWidget->index(m_iconWidget->currentItem());
+ m_pixmap = pixmapFromURL(m_imageList[selectedIndex].imageURL());
+
+ if(m_pixmap.isNull()) {
+ KMessageBox::sorry(this,
+ i18n("The cover you have selected is unavailable. Please select another."),
+ i18n("Cover Unavailable"));
+ QPixmap blankPix;
+ blankPix.resize(80, 80);
+ blankPix.fill();
+ m_iconWidget->currentItem()->setPixmap(blankPix, true, true);
+ return;
+ }
+
+ m_takeIt = true;
+ m_newSearch = false;
+ hide();
+}
+
+void GoogleFetcherDialog::slotCancel()
+{
+ m_takeIt = true;
+ m_newSearch = false;
+ m_pixmap = QPixmap();
+ hide();
+}
+
+void GoogleFetcherDialog::slotUser1()
+{
+ m_takeIt = false;
+ m_newSearch = true;
+ m_pixmap = QPixmap();
+ hide();
+}
+
+void GoogleFetcherDialog::imgSizeChanged(int index)
+{
+ GoogleFetcher::ImageSize imageSize = GoogleFetcher::All;
+ switch (index) {
+ case 1:
+ imageSize = GoogleFetcher::Icon;
+ break;
+ case 2:
+ imageSize = GoogleFetcher::Small;
+ break;
+ case 3:
+ imageSize = GoogleFetcher::Medium;
+ break;
+ case 4:
+ imageSize=GoogleFetcher::Large;
+ break;
+ case 5:
+ imageSize=GoogleFetcher::XLarge;
+ break;
+ default:
+ break;
+ }
+ emit sizeChanged(imageSize);
+}
+
+QPixmap GoogleFetcherDialog::fetchedImage(uint index) const
+{
+ return (index > m_imageList.count()) ? QPixmap() : pixmapFromURL(m_imageList[index].imageURL());
+}
+
+QPixmap GoogleFetcherDialog::pixmapFromURL(const KURL &url) const
+{
+ QString file;
+
+ if(KIO::NetAccess::download(url, file, 0)) {
+ QPixmap pixmap = QPixmap(file);
+ KIO::NetAccess::removeTempFile(file);
+ return pixmap;
+ }
+ KIO::NetAccess::removeTempFile(file);
+ return QPixmap();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CoverIconViewItem
+////////////////////////////////////////////////////////////////////////////////
+
+CoverIconViewItem::CoverIconViewItem(QIconView *parent, const GoogleImage &image) :
+ QObject(parent), KIconViewItem(parent, parent->lastItem(), image.size()), m_job(0)
+{
+ // Set up the iconViewItem
+
+ QPixmap mainMap;
+ mainMap.resize(80, 80);
+ mainMap.fill();
+ setPixmap(mainMap, true, true);
+
+ // Start downloading the image.
+
+ m_job = KIO::get(image.thumbURL(), false, false);
+ connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(imageResult(KIO::Job *)));
+ connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
+ this, SLOT(imageData(KIO::Job *, const QByteArray &)));
+}
+
+CoverIconViewItem::~CoverIconViewItem()
+{
+ if(m_job) {
+ m_job->kill();
+
+ // Drain results issued by KIO before being deleted,
+ // and before deleting the job.
+ kapp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
+
+ delete m_job;
+ }
+}
+
+void CoverIconViewItem::imageData(KIO::Job *, const QByteArray &data)
+{
+ int currentSize = m_buffer.size();
+ m_buffer.resize(currentSize + data.size(), QGArray::SpeedOptim);
+ memcpy(&(m_buffer.data()[currentSize]), data.data(), data.size());
+}
+
+void CoverIconViewItem::imageResult(KIO::Job *job)
+{
+ if(job->error())
+ return;
+
+ QPixmap iconImage(m_buffer);
+ iconImage = QImage(iconImage.convertToImage()).smoothScale(80, 80);
+ setPixmap(iconImage, true, true);
+}
+
+#include "googlefetcherdialog.moc"
diff --git a/kaffeine/src/input/audiobrowser/googlefetcherdialog.h b/kaffeine/src/input/audiobrowser/googlefetcherdialog.h
new file mode 100644
index 0000000..48ec70c
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/googlefetcherdialog.h
@@ -0,0 +1,98 @@
+/*
+ * googlefetcherdialog.h
+ *
+ * Copyright (C) 2004 Nathan Toone <nathan@toonetown.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef GOOGLEFETCHERDIALOG_H
+#define GOOGLEFETCHERDIALOG_H
+
+#include <kiconview.h>
+#include <kio/job.h>
+
+#include "googlefetcher.h"
+
+class KURL;
+
+class GoogleFetcherDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ GoogleFetcherDialog(const QString &name,
+ const GoogleImageList &urlList,
+ const QString &artist,
+ const QString &album,
+ QWidget *parent = 0);
+
+ virtual ~GoogleFetcherDialog();
+
+ QPixmap result() const { return m_pixmap; }
+ bool takeIt() const { return m_takeIt; }
+ bool newSearch() const { return m_newSearch; }
+
+ void setLayout();
+ void setImageList(const GoogleImageList &urlList);
+
+public slots:
+ int exec();
+ void refreshScreen(GoogleImageList &list);
+
+signals:
+ void sizeChanged(GoogleFetcher::ImageSize);
+
+protected slots:
+ void slotOk();
+ void slotCancel();
+ void slotUser1();
+ void imgSizeChanged(int index);
+
+private:
+ QPixmap fetchedImage(uint index) const;
+ QPixmap pixmapFromURL(const KURL &url) const;
+
+ QPixmap m_pixmap;
+ GoogleImageList m_imageList;
+ KIconView *m_iconWidget;
+ bool m_takeIt;
+ bool m_newSearch;
+ QString m_artist, m_album;
+};
+
+namespace KIO
+{
+ class TransferJob;
+}
+
+class CoverIconViewItem : public QObject, public KIconViewItem
+{
+ Q_OBJECT
+
+public:
+ CoverIconViewItem(QIconView *parent, const GoogleImage &image);
+ ~CoverIconViewItem();
+
+private slots:
+ void imageData(KIO::Job *job, const QByteArray &data);
+ void imageResult(KIO::Job* job);
+
+private:
+ QByteArray m_buffer;
+ QGuardedPtr<KIO::TransferJob> m_job;
+};
+
+#endif /* GOOGLEFETCHERDIALOG_H */
diff --git a/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc b/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc
new file mode 100644
index 0000000..a274d74
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/kaffeineplaylist.rc
@@ -0,0 +1,17 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kaffeineplaylist" version="4">
+<MenuBar>
+ <Menu name="playlist"><text>Play&amp;list</text>
+ <Action name="playlist_shuffle"/>
+ <Action name="playlist_repeat"/>
+ <Action name="playlist_autocover"/>
+ <Action name="playlist_showplayer"/>
+ <Separator/>
+ <Action name="playlist_clear"/>
+ <Action name="playlist_new"/>
+ <Action name="playlist_load"/>
+ <Action name="playlist_save_as"/>
+ <Action name="playlist_remove"/>
+ </Menu>
+</MenuBar>
+</kpartgui>
diff --git a/kaffeine/src/input/audiobrowser/playlist.cpp b/kaffeine/src/input/audiobrowser/playlist.cpp
new file mode 100644
index 0000000..480d70b
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlist.cpp
@@ -0,0 +1,2365 @@
+/*
+ * playlist.cpp
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
+ * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <krandomsequence.h>
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <kio/netaccess.h>
+#include <kio/job.h>
+#include <kprogress.h>
+#include <kfilemetainfo.h>
+#include <klineedit.h>
+#include <kcombobox.h>
+#include <kpushbutton.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <kaccel.h>
+#include <dcopref.h>
+#include <ktoolbar.h>
+#include <kcolordialog.h>
+#include <kurlcombobox.h>
+#include <kurlcompletion.h>
+
+#include <qlabel.h>
+#include <qclipboard.h>
+#include <qdragobject.h>
+#include <qstringlist.h>
+#include <qdom.h>
+#include <qxml.h>
+#include <qregexp.h>
+#include <qheader.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qvbox.h>
+#include <qlistbox.h>
+#include <qtextcodec.h>
+#include <qtooltip.h>
+#include <qinputdialog.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+#include <qpopupmenu.h>
+
+#include "googlefetcher.h"
+#include "mrl.h"
+#include "playlistimport.h"
+#include "playlistitem.h"
+#include "playlist.h"
+#include "playlist.moc"
+
+
+
+RollTitle::RollTitle( QWidget *parent ) : QLabel( "I", parent )
+{
+ QColorGroup cg = parentWidget()->colorGroup();
+ QColor base = cg.base();
+ QColor selection = cg.highlight();
+ int r = (base.red() + selection.red()) / 2;
+ int b = (base.blue() + selection.blue()) / 2;
+ int g = (base.green() + selection.green()) / 2;
+ back = QColor(r, g, b);
+ fore = parentWidget()->colorGroup().text();
+ setPaletteBackgroundColor( back );
+ setPaletteForegroundColor( fore );
+ setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ title = " ##### ";
+ titleOffset = 0;
+ setTitle( title );
+ connect( &titleTimer, SIGNAL( timeout() ), this, SLOT( rollTitle() ) );
+ titleTimer.start( 50 );
+}
+
+void RollTitle::setTitle( MRL mrl )
+{
+ title = " ##### ";
+ QString s1 = mrl.artist().stripWhiteSpace();
+ QString s2 = mrl.album().stripWhiteSpace();
+ QString s3 = mrl.title().stripWhiteSpace();
+ if ( !s1.isEmpty() )
+ title+= s1+" - ";
+ if ( !s2.isEmpty() )
+ title+= s2+" - ";
+ if ( s3.isEmpty() )
+ title+= mrl.url();
+ else
+ title+= s3;
+ titleOffset = 0;
+ setTitle( title );
+}
+
+void RollTitle::setTitle( QString t )
+{
+ QLabel *lab = new QLabel( t, this );
+ lab->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ lab->resize( lab->sizeHint() );
+ int x = 2*lab->frameWidth();
+ titlePix = QPixmap( lab->width()-x, height()-x, -1, QPixmap::BestOptim );
+ delete lab;
+ QPainter p( &titlePix );
+ p.fillRect( 0, 0, titlePix.width(), titlePix.height(), back );
+ p.setPen( fore );
+ p.setFont( font() );
+ p.drawText( QRect(0,(titlePix.height()-QFontInfo(font()).pointSize())/2,titlePix.width(),QFontInfo(font()).pointSize()*2), Qt::AlignAuto|Qt::SingleLine, t );
+ p.end();
+}
+
+void RollTitle::rollTitle()
+{
+ int w = 2*frameWidth();
+ QPixmap pix( width()-w, height()-w, -1, QPixmap::BestOptim );
+ QPainter p1( &pix );
+ p1.fillRect( 0, 0, pix.width(), pix.height(), back );
+ p1.end();
+ int x = titlePix.width()-titleOffset;
+ bitBlt( &pix, 0, 0, &titlePix, titleOffset, 0, x, titlePix.height(), CopyROP );
+ while ( x<pix.width() ) {
+ bitBlt( &pix, x, 0, &titlePix, 0, 0, titlePix.width(), titlePix.height(), CopyROP );
+ x+= titlePix.width();
+ }
+ ++titleOffset;
+ if ( titleOffset>titlePix.width() )
+ titleOffset = 0;
+ bitBlt( this, w/2, w/2, &pix, 0, 0, width()-w, height()-w, CopyROP );
+}
+
+void RollTitle::paintEvent( QPaintEvent *pe )
+{
+ QLabel::paintEvent( pe );
+ QColorGroup cg = parentWidget()->colorGroup();
+ QColor base = cg.base();
+ QColor selection = cg.highlight();
+ int r = (base.red() + selection.red()) / 2;
+ int b = (base.blue() + selection.blue()) / 2;
+ int g = (base.green() + selection.green()) / 2;
+ back=QColor(r,g,b);
+ setPaletteBackgroundColor( back );
+ fore = parentWidget()->colorGroup().text();
+ setPaletteForegroundColor( fore );
+ setTitle( title );
+}
+
+
+
+struct CoverPopup : public QWidget
+{
+ CoverPopup(const QPixmap &image, const QPoint &p) :
+ QWidget(0, 0, WDestructiveClose | WX11BypassWM)
+ {
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ QLabel *label = new QLabel(this);
+
+ layout->addWidget(label);
+ label->setFrameStyle(QFrame::Box | QFrame::Raised);
+ label->setLineWidth(1);
+ label->setPixmap(image);
+
+ setGeometry(p.x(), p.y(), label->width(), label->height());
+ show();
+ }
+ virtual void leaveEvent(QEvent *) { close(); }
+ virtual void mouseReleaseEvent(QMouseEvent *) { close(); }
+};
+
+CoverFrame::CoverFrame( QWidget *parent ) : QFrame( parent )
+{
+ imagePath = "";
+ QString path = locate("appdata", "nocover.png");
+ if ( !path )
+ path = locate("data", "kaffeine/nocover.png");
+ noCoverPix.convertFromImage( QImage(path) );
+ setPaletteBackgroundPixmap( noCoverPix );
+}
+
+CoverFrame::~CoverFrame()
+{
+}
+
+void CoverFrame::setCoverPixmap( const QString &path )
+{
+ QPixmap pix;
+ QImage img;
+
+ img = QImage( path );
+ if ( !img.isNull() ) {
+ img = img.smoothScale( 80, 80 );
+ pix.convertFromImage( img );
+ setPaletteBackgroundPixmap( pix );
+ imagePath = path;
+ }
+ else {
+ setPaletteBackgroundPixmap( noCoverPix );
+ imagePath = "";
+ }
+}
+
+void CoverFrame::popup( const QPixmap &pix ) const
+{
+ QPoint mouse = QCursor::pos();
+ QRect desktop = KApplication::desktop()->screenGeometry(mouse);
+ int x = mouse.x();
+ int y = mouse.y();
+ int height = pix.height() + 4;
+ int width = pix.width() + 4;
+
+ // Detect the right direction to pop up (always towards the center of the
+ // screen), try to pop up with the mouse pointer 10 pixels into the image in
+ // both directions. If we're too close to the screen border for this margin,
+ // show it at the screen edge, accounting for the four pixels (two on each
+ // side) for the window border.
+
+ if(x - desktop.x() < desktop.width() / 2)
+ x = (x - desktop.x() < 10) ? desktop.x() : (x - 10);
+ else
+ x = (x - desktop.x() > desktop.width() - 10) ? desktop.width() - width +desktop.x() : (x - width + 10);
+
+ if(y - desktop.y() < desktop.height() / 2)
+ y = (y - desktop.y() < 10) ? desktop.y() : (y - 10);
+ else
+ y = (y - desktop.y() > desktop.height() - 10) ? desktop.height() - height + desktop.y() : (y - height + 10);
+
+ new CoverPopup( pix, QPoint(x, y) );
+}
+
+void CoverFrame::mousePressEvent( QMouseEvent *e )
+{
+ int i;
+ QPixmap pix;
+
+ switch ( e->button() ) {
+ case LeftButton: {
+ if ( imagePath.isEmpty() )
+ break;
+ pix.convertFromImage( QImage( imagePath ) );
+ if ( !pix.isNull() )
+ popup( pix );
+ break;
+ }
+ case RightButton: {
+ QPopupMenu pop( this );
+ pop.insertItem( i18n("Choose a Cover..."), 1 );
+ pop.insertItem( i18n("Gallery..."), 2 );
+ i = pop.exec( QCursor::pos() );
+ if ( i==1 )
+ emit changeCurrentCover();
+ else if ( i==2 )
+ emit gallery();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+PlayList::PlayList( QWidget* parent, QObject *objParent, const char *name ) : KaffeineInput(objParent , name),
+ m_playTime(0), m_playTimeVisible(0), m_countVisible(0), m_searchSelection(false),
+ m_metaOnLoading(true), m_sortAscending(true), m_currentEntry(NULL), m_currentRandomListEntry(-1),
+ m_endless(false), m_random(false), m_useAlternateEncoding(false), m_alternateEncoding("ISO 8859-1")
+{
+ google = NULL;
+
+ mainWidget = new QVBox( parent );
+ //mainWidget->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred) );
+ hSplit = new QSplitter( mainWidget );
+ hSplit->setOpaqueResize( true );
+ panel = new QVBox( hSplit );
+ playlist = new QWidget( hSplit );
+ hSplit->moveToFirst( panel );
+ hSplit->setResizeMode( panel, QSplitter::KeepSize );
+
+ vSplit = new QSplitter( QSplitter::Vertical, panel );
+ vSplit->setOpaqueResize( true );
+ QWidget *vb = new QWidget( vSplit );
+ KToolBar *tb = new KToolBar( vb );
+ QVBoxLayout *v = new QVBoxLayout( vb, 0, 0 );
+ v->addWidget( tb );
+ tb->setIconSize( 16 );
+
+ browserComb = new KURLComboBox( KURLComboBox::Directories, true, vb );
+ browserComb->setCompletionObject( new KURLCompletion( KURLCompletion::DirCompletion ) );
+ browserComb->setAutoDeleteCompletionObject( true );
+ browserComb->setMaxItems( 10 );
+ browserComb->setFocusPolicy(QWidget::ClickFocus);
+
+
+ /* if (!m_medium)
+ m_combo->lineEdit()->setText( location->path() );
+ else
+ m_combo->lineEdit()->setText( "/" );*/
+
+ QVBoxLayout *v1 = new QVBoxLayout( 0, 3, 3 );
+ v1->addWidget( browserComb );
+ fileBrowser = new KDirOperator( KURL("/"), vb );
+ fileBrowser->setupMenu( KDirOperator::SortActions|KDirOperator::NavActions|KDirOperator::ViewActions );
+ view = new KFileIconView( fileBrowser, "view" );
+ view->setSelectionMode( KFile::Multi );
+ fileBrowser->setMode( KFile::Files );
+ fileBrowser->setView( view );
+ fileBrowser->setViewConfig( KGlobal::config(), "PlaylistFileBrowser" );
+ fileBrowser->setOnlyDoubleClickSelectsFiles( true );
+ v1->addWidget( fileBrowser );
+ v->addLayout( v1 );
+
+ KActionCollection *col = fileBrowser->actionCollection();
+ col->action( "up" )->plug( tb );
+ col->action( "back" )->plug( tb );
+ col->action( "forward" )->plug( tb );
+ col->action( "reload" )->plug( tb );
+ col->action( "home" )->plug( tb );
+
+ vSplit->moveToFirst( vb );
+ playerBox = new QVBox( vSplit );
+ playerBox->setMinimumHeight( 50 );
+ playerBox->setMinimumWidth( 200 );
+ vSplit->moveToLast( playerBox );
+
+ m_playlistDirectory = locateLocal("appdata", "playlists");
+ m_playlistDirectory.append("/");
+ KIO::NetAccess::mkdir(m_playlistDirectory, mainWidget);
+ kdDebug() << "PLAYLIST" << endl;
+
+ QGridLayout* layout = new QGridLayout( playlist, 4, 2, 3 );
+
+ m_list = new UrlListView(playlist);
+ mainWidget->setAcceptDrops(true);
+ m_list->setHScrollBarMode(KListView::AlwaysOff);
+ m_list->setItemMargin(2);
+ m_list->setMargin(0);
+ m_list->setSelectionMode(QListView::Extended);
+ m_list->addColumn("");
+ m_list->addColumn(i18n("Title"));
+ m_list->addColumn(i18n("Artist"));
+ m_list->addColumn(i18n("Album"));
+ m_list->addColumn(i18n("Track"));
+ m_list->addColumn(i18n("Length"));
+ m_list->setShowToolTips(true);
+ m_list->setColumnWidthMode(MIME_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(TITLE_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(ARTIST_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(ALBUM_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(TRACK_COLUMN, QListView::Manual);
+ m_list->setColumnWidthMode(LENGTH_COLUMN, QListView::Manual);
+ m_list->setResizeMode(QListView::NoColumn);
+ KConfig* config = kapp->config();
+ m_list->restoreLayout(config, "Playlist Layout");
+ m_list->setFullWidth(true);
+ m_list->setSorting(-1);
+ m_list->setDragEnabled(true);
+ m_list->setAcceptDrops(true);
+ m_list->setDropVisualizer(true);
+ m_list->setItemsMovable(true);
+ m_list->setItemsRenameable(true);
+ m_list->setRenameable(TITLE_COLUMN);
+ m_list->setRenameable(ARTIST_COLUMN);
+ m_list->setRenameable(ALBUM_COLUMN);
+ m_list->setRenameable(TRACK_COLUMN);
+ m_list->setAllColumnsShowFocus(true);
+ m_list->setShowSortIndicator(true);
+ layout->addMultiCellWidget(m_list, 3, 3, 0, 1);
+
+ coverFrame = new CoverFrame( playlist );
+ coverFrame->setFixedWidth( 80 );
+ coverFrame->setFixedHeight( 80 );
+ layout->addMultiCellWidget(coverFrame, 0, 2, 0, 0);
+
+ QHBoxLayout *h1 = new QHBoxLayout();
+ searchBtn = new QToolButton( playlist );
+ searchBtn->setAutoRaise( true );
+ QToolTip::add( searchBtn, i18n("Search"));
+ searchBtn->setIconSet( KGlobal::iconLoader()->loadIconSet("locationbar_erase", KIcon::Small) );
+ h1->addWidget( searchBtn );
+ QLabel* filterLabel = new QLabel(i18n("Filter") + ":", playlist);
+ h1->addWidget(filterLabel);
+ m_playlistFilter = new KLineEdit(playlist);
+ m_playlistFilter->setFocusPolicy(QWidget::ClickFocus);
+ h1->addWidget(m_playlistFilter);
+ layout->addLayout( h1, 2, 1 );
+
+ QHBoxLayout *h2 = new QHBoxLayout();
+ QLabel* playlistLabel = new QLabel(i18n("Playlist:"), playlist);
+ h2->addWidget(playlistLabel);
+ m_playlistSelector = new KComboBox( playlist );
+ m_playlistSelector->setMinimumWidth(10);
+ m_playlistSelector->setSizePolicy( QSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Preferred) );
+ m_playlistSelector->setEditable(true);
+ m_playlistSelector->setDuplicatesEnabled(false);
+ m_playlistSelector->setFocusPolicy(QWidget::ClickFocus);
+ QToolTip::add(m_playlistSelector, i18n("Select the active playlist. To change playlist name edit it and confirm with 'Return'."));
+ h2->addWidget(m_playlistSelector);
+ layout->addLayout( h2, 1, 1 );
+
+ roller = new RollTitle( playlist );
+ layout->addWidget( roller, 0, 1 );
+
+ KAccel* accel = new KAccel(mainWidget);
+ accel->insert("Delete selected", Qt::Key_Delete, this, SLOT(slotRemoveSelected()));
+
+ m_isCurrentEntry = UserIcon("playing");
+ m_cdPixmap = KGlobal::iconLoader()->loadIcon("cdtrack", KIcon::Small);
+
+ setXMLFile("kaffeineplaylist.rc");
+ setupActions();
+
+ QStrList formats = QImageIO::outputFormats();
+ coverImageFormat = "PNG";
+ for (int i=0; i<(int)formats.count(); i++ ) {
+ if ( QString(formats.at(i))=="JPEG" ) {
+ coverImageFormat = "JPEG";
+ break;
+ }
+ }
+
+ loadConfig( KGlobal::config() );
+
+ connect(coverFrame, SIGNAL(changeCurrentCover()), this, SLOT(chooseCurrentCover()));
+ connect(coverFrame, SIGNAL(gallery()), this, SLOT(showGallery()));
+ connect(browserComb, SIGNAL(urlActivated( const KURL& )), this, SLOT(setBrowserURL( const KURL& )));
+ connect(browserComb, SIGNAL(returnPressed( const QString& )), this, SLOT(setBrowserURL( const QString& )));
+ connect(fileBrowser, SIGNAL(urlEntered( const KURL& )), this, SLOT(browserURLChanged( const KURL& )));
+ connect(fileBrowser, SIGNAL(fileSelected(const KFileItem*)), this, SLOT(fileSelected(const KFileItem*)));
+ connect(m_playlistFilter, SIGNAL(textChanged(const QString&)), this, SLOT(slotFindText(const QString&)));
+ connect( searchBtn, SIGNAL(clicked()), this, SLOT(resetSearch()) );
+ connect(m_playlistSelector, SIGNAL(returnPressed(const QString&)), this, SLOT(slotNewPlaylistName(const QString&)));
+ connect(m_playlistSelector, SIGNAL(activated(int)),this, SLOT(slotPlaylistActivated(int)));
+ connect(m_list, SIGNAL(dropped(QDropEvent*, QListViewItem*)), this, SLOT(slotDropEvent(QDropEvent*, QListViewItem*)));
+ connect(m_list, SIGNAL(aboutToMove()), this, SLOT(slotPreDropEvent()));
+ connect(m_list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*)));
+ connect(m_list, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*)));
+ connect(m_list, SIGNAL(signalCut()), this, SLOT(slotCut()));
+ connect(m_list, SIGNAL(signalCopy()), this, SLOT(slotCopy()));
+ connect(m_list, SIGNAL(signalPaste()), this, SLOT(slotPaste()));
+ connect(m_list, SIGNAL(signalSelectAll()), this, SLOT(slotSelectAll()));
+ connect(m_list, SIGNAL(signalPlayItem(QListViewItem*)), this, SLOT(slotPlayDirect(QListViewItem*)));
+ connect(m_list, SIGNAL(signalPlaylistFromSelected()), this, SLOT(slotPlaylistFromSelected()));
+ connect(m_list, SIGNAL(signalAddToQueue(MRL)), this, SLOT(slotAddToQueue(MRL)));
+ connect(m_list->header(), SIGNAL(clicked(int)), this, SLOT(slotSort(int)));
+}
+
+void PlayList::togglePanel()
+{
+ if ( panel->isHidden() )
+ panel->show();
+ else
+ panel->hide();
+}
+
+void PlayList::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames )
+{
+ uiNames.append( i18n("Play Playlist") );
+ iconNames.append( "view_text" );
+ targetNames.append( "PLAYLIST" );
+}
+
+bool PlayList::execTarget( const QString &target )
+{
+ if ( target=="PLAYLIST" ) {
+ emit showMe( this );
+ QTimer::singleShot( 100, this, SLOT(startPlaylist()) );
+ return true;
+ }
+ return false;
+}
+
+void PlayList::setFileFilter( const QString& filter )
+{
+ m_fileFilter = filter;
+ fileBrowser->setNameFilter( m_fileFilter );
+}
+
+PlayList::~PlayList()
+{
+ delete m_list;
+}
+
+void PlayList::setupActions()
+{
+ m_repeat = new KToggleAction(i18n("&Repeat"), 0 , CTRL|Key_E, this, SLOT(slotRepeat()), actionCollection(),"playlist_repeat");
+ m_repeat->setStatusText(i18n("Loop playlist"));
+ m_shuffle = new KToggleAction(i18n("Sh&uffle"), 0 , CTRL|Key_R, this, SLOT(slotShuffle()), actionCollection(),"playlist_shuffle");
+ m_shuffle->setStatusText(i18n("Play items in random order"));
+ m_autoCover = new KToggleAction(i18n("Autodownload covers"), 0 , 0, this, SLOT(slotAutoCover()), actionCollection(),"playlist_autocover");
+ m_autoCover->setStatusText(i18n("Automatic dowloading of covers"));
+ m_showPlayer = new KToggleAction(i18n("Don't switch to player window"), 0 , 0, this, SLOT(slotShowPlayer()), actionCollection(),"playlist_showplayer");
+ m_showPlayer->setStatusText(i18n("Don't switch automatically to player window"));
+ new KAction(i18n("&Clear Current Playlist"), "eraser", 0, this, SLOT(slotClearList()), actionCollection(), "playlist_clear");
+ new KAction(i18n("Ne&w Playlist"), "filenew", 0, this, SLOT(slotNewList()), actionCollection(), "playlist_new");
+ new KAction(i18n("&Import Playlist..."), "project_open", 0, this, SLOT(slotPlaylistLoad()), actionCollection(), "playlist_load");
+ new KAction(i18n("&Save Current Playlist As..."), "filesaveas", 0, this, SLOT(slotPlaylistSaveAs()), actionCollection(), "playlist_save_as");
+ new KAction(i18n("Re&move Current Playlist"), "fileclose", 0, this, SLOT(slotPlaylistRemove()), actionCollection(), "playlist_remove");
+}
+
+void PlayList::slotClearList()
+{
+ clearList();
+}
+
+void PlayList::slotRepeat()
+{
+ setEndless(m_repeat->isChecked());
+}
+
+void PlayList::slotShuffle()
+{
+ setRandom(m_shuffle->isChecked());
+}
+
+void PlayList::slotAutoCover()
+{
+ m_cover = m_autoCover->isChecked();
+}
+
+void PlayList::slotShowPlayer()
+{
+}
+
+void PlayList::slotToggleShuffle()
+{
+ m_shuffle->setChecked(!m_shuffle->isChecked());
+ slotShuffle();
+}
+
+void PlayList::slotPlaylistLoad()
+{
+ QString path = KFileDialog::getOpenFileName(":kaffeine_openPlaylist", QString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n*.*|" + i18n("All Files"), 0, i18n("Open Playlist"));
+ if (path.isEmpty() || (!path.contains(".kaffeine", false)))
+ return;
+
+ loadPlaylist(path);
+}
+
+void PlayList::slotPlaylistSaveAs()
+{
+ QString startPath = ":kaffeine_savePlaylist";
+ //if (!lastPlaylist.isEmpty()) startPath = lastPlaylist;
+ QString path = KFileDialog::getSaveFileName(startPath,
+ QString("*.kaffeine|") + i18n("Kaffeine Playlists") + "\n" +
+ QString("*.m3u|") + i18n("M3U Playlists") + "\n" +
+ QString("*.pls|") + i18n("PLS Playlists") + "\n" +
+ "*.*|" + i18n("All Files"), 0, i18n("Save Playlist"));
+
+ if ( path.isEmpty() )
+ return;
+ if ( path.right(4).lower() == ".m3u" ) {
+ exportM3UPlaylist(path);
+ } else if ( path.right(4).lower() == ".pls" ) {
+ exportPLSPlaylist(path);
+ } else if ( path.right(9).lower() == ".kaffeine" ) {
+ savePlaylist(path);
+ } else {
+ path.append(".kaffeine");
+ savePlaylist(path);
+ }
+}
+
+void PlayList::slotPlaylistRemove()
+{
+ removeCurrentPlaylist();
+}
+
+QWidget* PlayList::wantPlayerWindow()
+{
+ return playerBox;
+}
+
+QWidget* PlayList::inputMainWidget()
+{
+ return mainWidget;
+}
+
+void PlayList::loadConfig(KConfig* config)
+{
+ QValueList<int> sl;
+ bool b;
+
+ config->setGroup("Playlist");
+ b = config->readBoolEntry("Endless Mode", false);
+ m_repeat->setChecked(b);
+ setEndless(b);
+ b = config->readBoolEntry("Random Mode", false);
+ m_shuffle->setChecked(b);
+ setRandom(b);
+ b = config->readBoolEntry("AutoCover", false);
+ m_autoCover->setChecked(b);
+ m_cover = b;
+ b = config->readBoolEntry("DontShowPlayer", false);
+ m_showPlayer->setChecked(b);
+
+ sl = config->readIntListEntry("HSplitSizes");
+ if ( sl.count() )
+ hSplit->setSizes( sl );
+ else {
+ sl.append( 200 );
+ sl.append( 200 );
+ hSplit->setSizes( sl );
+ }
+ vSplit->setSizes( config->readIntListEntry("VSplitSizes") );
+ QStringList list;
+ list = config->readListEntry("Playlists");
+ if (!list.count())
+ {
+ list.append(i18n("Playlist") + "1");
+ }
+ int lastRegularPlaylist = list.count();
+ list.append(i18n("NEW"));
+ m_playlistSelector->insertStringList(list);
+ m_currentPlaylist = config->readNumEntry("Current", 0);
+ if (m_currentPlaylist > lastRegularPlaylist)
+ m_currentPlaylist = 0;
+ m_playlistSelector->setCurrentItem(m_currentPlaylist);
+ add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL);
+ m_nextPlaylistNumber = config->readNumEntry("Next Playlist", 2);
+ QString currentEntry = config->readEntry("Current Entry", QString());
+ if ((!currentEntry.isEmpty()) && (m_list->childCount()))
+ {
+ QListViewItem* tmp = findByURL(currentEntry);
+ if (tmp)
+ setCurrentEntry(tmp, false);
+ }
+ fileBrowser->readConfig( config, "PlaylistFileBrowser" );
+ fileBrowser->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )), true );
+ browserComb->setURL( KURL(config->readEntry( "FileBrowserURL", "/" )) );
+}
+
+void PlayList::saveConfig()
+{
+ saveConfig( KGlobal::config() );
+}
+
+void PlayList::saveConfig(KConfig* config)
+{
+ saveCurrentPlaylist();
+ config->setGroup("Playlist");
+ config->writeEntry("Endless Mode", m_repeat->isChecked());
+ config->writeEntry("Random Mode", m_shuffle->isChecked());
+ config->writeEntry("AutoCover", m_autoCover->isChecked());
+ config->writeEntry("DontShowPlayer", m_showPlayer->isChecked());
+ config->writeEntry( "HSplitSizes", hSplit->sizes() );
+ config->writeEntry( "VSplitSizes", vSplit->sizes() );
+ QStringList list;
+ QString text;
+ for (uint i=0; i < m_playlistSelector->listBox()->count(); i++)
+ {
+ text = m_playlistSelector->text(i);
+ if ( text != i18n("NEW") )
+ list.append(text);
+ }
+ config->writeEntry("Playlists", list);
+ config->writeEntry("Current", m_currentPlaylist);
+ config->writeEntry("Next Playlist", m_nextPlaylistNumber);
+ config->writeEntry("Current Entry", m_currentEntryMRL.url());
+ m_list->saveLayout(config, "Playlist Layout");
+ fileBrowser->writeConfig( config, "PlaylistFileBrowser" );
+ config->writeEntry( "FileBrowserURL", fileBrowser->url().url() );
+}
+
+void PlayList::closeEvent(QCloseEvent* ce)
+{
+ kdDebug() << "Playlist: close Event" << endl;
+ ce->ignore();
+}
+
+/******************************************
+ * get the urls from playlist
+ ******************************************/
+void PlayList::startPlaylist()
+{
+ MRL mrl;
+ if ( trackNumber( 1, mrl ) )
+ emit play( mrl, this );
+}
+
+bool PlayList::currentTrack( MRL &mrl )
+{
+ mrl = getCurrent();
+ if ( !mrl.isEmpty() )
+ return true;
+ else
+ return false;
+}
+
+MRL PlayList::getCurrent()
+{
+ if (isQueueMode())
+ {
+ m_queue.clear();
+ updateStatus();
+ }
+
+ if (m_random)
+ {
+ if (m_currentRandomListEntry == -1) return MRL();
+ setCurrentEntry(m_randomList.at(m_currentRandomListEntry));
+ return m_currentEntryMRL;
+ }
+
+ if (!m_currentEntry)
+ if (m_list->childCount() > 0)
+ {
+ if (m_list->firstChild()->isVisible())
+ setCurrentEntry(m_list->firstChild());
+ else
+ {
+ if (m_list->firstChild()->itemBelow())
+ setCurrentEntry(m_list->firstChild()->itemBelow());
+ else
+ return MRL();
+ }
+ }
+ else
+ return MRL();
+
+ setCurrentEntry(m_currentEntry);
+ return m_currentEntryMRL;
+}
+
+bool PlayList::playbackFinished( MRL &mrl )
+{
+ return nextTrack( mrl );
+}
+
+bool PlayList::nextTrack( MRL &mrl )
+{
+ if (isQueueMode())
+ {
+ mrl = m_queue.first();
+ m_queue.remove(m_queue.begin());
+ updateStatus();
+ return true;
+ }
+
+ if (!m_currentEntry) {
+ mrl = getCurrent();
+ if ( !mrl.isEmpty() )
+ return true;
+ else
+ return false;
+ }
+
+ if (m_random)
+ {
+ if ((m_currentRandomListEntry+1) < (int)m_randomList.count())
+ m_currentRandomListEntry += 1;
+ else
+ {
+ if (m_endless)
+ m_currentRandomListEntry = 0;
+ else
+ return false;
+ }
+ setCurrentEntry(m_randomList.at(m_currentRandomListEntry));
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+
+ QListViewItem* tmpItem;
+ tmpItem = m_currentEntry->itemBelow();
+
+ if (tmpItem)
+ {
+ setCurrentEntry(tmpItem);
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else
+ {
+ if (m_endless)
+ {
+ setCurrentEntry(m_list->firstChild());
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool PlayList::previousTrack( MRL &mrl )
+{
+ if (isQueueMode())
+ {
+ m_queue.clear();
+ updateStatus();
+ }
+
+ if (!m_currentEntry) {
+ mrl = getCurrent();
+ if ( !mrl.isEmpty() )
+ return true;
+ else
+ return false;
+ }
+
+ if (m_random) {
+ if (m_currentRandomListEntry > 0)
+ m_currentRandomListEntry -= 1;
+ else {
+ if (m_endless)
+ m_currentRandomListEntry = m_randomList.count()-1;
+ else
+ return false;
+ }
+ setCurrentEntry(m_randomList.at(m_currentRandomListEntry));
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+
+ QListViewItem* tmpItem;
+ tmpItem = m_currentEntry->itemAbove();
+
+ if (tmpItem) {
+ setCurrentEntry(tmpItem);
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else {
+ if (m_endless) {
+ setCurrentEntry(getLast());
+ mrl = m_currentEntryMRL;
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool PlayList::trackNumber( int number, MRL &mrl )
+{
+ if (number > m_list->childCount())
+ return false;
+
+ QListViewItem * item = m_list->firstChild();
+ for (int i = 1; i < number; i++)
+ item = item->nextSibling();
+
+ setCurrentEntry(item);
+ mrl = m_currentEntryMRL;
+ return true;
+}
+
+QListViewItem* PlayList::getLast()
+{
+ return m_list->lastItem();
+}
+
+QListViewItem* PlayList::getFirst()
+{
+ return m_list->firstChild();
+}
+
+QListViewItem* PlayList::findByURL(const QString& url)
+{
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->url() == url)
+ {
+ return (*it);
+ }
+ ++it;
+ }
+
+ /* fallback */
+ return getFirst();
+}
+
+/********* set current entry (with play icon) ****************/
+
+void PlayList::setCurrentEntry(QListViewItem* item, bool playIcon)
+{
+ PlaylistItem* newItem = dynamic_cast<PlaylistItem*>(item);
+ PlaylistItem* oldItem = dynamic_cast<PlaylistItem*>(m_currentEntry);
+ if (m_currentEntry)
+ {
+ oldItem->setPlaying(false);
+ m_currentEntry->setPixmap(TITLE_COLUMN, QPixmap());
+ }
+ if (playIcon)
+ {
+ newItem->setPlaying(true);
+ item->setPixmap(TITLE_COLUMN, m_isCurrentEntry);
+ }
+ m_currentEntry = item;
+ if (m_random)
+ m_currentRandomListEntry = m_randomList.find(item);
+ m_currentEntryMRL = newItem->toMRL();
+ roller->setTitle( m_currentEntryMRL );
+ m_list->setCurrentItem(m_currentEntry);
+
+ m_list->ensureVisible(10, m_list->itemPos(m_currentEntry), 10, 30);
+}
+
+QListViewItem* PlayList::insertItem(QListViewItem* after, const MRL& m)
+{
+ PlaylistItem* tmp = NULL;
+ MRL mrl(m);
+
+ m_list->setSorting(-1);
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->url() == mrl.url())
+ {
+ kdDebug() << "PlayList: Source '" << mrl.url() << "' still exists. Skipped." << endl;
+ return after;
+ }
+ ++it;
+ }
+
+ if (mrl.mime().isNull())
+ {
+ KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path());
+ mrl.setMime(mime->name());
+ }
+
+ tmp = new PlaylistItem(m_list, dynamic_cast<KListViewItem *>(after), mrl);
+ if (!tmp) return after;
+
+ if ((mrl.mime() == "video/dvd") || (mrl.mime() == "video/vcd") || (mrl.mime() == "audio/cd"))
+ tmp->setPixmap(MIME_COLUMN, m_cdPixmap);
+ else
+ tmp->setPixmap(MIME_COLUMN, KMimeType::mimeType(mrl.mime())->pixmap(KIcon::Small));
+
+ if (tmp->length().contains(':'))
+ m_playTime += timeStringToMs(tmp->length());
+
+ if (m_searchSelection)
+ {
+ QString text = m_playlistFilter->text();
+ if ((!tmp->title().contains(text, false)) && (!tmp->url().contains(text, false))
+ && (!tmp->artist().contains(text, false)) && (!tmp->album().contains(text, false)))
+ {
+ tmp->setVisible(false);
+ }
+ }
+
+ if (tmp->isVisible())
+ {
+ if (tmp->length().contains(':'));
+ m_playTimeVisible += timeStringToMs(tmp->length());
+ m_countVisible++;
+ }
+
+ return tmp;
+}
+
+void PlayList::fileSelected( const KFileItem *item )
+{
+ if ( !item )
+ return;
+ add( QStringList( item->url().path() ), NULL );
+ QListViewItem* tmp = findByURL(item->url().path());
+ if (tmp) {
+ setCurrentEntry(tmp);
+ emit play(m_currentEntryMRL, this);
+ }
+}
+
+void PlayList::setBrowserURL( const QString &path )
+{
+ fileBrowser->setURL( KURL(path), true );
+}
+
+void PlayList::setBrowserURL( const KURL &path )
+{
+ fileBrowser->setURL( path, true );
+}
+
+void PlayList::browserURLChanged( const KURL &u )
+{
+ QString url;
+
+ if ( u.isLocalFile() )
+ url = u.path();
+ else
+ url = u.prettyURL();
+
+ QStringList urls = browserComb->urls();
+ urls.remove( url ); // do not duplicate
+ urls.prepend( url );
+ browserComb->setURLs( urls, KURLComboBox::RemoveBottom );
+}
+
+void PlayList::add(const QString& url, QListViewItem* after)
+{
+ add(QStringList(url), after);
+}
+
+
+void PlayList::add(const QStringList& urlList, QListViewItem* after)
+{
+ QListViewItem* tmp = NULL;
+ QStringList urls(urlList);
+
+ QString ext;
+ QString subtitleURL;
+ QStringList subs;
+ KURL tmpKURL;
+ bool playlist;
+ MRL mrl;
+ QValueList<MRL> mrlList;
+ QString mediadevice="";
+
+ KProgressDialog* progress = NULL;
+ progress = new KProgressDialog(mainWidget, "importprogress", QString::null, i18n("Importing media resources..."));
+ progress->progressBar()->setTotalSteps(urls.count());
+ progress->show();
+
+ kdDebug() << "PlayList: add " << urls.count() << " items to playlist" << endl;
+
+ for (uint i = 0; i < urls.count(); i++)
+ {
+ mrl = MRL(urls[i]);
+ QString url(mrl.kurl().prettyURL());
+
+ if (mrl.kurl().protocol() == "media" || url.startsWith("system:/media/"))
+ {
+ QString mediaName;
+ if (url.startsWith("system:/media/"))
+ mediaName = url.mid(14);
+ else
+ mediaName = url.mid(7);
+ int slash = mediaName.find("/");
+ QString filePath(mediaName.mid(slash));
+ if (filePath == "/")
+ filePath = "";
+ mediaName = mediaName.left(slash);
+
+ DCOPRef mediamanager("kded","mediamanager");
+ DCOPReply reply = mediamanager.call("properties(QString)",mediaName);
+ if (reply.isValid())
+ {
+ QStringList properties = reply;
+ if (properties.isEmpty()) break;
+ url = properties[6] + filePath;
+ if (filePath.isEmpty())
+ {
+ if (properties[10] == "media/audiocd")
+ {
+ mediadevice = properties[5];
+ delete progress;
+ emit signalRequestForAudioCD(mediadevice);
+ return;
+ }
+ if (properties[10] == "media/dvdvideo")
+ {
+ mediadevice = properties[5];
+ delete progress;
+ emit signalRequestForDVD(mediadevice);
+ return;
+ }
+ if ((properties[10] == "media/vcd") || (properties[10] == "media/svcd"))
+ {
+ mediadevice = properties[5];
+ delete progress;
+ emit signalRequestForVCD(mediadevice);
+ return;
+ }
+ }
+ mrl = MRL(url);
+ }
+ }
+
+ if (mrl.kurl().isLocalFile())
+ {
+ if (!QFile::exists(mrl.kurl().path()))
+ continue;
+ mrl.setTitle(mrl.kurl().fileName());
+ mrl.setURL(mrl.kurl().path());
+ }
+ else
+ {
+ mrl.setTitle(mrl.url());
+ }
+
+ //kdDebug() << "PlayList: Check url " << mrl.url() << endl;
+ /*********** determine extension and mime type ************/
+
+ ext = mrl.kurl().fileName();
+ ext = ext.remove(0 , ext.findRev('.') +1).lower();
+ // kdDebug() << "Extension: " << ext << endl;
+
+ //kdDebug() << "PlayList: Try to determine mime of: " << mrl.url() << endl;
+ KMimeType::Ptr mime = KMimeType::findByURL(mrl.kurl().path()); /* works only with path() (without protocol)
+ e.g. http://www.somafm.com/indipop.pls
+ path: /indipop.pls */
+ //kdDebug() << "Mime: " << mime->name() << endl;
+ /*** check for kaffeine/noatun/pls/asx/m3u playlist ***/
+ mrl.setMime(mime->name());
+
+ /******** some special processing for local files! *******/
+ if (mrl.kurl().isLocalFile())
+ {
+ /* playlist ? */
+ if ((mime->name() == "text/plain") || (mime->name() == "text/xml") || (mime->name() == "application/x-kaffeine")
+ || (mime->name() == "audio/x-scpls") || (mime->name() == "audio/x-mpegurl" || (mime->name() == "audio/mpegurl")
+ || (ext == "asx") || (ext == "asf") || (ext == "wvx") || (ext == "wax"))) /* windows meta files */
+ {
+ kdDebug() << "PlayList: Check for kaffeine/noatun/m3u/pls/asx playlist\n";
+
+ mrlList.clear();
+ playlist = false;
+ QFile file(mrl.url());
+ file.open(IO_ReadOnly);
+
+ QTextStream stream(&file);
+ QString firstLine = stream.readLine();
+ QString secondLine = stream.readLine();
+ file.close();
+
+ if (secondLine.contains("kaffeine", false))
+ {
+ kdDebug() << "PlayList: Try loading kaffeine playlist\n";
+ playlist = PlaylistImport::kaffeine(mrl.url(), mrlList);
+ if (!playlist)
+ continue;
+ }
+ if (secondLine.contains("noatun", false))
+ {
+ kdDebug() << "PlayList: Try loading noatun playlist\n";
+ playlist = PlaylistImport::noatun(mrl.url(), mrlList);
+ }
+ if (firstLine.contains("asx", false))
+ {
+ kdDebug() << "PlayList: Try loading asx playlist\n";
+ playlist = PlaylistImport::asx(mrl.url(), mrlList);
+ }
+ if ( (firstLine.contains("[playlist]", false)) || (ext == "pls") )
+ {
+ kdDebug() << "PlayList: Try loading pls playlist\n";
+ playlist = PlaylistImport::pls(mrl.url(), mrlList);
+ }
+ if (ext == "m3u") //identify by extension
+ {
+ kdDebug() << "PlayList: Try loading m3u playlist\n";
+ playlist = PlaylistImport::m3u(mrl.url(), mrlList);
+ }
+ if (playlist)
+ {
+ QValueList<MRL>::ConstIterator end(mrlList.end());
+ for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it)
+ after = insertItem(after, *it);
+ continue;
+ }
+
+ }
+
+ /* check for ram playlist */
+ if ( (ext == "ra") || (ext == "rm") || (ext == "ram") || (ext == "lsc") || (ext == "pl") )
+ {
+ mrlList.clear();
+ kdDebug() << "PlayList: Try loading ram playlist\n";
+ if (PlaylistImport::ram(mrl, mrlList, mainWidget->parentWidget()))
+ {
+ QValueList<MRL>::ConstIterator end(mrlList.end());
+ for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it)
+ after = insertItem(after, *it);
+ continue;
+ }
+ }
+
+ /**** a directory ? ****/
+ if (mime->name() == "inode/directory")
+ {
+ kdDebug() << "PlayList: Add Directory: " << mrl.url() << endl;
+
+ QDir d(mrl.url());
+ uint x;
+
+ /* subdirs */
+ QStringList entryList = d.entryList(QDir::Dirs, QDir::Name);
+ for (x = 0; x < entryList.count(); x++)
+ {
+ if (entryList[x][0] != '.')
+ {
+ urls.append(mrl.url() + "/" + entryList[x]);
+ }
+ }
+
+ /* Media files */
+ /* Exclude subtitles because they are examined twice : */
+ /* Once for movie and once per subtitle - very annoying*/
+ QString fileFilter = m_fileFilter;
+ fileFilter.remove("*.srt",false);
+ fileFilter.remove("*.ssa",false);
+ fileFilter.remove("*.txt",false);
+ fileFilter.remove("*.asc",false);
+ fileFilter.remove("*.smi",false);
+ fileFilter.remove("*.sub",false);
+ entryList = d.entryList(fileFilter, QDir::Files, QDir::Name );
+ for (x = 0; x < entryList.count(); x++)
+ {
+ urls.append(mrl.url() + "/" + entryList[x]);
+ }
+
+ progress->progressBar()->setTotalSteps(urls.count());
+ continue; /* dont add directory to playlist */
+ }
+
+ /*** append subtitle files to the movie ***/
+ if ((ext == "srt") || (ext == "ssa") || (ext == "txt") ||
+ (ext == "asc") || (ext == "smi") || (ext == "sub"))
+ {
+ QStringList movies;
+ QString movieURL;
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->mime().contains("video"))
+ movies << dynamic_cast<PlaylistItem*>(*it)->url();
+ ++it;
+ }
+ if (movies.count() == 1)
+ movieURL = movies[0];
+ else if (movies.count() >= 2)
+ {
+ MovieChooser *mc = new MovieChooser(movies, mrl.url(), mainWidget);
+ if(mc->exec() == QDialog::Accepted)
+ movieURL = mc->getSelection();
+ delete mc;
+ }
+ it = m_list;
+ while (it.current())
+ {
+ if (dynamic_cast<PlaylistItem*>(*it)->url() == movieURL)
+ {
+ kdDebug() << "PlayList: adding subtitle to movie " << dynamic_cast<PlaylistItem*>(*it)->url() << endl;
+ (dynamic_cast<PlaylistItem*>(*it))->addSubtitle(mrl.url());
+ break;
+ }
+ ++it;
+ }
+ continue;
+ }
+
+ /*** get meta tags ****/
+ if (m_metaOnLoading)
+ getMetaInfo(mrl, mime->name());
+
+ /* Get all suported subs in movie dir, clear out
+ * those starting with a different name than the movie,
+ * prompt the user to select a sub
+ */
+ if (mime->name().contains("video"))
+ {
+ kdDebug() << "PlayList: Check for subtitle files" << endl;
+ subtitleURL = QString::null;
+ QDir *d = new QDir(mrl.url().section('/',0,-2));
+ QString filename = mrl.url().section('/',-1,-1);
+ subs = QStringList();
+ //Do a case insensitive search for subs
+ QStringList dirListing = d->entryList(QDir::Files|QDir::NoSymLinks); //cache directory listing
+ bool matches = false;
+ QStringList::Iterator end(dirListing.end());
+ for(QStringList::Iterator it = dirListing.begin(); it != end; ++it )
+ {
+ if(startsWith(*it, filename.section('.',0,-2), false)) //If filenames (without extensions) match
+ {
+ if( endsWith(*it, ".srt", false) || endsWith(*it, ".ssa", false) ||
+ endsWith(*it, ".txt", false) || endsWith(*it, ".smi", false) ||
+ endsWith(*it, ".asc", false) || endsWith(*it, ".sub", false) )
+ matches = true;
+
+ if(matches) {
+ subs.append(*it); //This is a subtitle for our movie
+ }
+ matches = false;
+ }
+ }
+
+ if((subs.count() > 1)) {
+ subs.prepend(i18n("(no subtitles)"));
+ subs.append(i18n("Other subtitle..."));
+ subtitleURL = QString::null;
+ SubtitleChooser *sc = new SubtitleChooser(subs, filename, mainWidget);
+
+ THERE: if(sc->exec() == QDialog::Accepted)
+ {
+ if((sc->getSelection() != i18n("(no subtitles)")) && (sc->getSelection() != i18n("Other subtitle...")))
+ subtitleURL = d->path()+"/"+sc->getSelection();
+ if((sc->getSelection() == i18n("Other subtitle...")))
+ {
+ subtitleURL = KFileDialog::getOpenURL(d->path(), i18n("*.smi *.srt *.sub *.txt *.ssa *.asc|Subtitle Files\n*.*|All Files"), 0, i18n("Select Subtitle File")).path();
+ if(subtitleURL.isEmpty())
+ {
+ subtitleURL = QString::null;
+ goto THERE;
+ }
+ else //The user has selected another sub, so add this to the list
+ {
+ subs.clear();
+ subs.append(subtitleURL);
+ }
+ }
+ }
+ delete sc;
+ subs.remove(i18n("(no subtitles)"));
+ subs.remove(i18n("Other subtitle..."));
+ }
+
+ //Add the full path to the subtitle name
+ for (unsigned int i = 0; i < subs.size(); i++ )
+ if(!subs[i].startsWith(d->path()))
+ subs[i] = d->path()+"/"+subs[i];
+
+ mrl.setSubtitleFiles(subs);
+ if ( subs.count()==1 )
+ subtitleURL = subs[0]; // Use this one.
+ if (!subtitleURL.isNull())
+ {
+ kdDebug() << "PlayList: Use subtitle file: " << subtitleURL << " for: " << mrl.url() << endl;
+ mrl.setCurrentSubtitle(subs.findIndex(subtitleURL));
+ }
+ }
+ } /* if localFile() */
+
+ tmp = insertItem(after, mrl);
+ if (tmp)
+ after = tmp;
+
+ if ( progress->wasCancelled() )
+ break;
+ progress->progressBar()->setProgress(i+1);
+ progress->setLabel(QString::number(i+1) + " / " + QString::number(progress->progressBar()->totalSteps()) + " " + i18n("Files"));
+ KApplication::kApplication()->processEvents();
+ }
+
+ delete progress;
+ if (m_random) createRandomList();
+ updateStatus();
+}
+
+void PlayList::add(const QValueList<MRL>& mrlList, QListViewItem* after)
+{
+ QValueList<MRL>::ConstIterator end(mrlList.end());
+ for (QValueList<MRL>::ConstIterator it = mrlList.begin(); it != end; ++it)
+ after = insertItem(after, *it);
+ updateStatus();
+ if (m_random) createRandomList();
+}
+
+void PlayList::slotPlayDirect(QListViewItem* item)
+{
+ if (!item) return;
+
+ setCurrentEntry(item);
+ emit play(m_currentEntryMRL, this);
+}
+
+void PlayList::setEndless(bool e)
+{
+ m_endless = e;
+}
+
+void PlayList::setRandom(bool r)
+{
+ m_random = r;
+ if (m_random) createRandomList();
+}
+
+void PlayList::createRandomList()
+{
+ kdDebug() << "PlayList: Create a random playlist" << endl;
+ m_randomList.clear();
+ m_currentRandomListEntry = 0;
+
+ QListViewItem* tmpItem = NULL;
+ tmpItem = m_list->firstChild();
+ if ( (tmpItem) && (!tmpItem->isVisible()) )
+ tmpItem = tmpItem->itemBelow();
+
+ while (tmpItem)
+ {
+ m_randomList.append(tmpItem);
+ tmpItem = tmpItem->itemBelow();
+ }
+
+ if (!(m_randomList.count() > 0))
+ {
+ m_currentRandomListEntry = -1;
+ return;
+ }
+
+ KRandomSequence r(KApplication::random());
+ r.randomize(&m_randomList);
+}
+
+void PlayList::clearList()
+{
+ m_list->clear();
+ m_randomList.clear();
+ m_playTime = 0;
+ m_playTimeVisible = 0;
+ m_countVisible = 0;
+ if (m_searchSelection)
+ {
+ m_playlistFilter->clear();
+ m_searchSelection = false;
+ }
+ updateStatus();
+ m_currentEntry = NULL;
+ m_currentRandomListEntry = -1;
+}
+
+void PlayList::slotDropEvent(QDropEvent* dev, QListViewItem* after)
+{
+ QStringList urls ,newurls;
+
+ m_list->setSorting(-1);
+ if (QUriDrag::decodeLocalFiles(dev, urls))
+ {
+ if (urls.count())
+ {
+ for (uint i=0; i < urls.count() ;i++)
+ {
+ //KURL url(QUriDrag::unicodeUriToUri(urls[i]));
+ //newurls << url.path(-1);
+ //kdDebug() << "PlayList: Dropped " << url.path() << endl;
+ newurls << urls[i];
+ kdDebug() << "PlayList: Dropped " << urls[i] << endl;
+ }
+ add(newurls, after);
+ }
+ else
+ {
+ QUriDrag::decodeToUnicodeUris(dev, urls);
+ if (urls.count())
+ add(urls, after);
+ }
+ }
+ else
+ if (strcmp(dev->format(), "text/x-moz-url") == 0) /* for mozilla drops */
+ {
+ QByteArray data = dev->encodedData("text/plain");
+ QString md(data);
+ add(md, after);
+ }
+}
+
+void PlayList::slotPreDropEvent()
+{
+ m_list->setSorting(-1);
+}
+
+void PlayList::slotSetAlternateColor( const QColor& col )
+{
+ m_list->setAlternateBackground( col );
+ m_altCol = col;
+ m_list->triggerUpdate();
+}
+
+void PlayList::useAlternateEncoding(bool useEncoding)
+{
+ m_useAlternateEncoding = useEncoding;
+}
+
+void PlayList::setAlternateEncoding(const QString& encoding)
+{
+ m_alternateEncoding = encoding;
+}
+
+
+void PlayList::getMetaInfo(MRL& mrl, const QString& mimeName)
+{
+ KFileMetaInfo* metaInfo = NULL;
+ KFileMetaInfoGroup metaGroup;
+ uint m, n;
+
+ metaInfo = new KFileMetaInfo(mrl.url(), mimeName);
+ QStringList groups = metaInfo->groups();
+ QStringList keys;
+ QString title;
+ QString artist;
+ QString album;
+
+ QTextCodec *altCodec;
+ QTextCodec *CodecUtf8;
+
+ altCodec = QTextCodec::codecForName(m_alternateEncoding.ascii());
+ CodecUtf8 = QTextCodec::codecForName("UTF-8");
+ //kdDebug() << "playlist: locale " << Codec->name << " index: " << m_alternateEncoding << endl;
+
+ for (m = 0; m < groups.count(); m++)
+ {
+ //kdDebug() << "Metainfo-Group: " << groups[m] << endl;
+ metaGroup = metaInfo->group(groups[m]);
+ keys = metaGroup.keys();
+ for (n = 0; n < keys.count(); n++)
+ {
+ //kdDebug() << "Metainfo-Key: " << keys[n] << endl;
+ if (keys[n] == "Length")
+ {
+ mrl.setLength(QTime().addSecs(metaGroup.item(keys[n]).value().toUInt()));
+ }
+
+ if (keys[n] == "Title")
+ {
+ title = metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace();
+ if ((!title.isEmpty()) && (title.contains(QRegExp("\\w")) > 2) && (title.left(5).lower() != "track"))
+ {
+ if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(title.ascii(), title.length()) < 0))
+ {
+ mrl.setTitle(altCodec->toUnicode(title.ascii()));
+ //kdDebug() << "playlist: Convert, locale name: " << altCodec->name() << title << endl;
+ }
+ else
+ {
+ mrl.setTitle(title);
+ //kdDebug() << "playlist: non Convert, locale name: " << CodecUtf8->name() << title << endl;
+ }
+ }
+ }
+
+ if (keys[n] == "Artist")
+ {
+ artist = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (!artist.isEmpty())
+ {
+ if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(artist.ascii(),artist.length()) < 0 ))
+ {
+ mrl.setArtist(altCodec->toUnicode(artist.ascii()));
+ }
+ else
+ {
+ mrl.setArtist(artist);
+ }
+ }
+ }
+
+ if (keys[n] == "Album")
+ {
+ album = (metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (!album.isEmpty())
+ {
+ if ((m_useAlternateEncoding) && (CodecUtf8->heuristicContentMatch(album.ascii(),album.length()) < 0 ))
+ {
+ mrl.setAlbum(altCodec->toUnicode(album.ascii()));
+ }
+ else
+ {
+ mrl.setAlbum(album);
+ }
+ }
+ }
+
+ if (keys[n] == "Tracknumber")
+ mrl.setTrack(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (keys[n] == "Date")
+ mrl.setYear(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ if (keys[n] == "Genre")
+ mrl.setGenre(metaGroup.item(keys[n]).value().toString().simplifyWhiteSpace());
+ }
+ }
+
+ delete metaInfo;
+}
+
+void PlayList::mergeMeta(const MRL& mrl)
+{
+ if (!m_currentEntry) return;
+ PlaylistItem* tmp = dynamic_cast<PlaylistItem*>(m_currentEntry);
+ bool addTime = (tmp->length() == QString("00:00:00"));
+ if ((tmp) && (tmp->url() == mrl.url()))
+ {
+ tmp->setTitle(mrl.title());
+ tmp->setArtist(mrl.artist());
+ tmp->setAlbum(mrl.album());
+ tmp->setTrack(mrl.track());
+ tmp->setYear(mrl.year());
+ tmp->setGenre(mrl.genre());
+ tmp->setLength(mrl.length().toString("h:mm:ss"));
+ tmp->setCurrentSubtitle(mrl.currentSubtitle());
+ tmp->setSubtitles(mrl.subtitleFiles());
+ }
+ if (addTime)
+ {
+ if (tmp->length().contains(':'));
+ {
+ m_playTime += timeStringToMs(tmp->length());
+ if (tmp->isVisible())
+ m_playTimeVisible += timeStringToMs(tmp->length());
+
+ updateStatus();
+ }
+ }
+
+ roller->setTitle( mrl );
+ setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace() );
+}
+
+GalleryDialog::GalleryDialog( QWidget *parent, GoogleFetcher *goog )
+ : KDialogBase( parent, QString(i18n("Gallery")).latin1(), true, QString::null, Ok, NoDefault, true )
+{
+ google = goog;
+ hbox = new QHBox(this);
+ imageFrame = new QFrame( hbox );
+ imageFrame->setFixedSize(500,500);
+ setMainWidget(hbox);
+ connect( &next, SIGNAL(timeout()), this, SLOT(slotNext()) );
+ next.start(1000,true);
+}
+
+void GalleryDialog::slotNext()
+{
+ QPixmap pix;
+ bool end;
+
+ actionButton(Ok)->setEnabled(false);
+loop:
+ QImage img = google->galleryNext( end );
+ if ( end ) {
+ slotOk();
+ return;
+ }
+ if ( !img.isNull() ) {
+ if ( img.width()>img.height() )
+ imageFrame->setFixedSize(500, 500*img.height()/img.width());
+ else
+ imageFrame->setFixedSize(500*img.width()/img.height(), 500);
+ img = img.smoothScale(imageFrame->width(),imageFrame->height());
+ pix.convertFromImage( img );
+ imageFrame->setPaletteBackgroundPixmap( pix );
+ }
+ else
+ goto loop;
+
+ actionButton(Ok)->setEnabled(true);
+ next.start(5000,true);
+}
+
+void GalleryDialog::slotOk()
+{
+ if ( next.isActive() )
+ next.stop();
+ hide();
+}
+
+void PlayList::showGallery()
+{
+ if ( google )
+ return;
+ QString s = getCurrent().artist().stripWhiteSpace();
+ if ( s.isEmpty() )
+ return;
+ google = new GoogleFetcher( s, "", true );
+ GalleryDialog dlg( 0, google );
+ dlg.exec();
+ delete google;
+ google = NULL;
+}
+
+void PlayList::setCover( QString s1, QString s2, bool forceFetch )
+{
+ if ( s1.isEmpty() || s2.isEmpty() ) {
+ coverFrame->setCoverPixmap( "" );
+ return;
+ }
+ QString s = locateLocal("appdata", "");
+ QImage img;
+ QPixmap pix;
+ QString fname = s1+"_"+s2;
+ fname = fname.replace( QChar( '/' ), "_" );
+ fname = fname.upper();
+ fname = s+"covers/"+fname;
+ if ( !forceFetch && QFile( fname ).exists() )
+ coverFrame->setCoverPixmap( fname );
+ else {
+ if ( !forceFetch )
+ coverFrame->setCoverPixmap( "" );
+ if ( google )
+ return;
+ if ( m_cover || forceFetch ) {
+ google = new GoogleFetcher( s1, s2 );
+ pix = google->pixmap( forceFetch );
+ delete google;
+ google = NULL;
+ }
+ if ( !QDir( s+"covers" ).exists() )
+ QDir().mkdir( s+"covers" );
+ if ( !pix.isNull() ) {
+ img = pix.convertToImage();
+ img.save( fname, coverImageFormat.latin1() );
+ MRL mrl = getCurrent();
+ if ( s1==mrl.artist().stripWhiteSpace() && s2==mrl.album().stripWhiteSpace() )
+ coverFrame->setCoverPixmap( fname );
+ }
+ else if ( !forceFetch && m_cover ) {
+ QString path = locate("appdata", "nocover.png");
+ if ( !path )
+ path = locate("data", "kaffeine/nocover.png");
+ KIO::file_copy( KURL::fromPathOrURL( path ), KURL::fromPathOrURL( fname ), -1, true );
+ }
+ }
+}
+
+void PlayList::chooseCurrentCover()
+{
+ MRL mrl = getCurrent();
+ setCover( mrl.artist().stripWhiteSpace(), mrl.album().stripWhiteSpace(), true );
+}
+
+/************ sort playlist ******************/
+
+void PlayList::slotSort(int section)
+{
+ m_list->setSorting(section, m_sortAscending);
+ m_list->sort();
+ m_sortAscending = !m_sortAscending;
+}
+
+
+/*** remove items ***/
+
+void PlayList::slotRemoveSelected()
+{
+ QPtrList<QListViewItem> selected;
+
+ if (m_currentEntry)
+ if (m_currentEntry->isSelected())
+ {
+ m_currentEntry = NULL;
+ m_currentRandomListEntry = -1;
+ }
+
+ selected = m_list->selectedItems();
+ PlaylistItem* item = NULL;
+
+ for(uint i = 0; i<selected.count(); i++)
+ {
+ // kdDebug() << "Remove " << selected.at(i)->text(TITLE_COLUMN) << "\n";
+ item = dynamic_cast<PlaylistItem *>(selected.at(i));
+ if (item->length().contains(':'))
+ {
+ m_playTime -= timeStringToMs(item->length());
+ m_playTimeVisible -= timeStringToMs(item->length());
+ }
+
+ m_countVisible--;
+ delete selected.at(i);
+ }
+
+ if (m_random) createRandomList();
+ updateStatus();
+}
+
+void PlayList::updateStatus()
+{
+ QString status;
+ if (isQueueMode())
+ {
+ QTime total;
+ QValueList<MRL>::ConstIterator end(m_queue.end());
+ for (QValueList<MRL>::ConstIterator it = m_queue.begin(); it != end; ++it)
+ total = total.addSecs(QTime().secsTo((*it).length()));
+ status = i18n("Queue: %1 Entries, Playtime: %2").arg(m_queue.count()).arg(total.toString("h:mm:ss"));
+ }
+ else
+ {
+ //status = i18n("Entries: %1, Playtime: %2 (Total: %3, %4)").arg(QString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible)).arg(QString::number(m_list->childCount())).arg(msToTimeString(m_playTime));
+
+
+ status = i18n("Entries: %1, Playtime: %2").arg(QString::number(m_countVisible)).arg(msToTimeString(m_playTimeVisible));
+ }
+ emit statusBarMessage(status);
+}
+
+void PlayList::slotNewList()
+{
+ m_list->setSorting(-1);
+ saveCurrentPlaylist();
+ m_playlistSelector->insertItem(i18n("Playlist") + QString::number(m_nextPlaylistNumber), 0);
+ m_nextPlaylistNumber++;
+ m_playlistSelector->setCurrentItem(0);
+ m_currentPlaylist = 0;
+ clearList();
+}
+
+void PlayList::setPlaylist(const QString& name, bool clear)
+{
+ saveCurrentPlaylist();
+ if (clear)
+ clearList();
+ int index = 0;
+ if (m_playlistSelector->listBox()->findItem(name))
+ index = m_playlistSelector->listBox()->index(m_playlistSelector->listBox()->findItem(name));
+ else
+ m_playlistSelector->insertItem(name, 0);
+ m_playlistSelector->setCurrentItem(index);
+ m_currentPlaylist = index;
+}
+
+void PlayList::nextPlaylist()
+{
+ int nextPlaylist = m_playlistSelector->currentItem();
+ QString pl = NULL;
+ do
+ {
+ nextPlaylist++;
+ if (nextPlaylist == m_playlistSelector->count())
+ nextPlaylist = 0;
+ pl = m_playlistSelector->text(nextPlaylist);
+ }
+ while (nextPlaylist != m_playlistSelector->currentItem());
+
+ saveCurrentPlaylist();
+ clearList();
+ m_playlistSelector->setCurrentItem(nextPlaylist);
+ m_currentPlaylist = nextPlaylist;
+ add(m_playlistDirectory + pl + ".kaffeine", NULL);
+ if (mainWidget->parentWidget())
+ mainWidget->parentWidget()->setFocus();
+}
+
+void PlayList::slotPlaylistActivated(int index)
+{
+ kdDebug() << "PlayList: Switch to playlist: " << m_playlistSelector->text(index) << endl;
+ QString pl = m_playlistSelector->text(index);
+
+ saveCurrentPlaylist();
+ clearList();
+ m_currentPlaylist = index;
+ add(m_playlistDirectory + pl + ".kaffeine", NULL);
+ if (mainWidget->parentWidget())
+ mainWidget->parentWidget()->setFocus();
+ /* if (!isQueueMode())
+ {
+ getCurrent();
+ emit signalPlay(m_currentEntryMRL);
+ } */
+}
+
+void PlayList::slotNewPlaylistName(const QString& text)
+{
+ if ((text.isEmpty()) || (text == m_playlistSelector->text(m_currentPlaylist)))
+ return;
+ if (m_playlistSelector->listBox()->findItem(text))
+ {
+ kdDebug() << "PlayList: Name still exists!" << endl;
+ return;
+ }
+ QString oldPl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine";
+ kdDebug() << "Playlist: removing file: " << oldPl << endl;
+ if (!KIO::NetAccess::del(oldPl, mainWidget))
+ kdError() << "Playlist: " << KIO::NetAccess::lastErrorString() << endl;
+
+ kdDebug() << "PlayList: Set playlist name to: " << text << endl;
+ m_playlistSelector->changeItem(text, m_currentPlaylist);
+ saveCurrentPlaylist();
+ if (mainWidget->parentWidget())
+ mainWidget->parentWidget()->setFocus();
+}
+
+QString PlayList::queryCurrentPlaylist()
+{
+ QString pl = m_playlistSelector->text(m_currentPlaylist);
+ return (m_playlistDirectory + pl + ".kaffeine");
+}
+
+void PlayList::saveCurrentPlaylist()
+{
+ QString pl = m_playlistSelector->text(m_currentPlaylist);
+ savePlaylist(m_playlistDirectory + pl + ".kaffeine");
+}
+
+void PlayList::removeCurrentPlaylist()
+{
+ int code = KMessageBox::warningContinueCancel(0, i18n("Remove '%1' from list and from disk?").arg(m_playlistSelector->text(m_currentPlaylist)),QString::null,KStdGuiItem::del());
+ if (code == KMessageBox::Continue)
+ {
+ QString pl = m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine";
+ if (!KIO::NetAccess::del(pl, mainWidget))
+ kdError() << "Playlist: " << KIO::NetAccess::lastErrorString() << endl;
+
+ m_playlistSelector->removeItem(m_currentPlaylist);
+ m_currentPlaylist = m_playlistSelector->currentItem();
+ clearList();
+ add(m_playlistDirectory + m_playlistSelector->text(m_currentPlaylist) + ".kaffeine", NULL);
+ }
+}
+
+void PlayList::loadPlaylist(const QString& pl)
+{
+ saveCurrentPlaylist();
+ QString plName = KURL(pl).fileName();
+ plName = plName.remove(".kaffeine", false);
+ if (m_playlistSelector->listBox()->findItem(plName))
+ {
+ QString plNewName = NULL;
+ while (true)
+ {
+ bool ok;
+ plNewName = QInputDialog::getText(i18n("Playlist Name Already Exists"),
+ i18n("Enter different playlist name:"), QLineEdit::Normal, plName, &ok);
+ if ((ok) && (!plNewName.isEmpty()))
+ {
+ if (m_playlistSelector->listBox()->findItem(plNewName))
+ continue;
+ else
+ break;
+ }
+ else
+ {
+ kdDebug() << "Playlist: Import aborted, playlist not added" << endl;
+ return;
+ }
+ }
+ plName = plNewName;
+ }
+ m_playlistSelector->insertItem(plName, 0);
+ m_playlistSelector->setCurrentItem(0);
+ m_currentPlaylist = 0;
+ clearList();
+ add(pl, NULL);
+}
+
+/******************************************
+ * save xml playlist
+ ******************************************/
+
+void PlayList::savePlaylist(const QString& pl)
+{
+ QDomDocument doc("playlist");
+ doc.setContent(QString("<!DOCTYPE XMLPlaylist>"));
+ QDomElement root = doc.createElement("playlist");
+ root.setAttribute("client", "kaffeine");
+ doc.appendChild(root);
+
+ QDomElement entry;
+ PlaylistItem * tmp = NULL;
+
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+
+ entry = doc.createElement("entry");
+
+ entry.setAttribute("title", tmp->title());
+ entry.setAttribute("artist", tmp->artist());
+ entry.setAttribute("album", tmp->album());
+ entry.setAttribute("track", tmp->track());
+ entry.setAttribute("year", tmp->year());
+ entry.setAttribute("genre", tmp->genre());
+ entry.setAttribute("url", tmp->url());
+ entry.setAttribute("mime", tmp->mime());
+ entry.setAttribute("length", tmp->length());
+
+ if(!(tmp->subtitles().isEmpty()))
+ {
+ QString subList;
+ for(unsigned int i=0; i<tmp->subtitles().count(); i++)
+ subList += tmp->subtitles()[i] + "&";
+
+ entry.setAttribute("subs", subList);
+ }
+ entry.setAttribute("currentSub", QString::number(tmp->currentSubtitle()));
+ root.appendChild(entry);
+
+ ++it;
+ }
+
+ QFile file(pl);
+ if (!file.open(IO_WriteOnly)) return;
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ stream << doc.toString();
+
+ file.close();
+ m_list->setCleared(false);
+}
+
+/**********************/
+
+void PlayList::exportM3UPlaylist(const QString& pl)
+{
+ PlaylistItem * tmp = NULL;
+
+ QListViewItemIterator it(m_list);
+
+ int length = -1;
+ QString m3uList = "#EXTM3U\n";
+
+ while (it.current())
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+
+ length = timeStringToMs(tmp->length()) / 1000;
+ if ( length == 0 )
+ length = -1;
+
+ m3uList.append("#EXTINF:" + QString::number(length) + "," + tmp->title());
+ if (tmp->artist().isEmpty() )
+ m3uList.append("\n");
+ else
+ m3uList.append(" - " + tmp->artist() + "\n");
+ m3uList.append(tmp->url() + "\n");
+ ++it;
+ }
+
+ QFile file(pl);
+ if (!file.open(IO_WriteOnly)) return;
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ stream << m3uList;
+
+ file.close();
+}
+
+void PlayList::exportPLSPlaylist(const QString& pl)
+{
+ PlaylistItem * tmp = NULL;
+
+ QListViewItemIterator it(m_list);
+
+ int counter = 0;
+ int length = -1;
+
+ QString plsList = "[playlist]\n";
+
+ while (it.current())
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+ ++counter;
+
+ length = timeStringToMs(tmp->length()) / 1000;
+
+ if ( length == 0 ) {
+ length = -1;
+ }
+
+ plsList.append("File" + QString::number(counter) + "=" + tmp->url() + "\n");
+ plsList.append("Title" + QString::number(counter) + "=" + tmp->title());
+ if (tmp->artist().isEmpty() )
+ plsList.append("\n");
+ else
+ plsList.append(" - " + tmp->artist() + "\n");
+ plsList.append("Length" + QString::number(counter) + "=" + QString::number(length) + "\n");
+ ++it;
+
+ }
+
+ plsList.append("NumberOfEntries=" + QString::number(counter) + "\n");
+ plsList.append("Version=2");
+
+ QFile file(pl);
+ if (!file.open(IO_WriteOnly)) return;
+ QTextStream stream(&file);
+ stream.setEncoding(QTextStream::UnicodeUTF8);
+
+ stream << plsList;
+
+ file.close();
+}
+
+void PlayList::resetSearch()
+{
+ m_playlistFilter->clear();
+ slotFindText( "" );
+}
+
+void PlayList::slotFindText(const QString& text)
+{
+ if (text == i18n("Filter")) return;
+
+ QListViewItemIterator it(m_list);
+ m_playTimeVisible = 0;
+ m_countVisible = 0;
+ PlaylistItem* tmp = NULL;
+ while ( it.current() )
+ {
+ tmp = dynamic_cast<PlaylistItem *>(it.current());
+ if (text.isEmpty() || tmp->title().contains(text, false) || tmp->url().contains(text, false)
+ || tmp->artist().contains(text, false) || tmp->album().contains(text, false) )
+ {
+ tmp->setVisible(true);
+ if (tmp->length().contains(':'))
+ m_playTimeVisible += timeStringToMs(tmp->length());
+
+ m_countVisible++;
+ }
+ else
+ {
+ tmp->setVisible(false);
+ if (tmp == m_currentEntry)
+ {
+ tmp->setPixmap(TITLE_COLUMN, QPixmap());
+ m_currentEntry = NULL;
+ m_currentRandomListEntry = -1;
+ }
+ }
+ ++it;
+ }
+
+ if (text.isEmpty())
+ m_searchSelection = false;
+ else
+ m_searchSelection = true;
+
+ if (m_random) createRandomList();
+ updateStatus();
+}
+
+
+/***************** cut/copy/paste *************************/
+
+void PlayList::slotCut()
+{
+ slotCopy();
+ slotRemoveSelected();
+}
+
+void PlayList::slotPaste()
+{
+ QPtrList<QListViewItem> selected;
+ selected = m_list->selectedItems();
+ QListViewItem* lastSelected = NULL;
+ if (selected.count())
+ lastSelected = selected.at(selected.count() - 1);
+ else
+ lastSelected = m_list->lastItem();
+
+ QStrList list;
+
+ if (QUriDrag::decode(QApplication::clipboard()->data(), list))
+ {
+ QStringList urls;
+ for (QStrListIterator it(list); *it; ++it)
+ urls.append(QUriDrag::uriToUnicodeUri(*it));
+ add(urls, lastSelected);
+ return;
+ }
+ /** try to decode as text **/
+ QString text;
+ if (QTextDrag::decode(QApplication::clipboard()->data(), text))
+ {
+ add(text, lastSelected);
+ }
+}
+
+void PlayList::slotCopy()
+{
+ QPtrList<QListViewItem> selected;
+ selected = m_list->selectedItems();
+
+ QStrList urlList;
+
+ for (uint i=0; i<selected.count(); i++)
+ {
+ urlList.append(QUriDrag::unicodeUriToUri(dynamic_cast<PlaylistItem *>(selected.at(i))->url()));
+ }
+
+ QApplication::clipboard()->setData(new QUriDrag(urlList));
+}
+
+void PlayList::slotSelectAll()
+{
+ QListViewItemIterator it(m_list);
+ while (it.current())
+ {
+ if ((*it)->isVisible())
+ m_list->setSelected(*it, true);
+ ++it;
+ }
+}
+
+void PlayList::slotPlaylistFromSelected()
+{
+ QPtrList<QListViewItem> selected;
+ selected = m_list->selectedItems();
+
+ QValueList<MRL> mrlList;
+
+ for (uint i=0; i<selected.count(); i++)
+ {
+ mrlList.append(dynamic_cast<PlaylistItem *>(selected.at(i))->toMRL());
+ }
+
+ if (mrlList.count())
+ {
+ slotNewList();
+ add(mrlList, NULL);
+ }
+}
+
+void PlayList::slotAddToQueue(MRL mrl)
+{
+ m_queue.append(mrl);
+ updateStatus();
+}
+
+/**** helper ****/
+
+QString PlayList::msToTimeString(int msec)
+{
+ /*
+ QTime t;
+ t = t.addMSecs(msec);
+ return t.toString("h:mm:ss");
+ */
+ /* can be >24h */
+ int hours;
+ int min;
+ int sec;
+ int my_msec=msec;
+ QString tmp;
+ QString t;
+
+ msec = msec/1000; //sec
+ hours = msec/3600;
+ my_msec -= hours*3600*1000;
+ t = t.setNum(hours);
+ t.append(":");
+
+ msec = msec - (hours*3600);
+ min = msec / 60;
+ my_msec -= min*60*1000;
+ tmp = tmp.setNum(min);
+ tmp = tmp.rightJustify(2, '0');
+ t.append(tmp);
+ t.append(":");
+
+ sec = msec - (min*60);
+ my_msec -= sec*1000;
+ if(my_msec > 500)
+ sec++;
+ tmp = tmp.setNum(sec);
+ tmp = tmp.rightJustify(2, '0');
+ t.append(tmp);
+
+ return t;
+}
+
+int PlayList::timeStringToMs(const QString& timeString)
+{
+ int sec = 0;
+ QStringList tokens = QStringList::split(':',timeString);
+
+ bool ok = false;
+ sec += tokens[0].toInt(&ok)*3600; //hours
+ if (!ok)
+ return 0;
+ sec += tokens[1].toInt(&ok)*60; //minutes
+ if (!ok)
+ return 0;
+ sec += tokens[2].toInt(&ok); //secs
+
+ if (ok)
+ return sec*1000; //return millisecs
+ else
+ return 0;
+}
+
+bool PlayList::endsWith(QString s1, QString s2, bool caseSensitive )
+{
+ if ( s1.isNull() || s2.isNull() )
+ return false;
+ int startPos = s1.length() - s2.length();
+
+ for (unsigned int i = 0; i < s2.length(); i++ )
+ {
+ if(caseSensitive)
+ {
+ if ( s1[startPos + i] != s2[i] )
+ return false;
+ }
+ else
+ {
+ if ( s1[startPos + i].lower() != s2[i].lower() )
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PlayList::startsWith(QString s1, QString s2, bool caseSensitive )
+{
+ if ( s1.isNull() || s2.isNull() )
+ return false;
+
+ if(s2.length() > s1.length())
+ return false;
+
+ for (unsigned int i = 0; i < s2.length(); i++ )
+ {
+ if(caseSensitive)
+ {
+ if ( s1[i] != s2[i] )
+ return false;
+ }
+ else
+ {
+ if ( s1[i].lower() != s2[i].lower() )
+ return false;
+ }
+ }
+
+ return true;
+}
+
+SubtitleChooser::SubtitleChooser(QStringList values, QString filename,QWidget *parent, const char * name) :
+ KDialogBase(parent,name,true,i18n("Select Subtitle"), Ok|Cancel, Ok, true)
+{
+ QVBox *page = makeVBoxMainWidget();
+ QLabel *label = new QLabel(page);
+ label->setText("<qt>" + i18n("Media file:") + " <b>" + filename + "</b></qt>");
+ table = new QListBox(page);
+ this->setMinimumSize(300,200);
+
+ table->setFocus();
+ table->insertStringList(values);
+ table->setSelected(0, true);
+}
+
+SubtitleChooser::~SubtitleChooser(){}
+
+QString SubtitleChooser::getSelection()
+{
+ return table->selectedItem()->text();
+}
+
+MovieChooser::MovieChooser(QStringList values, QString filename,QWidget *parent, const char * name) :
+ KDialogBase(parent,name,true,i18n("Select Movie"), Ok|Cancel, Ok, true)
+{
+ QVBox *page = makeVBoxMainWidget();
+ QLabel *label = new QLabel(page);
+ label->setText("<qt> " + i18n("Subtitle file:") + " <b>" + filename + "</b></qt>");
+ table = new QListBox(page);
+ this->setMinimumSize(450,200);
+
+ table->setFocus();
+ table->insertStringList(values);
+ table->setSelected(0, true);
+}
+
+MovieChooser::~MovieChooser(){}
+
+QString MovieChooser::getSelection()
+{
+ return table->selectedItem()->text();
+}
diff --git a/kaffeine/src/input/audiobrowser/playlist.h b/kaffeine/src/input/audiobrowser/playlist.h
new file mode 100644
index 0000000..41df120
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlist.h
@@ -0,0 +1,336 @@
+/*
+ * playlist.h
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
+ * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef PLAYLIST_H
+#define PLAYLIST_H
+
+#include <kdialogbase.h>
+#include <kdiroperator.h>
+#include <kfileiconview.h>
+#include <kaction.h>
+#include <kstdaction.h>
+
+#include <qwidget.h>
+#include <qptrlist.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+#include <qpainter.h>
+#include <qtoolbutton.h>
+
+#include "urllistview.h"
+#include "kaffeineinput.h"
+
+class UrlListView;
+class MRL;
+class KURL;
+class QListViewItem;
+class QString;
+class QLabel;
+class QColor;
+class QDropEvent;
+class QPixmap;
+class KLineEdit;
+class KComboBox;
+class KURLComboBox;
+class KConfig;
+class KPushButton;
+class GoogleFetcher;
+
+
+
+class GalleryDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ GalleryDialog( QWidget *parent, GoogleFetcher *goog );
+protected slots:
+ void slotOk();
+ void slotNext();
+private:
+ QFrame *imageFrame;
+ GoogleFetcher *google;
+ QTimer next;
+ QHBox *hbox;
+};
+
+
+
+class RollTitle : public QLabel
+{
+ Q_OBJECT
+
+public:
+ RollTitle( QWidget *parent );
+ void setTitle( MRL mrl );
+
+private:
+ void setTitle( QString t );
+ QTimer titleTimer;
+ QPixmap titlePix;
+ QColor back, fore;
+ int titleOffset;
+ QString title;
+
+protected:
+ void paintEvent ( QPaintEvent * );
+
+private slots:
+ void rollTitle();
+};
+
+
+
+class CoverFrame : public QFrame
+{
+ Q_OBJECT
+
+public:
+ CoverFrame( QWidget *parent );
+ ~CoverFrame();
+ void setCoverPixmap( const QString &path );
+
+protected:
+ void mousePressEvent( QMouseEvent *e );
+
+private:
+ void popup( const QPixmap &pix ) const;
+ QString imagePath;
+ QPixmap noCoverPix;
+
+signals:
+ void changeCurrentCover();
+ void gallery();
+};
+
+
+
+class PlayList : public KaffeineInput
+{
+ Q_OBJECT
+
+public:
+ PlayList(QWidget *parent, QObject *objParent, const char *name=0);
+ ~PlayList();
+
+ // Reimplemented from KaffeineInput
+public:
+ QWidget *wantPlayerWindow();
+ QWidget *inputMainWidget();
+ void mergeMeta(const MRL&);
+ bool nextTrack( MRL& );
+ bool previousTrack( MRL& );
+ bool currentTrack( MRL& );
+ bool trackNumber( int, MRL& );
+ bool playbackFinished( MRL& );
+ void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames );
+ void togglePanel();
+ bool execTarget( const QString& );
+ void saveConfig();
+ bool showPlayer() {return !m_showPlayer->isChecked();}
+ //***************************************
+
+public:
+ MRL getCurrent(); /* get current playlist entry */
+ MRL getNext();
+ MRL getEntryWithNumber(int number);
+ void setCurrentEntry(QListViewItem*, bool playIcon = true);
+
+ QListViewItem* getLast();
+ QListViewItem* getFirst();
+ QListViewItem* findByURL(const QString&);
+
+ /* insert a KURL(list) after a specific item */
+ void add(const QString& url, QListViewItem* after);
+ void add(const QStringList& urls, QListViewItem* after);
+ void add(const QValueList<MRL>&, QListViewItem* after);
+
+ bool isQueueMode() { return m_queue.count(); }
+
+ void setPlaylist(const QString& name, bool clear = false);
+ void nextPlaylist();
+ void removeCurrentPlaylist();
+ void saveCurrentPlaylist();
+ QString queryCurrentPlaylist();
+ void loadConfig(KConfig*);
+ void saveConfig(KConfig*);
+ void clearList();
+
+ void setEndless(bool);
+ void setRandom(bool);
+
+ void useAlternateEncoding(bool);
+ void setAlternateEncoding(const QString&);
+
+ void setFileFilter(const QString& filter);
+ void savePlaylist(const QString&);
+ void loadPlaylist(const QString&);
+
+ void exportM3UPlaylist(const QString&);
+ void exportPLSPlaylist(const QString&);
+
+ const bool getReadMetaOnLoading() const { return m_metaOnLoading; }
+
+ QVBox *mainWidget;
+ QVBox *playerBox;
+
+public slots:
+ void slotToggleShuffle();
+
+protected:
+ void closeEvent(QCloseEvent*);
+
+private slots:
+ void slotNewList();
+ void slotSetReadMetaOnLoading(bool read) { m_metaOnLoading = read; }
+ void slotSetAlternateColor(const QColor&);
+ void slotPlayDirect(QListViewItem* item); /* doubleclick */
+ void slotDropEvent(QDropEvent*, QListViewItem*);
+ void slotPreDropEvent();
+ void slotCut();
+ void slotPaste();
+ void slotCopy();
+ void slotSelectAll();
+ void slotPlaylistFromSelected();
+ void slotAddToQueue(MRL);
+ void slotRemoveSelected();
+ void slotFindText(const QString&);
+ void slotSort(int);
+ void slotPlaylistActivated(int);
+ void slotNewPlaylistName(const QString&);
+ void slotRepeat();
+ void slotShuffle();
+ void slotAutoCover();
+ void slotShowPlayer();
+ void slotPlaylistLoad();
+ void slotPlaylistSaveAs();
+ void slotPlaylistRemove();
+ void setCover( QString s1, QString s2, bool forceFetch=false );
+ void chooseCurrentCover();
+ void showGallery();
+ void startPlaylist();
+ void fileSelected( const KFileItem* );
+ void setBrowserURL( const QString& );
+ void setBrowserURL( const KURL& );
+ void browserURLChanged( const KURL& );
+ void slotClearList();
+ void resetSearch();
+
+private:
+ QListViewItem* insertItem(QListViewItem* after, const MRL&);
+ void updateStatus();
+ void createRandomList();
+ void getMetaInfo(MRL& mrl, const QString& mimeName);
+ void setupActions();
+ /* helpers */
+ static QString msToTimeString(int);
+ static int timeStringToMs(const QString&);
+ static bool endsWith(QString, QString, bool);
+ static bool startsWith(QString, QString, bool);
+
+private:
+ QColor m_altCol;
+ KComboBox* m_playlistSelector;
+ QToolButton *searchBtn;
+ KLineEdit* m_playlistFilter;
+ int m_nextPlaylistNumber;
+ QString m_playlistDirectory;
+ int m_currentPlaylist;
+ KURLComboBox *browserComb;
+
+ QSplitter *hSplit, *vSplit;
+ QVBox *panel;
+ QWidget *playlist;
+ KDirOperator *fileBrowser;
+ KFileIconView *view;
+ CoverFrame *coverFrame;
+ GoogleFetcher *google;
+ QString coverImageFormat;
+ RollTitle *roller;
+
+ KToggleAction *m_repeat, *m_shuffle, *m_autoCover, *m_showPlayer;
+
+ QValueList<MRL> m_queue;
+
+ uint m_playTime;
+ uint m_playTimeVisible;
+ uint m_countVisible;
+
+ bool m_searchSelection;
+ bool m_metaOnLoading;
+ bool m_sortAscending;
+
+ UrlListView* m_list;
+ QListViewItem* m_currentEntry;
+ MRL m_currentEntryMRL;
+
+ QString m_fileFilter;
+ QString m_metaInfoString;
+ QString m_lastPlaylist;
+
+ QPtrList<QListViewItem> m_randomList;
+ int m_currentRandomListEntry;
+
+ QPixmap m_isCurrentEntry;
+ QPixmap m_cdPixmap;
+
+ bool m_endless;
+ bool m_random;
+ bool m_cover;
+
+ bool m_useAlternateEncoding;
+ QString m_alternateEncoding;
+
+signals:
+ void signalRequestForAudioCD(const QString&);
+ void signalRequestForDVD(const QString&);
+ void signalRequestForVCD(const QString&);
+};
+
+class QListBox;
+class QStringList;
+
+class SubtitleChooser : public KDialogBase
+{
+ Q_OBJECT
+public:
+ SubtitleChooser(QStringList, QString, QWidget *parent=0, const char *name = 0);
+ virtual ~SubtitleChooser();
+
+ QString getSelection();
+
+private:
+ QListBox *table;
+};
+
+class MovieChooser : public KDialogBase
+{
+ Q_OBJECT
+public:
+ MovieChooser(QStringList, QString, QWidget *parent=0, const char *name = 0);
+ virtual ~MovieChooser();
+
+ QString getSelection();
+
+private:
+ QListBox *table;
+};
+
+#endif /* PLAYLIST_H */
diff --git a/kaffeine/src/input/audiobrowser/playlistitem.cpp b/kaffeine/src/input/audiobrowser/playlistitem.cpp
new file mode 100644
index 0000000..3b5fc05
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlistitem.cpp
@@ -0,0 +1,268 @@
+/*
+ * playlistitem.cpp - a self-displayable item for kaffeine's playlist
+ *
+ * Copyright (C) 2004-2005 Giorgos Gousios
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qstringlist.h>
+
+#include <kdebug.h>
+
+#include "mrl.h"
+#include "playlistitem.h"
+
+PlaylistItem::PlaylistItem(KListView *list, KListViewItem *after, const QString& url, const QString& mime, const QString& title,
+ const QString& length, const QString& artist, const QString& album, const QString& year, const QString& genre,
+ const QString& track, const QStringList& subtitles, int currentSubtitle) :
+ KListViewItem(list, after, mime, title, artist, album, track, length),
+ m_url(url), m_year(year), m_genre(genre), m_subtitles(subtitles), m_currentSubtitle(currentSubtitle), isCurrent(false)
+{}
+
+PlaylistItem::PlaylistItem(KListView* list, KListViewItem* after, const MRL& mrl) :
+ KListViewItem(list, after, mrl.mime(), mrl.title(), mrl.artist(), mrl.album(),
+ mrl.track(), mrl.length().toString("h:mm:ss")), m_url(mrl.url()),
+ m_year(mrl.year()), m_genre(mrl.genre()),
+ m_subtitles(mrl.subtitleFiles()), m_currentSubtitle(mrl.currentSubtitle()), isCurrent(false)
+{}
+
+PlaylistItem::~PlaylistItem() {}
+
+MRL PlaylistItem::toMRL() const
+{
+ return MRL(url(), title(), stringToTime(length()), mime(), artist(), album(), track(), year(), genre(), QString::null, subtitles(), currentSubtitle());
+}
+
+const QString& PlaylistItem::url() const
+{
+ return m_url;
+}
+
+QString PlaylistItem::mime() const
+{
+ return this->text(MIME_COLUMN);
+}
+
+QString PlaylistItem::title() const
+{
+ return this->text(TITLE_COLUMN);
+}
+
+QString PlaylistItem::artist() const
+{
+ return this->text(ARTIST_COLUMN);
+}
+
+QString PlaylistItem::album() const
+{
+ return this->text(ALBUM_COLUMN);
+}
+
+QString PlaylistItem::track() const
+{
+ return this->text(TRACK_COLUMN);
+}
+
+QString PlaylistItem::year() const
+{
+ return m_year;
+}
+
+QString PlaylistItem::genre() const
+{
+ return m_genre;
+}
+
+QString PlaylistItem::length() const
+{
+ return this->text(LENGTH_COLUMN);
+}
+
+const QStringList& PlaylistItem::subtitles() const
+{
+ return m_subtitles;
+}
+
+int PlaylistItem::currentSubtitle() const
+{
+ return m_currentSubtitle;
+}
+
+void PlaylistItem::setUrl(const QString& url)
+{
+ m_url = url;
+}
+
+void PlaylistItem::setMime(const QString& mime)
+{
+ this->setText(MIME_COLUMN, mime);
+}
+
+void PlaylistItem::setTitle(const QString& title)
+{
+ this->setText(TITLE_COLUMN, title);
+}
+
+void PlaylistItem::setArtist(const QString& artist)
+{
+ this->setText(ARTIST_COLUMN, artist);
+}
+
+void PlaylistItem::setAlbum(const QString& album)
+{
+ this->setText(ALBUM_COLUMN, album);
+}
+
+void PlaylistItem::setTrack(const QString& track)
+{
+ this->setText(TRACK_COLUMN, track);
+}
+
+void PlaylistItem::setYear(const QString& year)
+{
+ m_year = year;
+}
+
+void PlaylistItem::setGenre(const QString& genre)
+{
+ m_genre = genre;
+}
+
+void PlaylistItem::setLength(const QString& length)
+{
+ this->setText(LENGTH_COLUMN, length);
+}
+
+void PlaylistItem::setSubtitles(const QStringList& subs)
+{
+ m_subtitles = subs;
+}
+
+void PlaylistItem::addSubtitle(const QString& sub)
+{
+ /* This will add subtitle & set it to the current one */
+ for (uint i=0; i < m_subtitles.count(); i++) {
+ if (m_subtitles[i] == sub) {
+ m_currentSubtitle = i;
+ return;
+ }
+ }
+ m_subtitles.append(sub);
+ m_currentSubtitle = m_subtitles.count()-1;
+}
+
+void PlaylistItem::setCurrentSubtitle(int sub)
+{
+ m_currentSubtitle = sub;
+}
+
+QTime PlaylistItem::stringToTime(const QString& timeString)
+{
+ int sec = 0;
+ bool ok = false;
+ QStringList tokens = QStringList::split(':',timeString);
+
+ sec += tokens[0].toInt(&ok)*3600; //hours
+ sec += tokens[1].toInt(&ok)*60; //minutes
+ sec += tokens[2].toInt(&ok); //secs
+
+ if (ok)
+ return QTime().addSecs(sec);
+ else
+ return QTime();
+}
+
+int PlaylistItem::compare(QListViewItem *i, int col, bool ascending ) const
+{
+ PlaylistItem* p = dynamic_cast<PlaylistItem*>(i);
+ if (!p)
+ return QListViewItem::compare(i, col, ascending);
+
+ //if both strings are empty, sort by filename
+ if (text(col).isEmpty() && i->text(col).isEmpty())
+ return -url().compare(p->url());
+
+ bool ok;
+ int track1, track2 = 0;
+ track1 = track().toInt(&ok);
+ if (ok)
+ track2 = p->track().toInt(&ok);
+
+ if (col == TRACK_COLUMN)
+ {
+ if (ok)
+ return (track2 - track1);
+ else
+ return QListViewItem::compare(i, col, ascending);
+ }
+ else
+ {
+ int result = QListViewItem::compare(i, col, ascending);
+
+ //if artists are equal, compare albums
+ if ((col == ARTIST_COLUMN) && (result == 0))
+ {
+ result = QListViewItem::compare(i, ALBUM_COLUMN, ascending);
+ if (!ascending)
+ result = -result;
+ }
+
+ //if strings are equal, sort by track number or filename
+ if (result == 0)
+ {
+ int diff;
+ if (ok)
+ diff = track1 - track2;
+ else
+ diff = url().compare(p->url());
+
+ if (ascending)
+ return diff;
+ else
+ return -diff;
+ }
+ else
+ return result;
+ }
+}
+
+void PlaylistItem::setPlaying(bool playing)
+{
+ isCurrent = playing;
+}
+
+void PlaylistItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align)
+{
+ if (isCurrent)
+ {
+ QColorGroup colorGroup = cg;
+
+ QColor base = colorGroup.base();
+ QColor selection = colorGroup.highlight();
+
+ int r = (base.red() + selection.red()) / 2;
+ int b = (base.blue() + selection.blue()) / 2;
+ int g = (base.green() + selection.green()) / 2;
+
+ QColor c(r, g, b);
+
+ colorGroup.setColor(QColorGroup::Base, c);
+ QListViewItem::paintCell(p, colorGroup, column, width, align);
+ }
+ else
+ return KListViewItem::paintCell(p, cg, column, width, align);
+}
diff --git a/kaffeine/src/input/audiobrowser/playlistitem.h b/kaffeine/src/input/audiobrowser/playlistitem.h
new file mode 100644
index 0000000..9b1b9f5
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/playlistitem.h
@@ -0,0 +1,93 @@
+/*
+ * playlistitem.h - a self-displayable item for kaffeine's playlist
+ *
+ * Copyright (C) 2004-2005 Giorgos Gousios
+ * Copyright (C) 2004-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef PLAYLISTITEM_H
+#define PLAYLISTITEM_H
+
+#include <klistview.h>
+
+#define MIME_COLUMN 0
+#define TITLE_COLUMN 1
+#define ARTIST_COLUMN 2
+#define ALBUM_COLUMN 3
+#define TRACK_COLUMN 4
+#define LENGTH_COLUMN 5
+
+class QTime;
+class QString;
+class QStringList;
+class MRL;
+
+class PlaylistItem : public KListViewItem
+{
+
+public:
+ PlaylistItem(KListView *list, KListViewItem *after, const QString& url, const QString& mime, const QString& title,
+ const QString& length = QString::null, const QString& artist = QString::null, const QString& album = QString::null,
+ const QString& track = QString::null, const QString& year = QString::null, const QString& genre = QString::null,
+ const QStringList& subtitles = QStringList(), int currentSubtitle = -1);
+ PlaylistItem(KListView* list, KListViewItem* after, const MRL&);
+ virtual ~PlaylistItem();
+
+ MRL toMRL() const;
+
+ const QString& url() const;
+ QString mime() const;
+ QString title() const;
+ QString artist() const;
+ QString album() const;
+ QString track() const;
+ QString year() const;
+ QString genre() const;
+ QString length() const;
+ const QStringList& subtitles() const;
+ int currentSubtitle() const;
+
+ void setUrl(const QString&);
+ void setMime(const QString&);
+ void setTitle(const QString&);
+ void setArtist(const QString&);
+ void setAlbum(const QString&);
+ void setTrack(const QString&);
+ void setYear(const QString&);
+ void setGenre(const QString&);
+ void setLength(const QString&);
+ void setSubtitles(const QStringList&);
+ void addSubtitle(const QString&);
+ void setCurrentSubtitle(int);
+
+ //reimplement to fix track order
+ int compare( QListViewItem *i, int col, bool ascending ) const;
+
+ void setPlaying(bool playing);
+ virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align);
+
+private:
+ static QTime stringToTime(const QString&);
+ QString m_url;
+ QString m_year;
+ QString m_genre;
+ QStringList m_subtitles;
+ int m_currentSubtitle;
+ bool isCurrent;
+};
+
+#endif /* PLAYLISTITEM_H */
diff --git a/kaffeine/src/input/audiobrowser/urllistview.cpp b/kaffeine/src/input/audiobrowser/urllistview.cpp
new file mode 100644
index 0000000..49cfc3c
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/urllistview.cpp
@@ -0,0 +1,347 @@
+/*
+ * urllistview.cpp
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <kglobalsettings.h>
+#include <kfiledialog.h>
+#include <kpopupmenu.h>
+
+#include <qfontmetrics.h>
+#include <qdragobject.h>
+
+#include "mrl.h"
+#include "playlistitem.h"
+#include "urllistview.h"
+#include "urllistview.moc"
+
+
+UrlListView::UrlListView(QWidget *parent, const char *name ) : KListView(parent,name),
+ m_listCleared(true), m_itemOfContextMenu(NULL)
+{
+ m_contextMenu = new KPopupMenu(this);
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("player_play", KIcon::Small), i18n("Play"), this, SLOT(slotPlayItem()));
+ m_contextMenu->insertItem(i18n("Play Next/Add to Queue"), this, SLOT(slotPlayNext()));
+ m_contextMenu->insertSeparator();
+
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editcut", KIcon::Small), i18n("C&ut"), this, SIGNAL(signalCut()), CTRL+Key_X);
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editcopy", KIcon::Small), i18n("&Copy"), this, SIGNAL(signalCopy()), CTRL+Key_C);
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("editpaste", KIcon::Small), i18n("&Paste"), this, SIGNAL(signalPaste()), CTRL+Key_V);
+ m_contextMenu->insertItem(i18n("Select &All"), this, SIGNAL(signalSelectAll()), CTRL+Key_A);
+ m_contextMenu->insertItem(i18n("Create Playlist From Selected"), this, SIGNAL(signalPlaylistFromSelected()));
+ m_contextMenu->insertSeparator();
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("indent", KIcon::Small), i18n("Add Sub&title..."), this, SLOT(slotAddSubtitle()),QKeySequence(),100 );
+ m_contextMenu->insertSeparator();
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("edit", KIcon::Small), i18n("&Edit Title"), this, SLOT(slotEditTitle()));
+ m_contextMenu->insertItem(KGlobal::iconLoader()->loadIconSet("info", KIcon::Small), i18n("&Info"), this, SLOT(slotShowInfo()));
+
+/* width of the "length"-column */
+ QFontMetrics met(KGlobalSettings::generalFont());
+ int w1 = met.width(i18n("Length"));
+ int w2 = met.width("5:55:55") + 2;
+
+ m_column5Width = w1 > w2 ? w1 : w2;
+ m_column5Width += 30;
+
+/* width of the "track"-column */
+ w1 = met.width(i18n("Track"));
+ w2 = met.width("9999") + 2;
+
+ m_column4Track = w1 > w2 ? w1 : w2;
+ m_column4Track += 36;
+
+ connect(this, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)),
+ this, SLOT(slotShowContextMenu(QListViewItem*, const QPoint&, int)));
+ connect(this, SIGNAL(currentChanged(QListViewItem*)),
+ this, SLOT(slotCurrentChanged(QListViewItem*)));
+ connect(this, SIGNAL(clicked( QListViewItem*, const QPoint&, int )),
+ this, SLOT(slotClicked( QListViewItem*, const QPoint&, int )));
+}
+
+UrlListView::~UrlListView()
+{
+}
+
+bool UrlListView::acceptDrag(QDropEvent* event) const
+{
+ return QUriDrag::canDecode(event) || QTextDrag::canDecode(event) || KListView::acceptDrag(event);
+}
+
+QDragObject* UrlListView::dragObject()
+{
+ // get selected items
+ QPtrList<QListViewItem> selected;
+ QStrList urlList;
+
+ selected = selectedItems();
+ for (uint i = 0; i<selected.count(); i++)
+ {
+ urlList.append(dynamic_cast<PlaylistItem*>(selected.at(i))->url().ascii());
+ }
+
+ return new QUriDrag(urlList, viewport());
+}
+
+void UrlListView::resizeEvent(QResizeEvent* rev)
+{
+ int width = contentsRect().width() - m_column5Width - m_column4Track - 69;
+ setColumnWidth(0, 20); /* mime */
+ setColumnWidth(1, ((width * 5 / 12) + 50)); /* title */
+ setColumnWidth(2, (width * 3 / 12)); /* artist */
+ setColumnWidth(3, (width * 4 / 12)); /* album */
+ setColumnWidth(4, m_column4Track); /* track */
+ setColumnWidth(5, m_column5Width); /* width of "length" column */
+
+ KListView::resizeEvent(rev);
+}
+
+void UrlListView::clear()
+{
+ m_listCleared = true;
+ m_itemOfContextMenu = NULL;
+ setSorting(-1);
+ KListView::clear();
+}
+
+void UrlListView::setCleared(bool cl)
+{
+ m_listCleared = cl;
+}
+
+bool UrlListView::getCleared() const /* was playlist cleared ? */
+{
+ return m_listCleared;
+}
+
+/********** context menu **********/
+
+void UrlListView::slotShowContextMenu(QListViewItem* item, const QPoint& pos, int)
+{
+ if (!item)
+ {
+ m_itemOfContextMenu = NULL;
+ disableSubEntry();
+ }
+ else
+ {
+ m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item);
+ if (m_itemOfContextMenu->mime().contains("video"))
+ enableSubEntry();
+ else
+ disableSubEntry();
+ }
+
+ m_contextMenu->popup(pos);
+}
+
+void UrlListView::slotPlayItem()
+{
+ if (m_itemOfContextMenu)
+ emit signalPlayItem(m_itemOfContextMenu);
+}
+
+void UrlListView::slotPlayNext()
+{
+ if (m_itemOfContextMenu)
+ emit signalAddToQueue(m_itemOfContextMenu->toMRL());
+}
+
+void UrlListView::slotEditTitle()
+{
+ if (m_itemOfContextMenu)
+ {
+ m_itemOfContextMenu->setRenameEnabled(1, true);
+ m_itemOfContextMenu->startRename(1);
+ m_itemOfContextMenu->setRenameEnabled(1, false);
+ }
+}
+
+//Pretty print item info
+void UrlListView::slotShowInfo()
+{
+ if (!m_itemOfContextMenu)
+ return;
+
+ QString num;
+ num = num.setNum(childCount());
+ QString info = "<qt><table width=\"90%\">";
+ info = info + "<tr><td colspan=\"2\"><center><b>" + m_itemOfContextMenu->title() + "</b></center></td></tr>";
+ info = info + "<tr><td><b>" + i18n("URL")+ ":</b></td><td>" + m_itemOfContextMenu->url() + "</td></tr>";
+ info = info + "<tr><td><b>" + i18n("Artist") + ":</b></td><td>" + m_itemOfContextMenu->artist() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Album") + ":</b></td><td>" + m_itemOfContextMenu->album() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Track") + ":</b></td><td>" + m_itemOfContextMenu->track() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Year") + ":</b></td><td>" + m_itemOfContextMenu->year() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Genre") + ":</b></td><td>" + m_itemOfContextMenu->genre() + "</td></td>";
+ info = info + "<tr><td><b>" + i18n("Length") + ":</b></td><td>" + m_itemOfContextMenu->length() + "</td></tr>";
+ if(!m_itemOfContextMenu->subtitles().isEmpty())
+ {
+ info = info + "<tr><td><b>" + i18n("Subtitles") + ":</b></td><td>";
+
+ for(uint i = 0; i < m_itemOfContextMenu->subtitles().count(); i++ )
+ {
+ info = info + ""+m_itemOfContextMenu->subtitles()[i];
+ if(m_itemOfContextMenu->currentSubtitle() == (int)i)
+ info = info + "<small> ("+i18n("in use")+")</small>";
+ info = info + "<br>";
+ }
+ info = info + "</ul></td></tr></table></qt>";
+ }
+
+ KMessageBox::information(this, info);
+}
+
+void UrlListView::slotClicked(QListViewItem*, const QPoint&, int)
+{
+ /*if ( (item) && (col == 3) )
+ {
+ m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item);
+ if (!m_itemOfContextMenu) return;
+ slotShowInfo();
+ } */
+}
+
+#include <qdom.h>
+#include <kio/job.h>
+
+void UrlListView::slotAddSubtitle()
+{
+ /*QDomDocument reqdoc;
+
+ QDomElement methodCall = reqdoc.createElement( "methodCall" );
+ QDomElement methodName = reqdoc.createElement( "methodName" );
+ QDomText methodNameValue = reqdoc.createTextNode( "LogIn" );
+ methodName.appendChild( methodNameValue );
+ methodCall.appendChild( methodName );
+ reqdoc.appendChild( methodCall );
+
+ QDomElement params = reqdoc.createElement( "params" );
+
+ QDomElement param1 = reqdoc.createElement( "param" );
+ QDomElement value1 = reqdoc.createElement( "value" );
+ QDomElement type1 = reqdoc.createElement( "string" );
+ QDomText param1Value = reqdoc.createTextNode( "" );
+ type1.appendChild( param1Value );
+ value1.appendChild( type1 );
+ param1.appendChild( value1 );
+ params.appendChild( param1 );
+
+ QDomElement param2 = reqdoc.createElement( "param" );
+ QDomElement value2 = reqdoc.createElement( "value" );
+ QDomElement type2 = reqdoc.createElement( "string" );
+ QDomText param2Value = reqdoc.createTextNode( "" );
+ type2.appendChild( param2Value );
+ value2.appendChild( type2 );
+ param2.appendChild( value2 );
+ params.appendChild( param2 );
+
+ QDomElement param3 = reqdoc.createElement( "param" );
+ QDomElement value3 = reqdoc.createElement( "value" );
+ QDomElement type3 = reqdoc.createElement( "string" );
+ QDomText param3Value = reqdoc.createTextNode( "en" );
+ type3.appendChild( param3Value );
+ value3.appendChild( type3 );
+ param3.appendChild( value3 );
+ params.appendChild( param3 );
+
+ methodCall.appendChild( params );
+
+ const QString xmlRequest = "<?xml version=\"1.0\"?>\n" + reqdoc.toString();
+
+ QByteArray postData;
+ QDataStream stream( postData, IO_WriteOnly );
+ stream.writeRawBytes( xmlRequest.utf8(), xmlRequest.utf8().length() );
+
+ openSubJobBuf = QByteArray();
+
+ openSubJob = KIO::http_post( "http://test.opensubtitles.org/xml-rpc", postData, false );
+ openSubJob->addMetaData( "content-type", "Content-Type: text/xml" );
+
+ connect( openSubJob, SIGNAL(result(KIO::Job*)), this, SLOT(openSubResult(KIO::Job*)) );
+ connect( openSubJob, SIGNAL(data(KIO::Job*,const QByteArray&) ), this, SLOT(openSubData(KIO::Job*,
+ const QByteArray&)) );
+
+ kdDebug() << "\n\n" << xmlRequest << "\n\n" << endl;*/
+
+
+ if (!m_itemOfContextMenu)
+ return;
+
+ QString openURL = m_itemOfContextMenu->url();
+ QString subtitleURL = KFileDialog::getOpenURL(openURL,
+ i18n("*.smi *.srt *.sub *.txt *.ssa *.asc|Subtitle Files\n*.*|All Files"),
+ 0, i18n("Select Subtitle File")).path();
+ if(!(subtitleURL.isEmpty()) && !(m_itemOfContextMenu->subtitles().contains(subtitleURL)) && QFile::exists(subtitleURL))
+ {
+ m_itemOfContextMenu->addSubtitle(subtitleURL);
+ emit signalPlayItem(m_itemOfContextMenu);
+ }
+
+}
+
+void UrlListView::openSubResult( KIO::Job* job )
+{
+ if ( openSubJob!=job )
+ return;
+ if ( job->error() ) {
+ kdDebug() << "OpenSubtiltes error : " << job->error() << endl;
+ return;
+ }
+
+ QDomDocument document;
+ if ( !document.setContent( openSubJobBuf ) ) {
+ kdDebug() << "Couldn't read similar artists response" << endl;
+ return;
+ }
+ kdDebug() << "\n\n" << document.toString() << "\n\n" << endl;
+ openSubJob = 0;
+}
+
+void UrlListView::openSubData( KIO::Job* job, const QByteArray& data )
+{
+ if ( openSubJob != job )
+ return;
+
+ unsigned int bufsize = openSubJobBuf.size();
+ openSubJobBuf.resize( bufsize + data.size() );
+ memcpy( openSubJobBuf.data()+bufsize, data.data(), data.size() );
+}
+
+
+void UrlListView::slotCurrentChanged(QListViewItem * item)
+{
+ if(item == 0) //All items deleted
+ m_itemOfContextMenu = NULL;
+ else
+ m_itemOfContextMenu = dynamic_cast<PlaylistItem *>(item);
+}
+
+void UrlListView::enableSubEntry()
+{
+ m_contextMenu->setItemEnabled(100, true);
+}
+
+void UrlListView::disableSubEntry()
+{
+ m_contextMenu->setItemEnabled(100, false);
+}
diff --git a/kaffeine/src/input/audiobrowser/urllistview.h b/kaffeine/src/input/audiobrowser/urllistview.h
new file mode 100644
index 0000000..964b743
--- /dev/null
+++ b/kaffeine/src/input/audiobrowser/urllistview.h
@@ -0,0 +1,92 @@
+/*
+ * urllistview.h
+ *
+ * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef URLLISTVIEW_H
+#define URLLISTVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <klistview.h>
+
+class KPopupMenu;
+class QWidget;
+class QDragObject;
+class PlaylistItem;
+class MRL;
+class KIO::Job;
+
+class UrlListView : public KListView
+{
+ Q_OBJECT
+public:
+ UrlListView(QWidget *parent=0, const char *name=0);
+ ~UrlListView();
+
+ void setCleared(bool);
+ bool getCleared() const; /* was the playlist cleared or should we save it? */
+
+public slots:
+ virtual void clear(); /* reimplement slot */
+
+signals:
+ void signalPlayItem(QListViewItem* ); /* play selected in context menu */
+ void signalCut();
+ void signalCopy();
+ void signalPaste();
+ void signalSelectAll();
+ void signalAddToQueue(MRL);
+ void signalPlaylistFromSelected();
+
+private slots:
+ void slotShowContextMenu(QListViewItem*, const QPoint&, int);
+ void slotCurrentChanged(QListViewItem *);
+ void slotAddSubtitle();
+ void slotShowInfo();
+ void slotEditTitle();
+ void slotPlayItem();
+ void slotClicked(QListViewItem*, const QPoint&, int);
+ void slotPlayNext();
+ void openSubResult( KIO::Job* );
+ void openSubData( KIO::Job*, const QByteArray& );
+
+protected:
+ virtual bool acceptDrag(QDropEvent* event) const;
+ virtual void resizeEvent(QResizeEvent*);
+ virtual QDragObject* dragObject();
+
+private:
+ void enableSubEntry();
+ void disableSubEntry();
+
+private:
+ bool m_listCleared;
+ int m_column5Width; /* width of the fifth column */
+ int m_column4Track; /* width of the fourth column */
+
+ PlaylistItem* m_itemOfContextMenu;
+ KPopupMenu* m_contextMenu;
+ KIO::Job *openSubJob;
+ QByteArray openSubJobBuf;
+
+};
+
+#endif /* URLLISTVIEW_H */
diff --git a/kaffeine/src/input/disc/Makefile.am b/kaffeine/src/input/disc/Makefile.am
new file mode 100644
index 0000000..b9827cc
--- /dev/null
+++ b/kaffeine/src/input/disc/Makefile.am
@@ -0,0 +1,36 @@
+METASOURCES = AUTO
+
+SUBDIRS = plugins .
+
+noinst_LTLIBRARIES = libkaffeinedisc.la
+
+noinst_HEADERS = cddb.h \
+ disc.h \
+ paranoia.h
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \
+ -I$(top_builddir)/kaffeine/src/input/ \
+ -I$(top_srcdir)/kaffeine/src/ \
+ -I$(top_srcdir)/kaffeine/src/player-parts/kaffeine-part \
+ -I$(top_srcdir)/kaffeine/src/input/disc/plugins \
+ $(all_includes)
+
+libkaffeinedisc_la_SOURCES = disc.cpp \
+ cddb.cpp \
+ paranoia.cpp \
+ paranoiasettings.ui
+
+libkaffeinedisc_la_LDFLAGS = $(KDE_RPATH) \
+ $(all_libraries) \
+ -L$(top_srcdir)/kaffeine/src/input \
+ -L$(top_srcdir)/kaffeine/src/input/disc/plugins
+
+libkaffeinedisc_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \
+ $(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la \
+ $(top_builddir)/kaffeine/src/input/disc/plugins/libkaffeineaudioencoder.la \
+ -lcdda_interface -lcdda_paranoia
+
+# this is where the XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kaffeine
+shellrc_DATA = kaffeinedisc.rc
+
diff --git a/kaffeine/src/input/disc/cddb.cpp b/kaffeine/src/input/disc/cddb.cpp
new file mode 100644
index 0000000..407fbbc
--- /dev/null
+++ b/kaffeine/src/input/disc/cddb.cpp
@@ -0,0 +1,572 @@
+/*
+ * cddb.cpp
+ *
+ * Copyright (C) 2000 Michael Matz <matz@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <qdir.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <qapplication.h>
+#include <qstring.h>
+#include <qcursor.h>
+#include <kdebug.h>
+#include <ksock.h>
+#include <kextsock.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+
+#include "cddb.h"
+#include "cddb.moc"
+
+CDDB::CDDB() : ks(0), port(80), remote(false), save_local(false)
+{
+ QString s = QDir::homeDirPath()+"/.cddb";
+ cddb_dirs +=s;
+}
+
+CDDB::~CDDB()
+{
+ deinit();
+}
+
+bool CDDB::set_server(const char *hostname, unsigned short int _port)
+{
+ if (ks)
+ {
+ if (h_name == hostname && port == _port)
+ return true;
+ deinit();
+ }
+ remote = (hostname != 0) && (*hostname != 0);
+ kdDebug(7101) << "CDDB: set_server, host=" << hostname << "port=" << _port << endl;
+ if (remote)
+ {
+ ks = new KExtendedSocket(hostname, _port);
+ if (ks->connect() < 0)
+ {
+ kdDebug(7101) << "CDDB: Can't connect!" << endl;
+ delete ks;
+ ks = 0;
+ return false;
+ }
+
+ h_name = hostname;
+ port = _port;
+ QCString r;
+ readLine(r); // the server greeting
+ writeLine("cddb hello kde-user blubb kio_audiocd 0.4");
+ readLine(r);
+ }
+ return true;
+}
+
+bool CDDB::deinit()
+{
+ if (ks)
+ {
+ writeLine("quit");
+ QCString r;
+ readLine(r);
+ ks->close();
+ }
+ h_name.resize(0);
+ port = 0;
+ remote = false;
+ ks = 0;
+ return true;
+}
+
+bool CDDB::readLine(QCString& ret)
+{
+ int read_length = 0;
+ char small_b[128];
+ //fd_set set;
+
+ ret.resize(0);
+ while (read_length < 40000)
+ {
+ // Look for a \n in buf
+ int ni = buf.find('\n');
+ if (ni >= 0)
+ {
+ // Nice, so return this substring (without the \n),
+ // and truncate buf accordingly
+ ret = buf.left(ni);
+ if (ret.length() && ret[ret.length()-1] == '\r')
+ ret.resize(ret.length());
+ buf.remove(0, ni+1);
+ kdDebug(7101) << "CDDB: got `" << ret << "'" << endl;
+ return true;
+ }
+
+ // Try to refill the buffer
+ ks->waitForMore(60 * 1000);
+ ssize_t l = ks->readBlock(small_b, sizeof(small_b)-1);
+ if (l <= 0)
+ {
+ // l==0 normally means fd got closed, but we really need a lineend
+ return false;
+ }
+ small_b[l] = 0;
+ read_length += l;
+ buf += small_b;
+ }
+ return false;
+}
+
+bool CDDB::writeLine(const QCString& line)
+{
+ const char *b = line.data();
+ int l = line.length();
+ kdDebug(7101) << "CDDB: send `" << line << "'" << endl;
+ while (l)
+ {
+ ssize_t wl = ks->writeBlock(b, l);
+ if (wl < 0 && errno != EINTR)
+ return false;
+ if (wl < 0)
+ wl = 0;
+ l -= wl;
+ b += wl;
+ }
+ l = line.length();
+ if (l && line.data()[l-1] != '\n')
+ {
+ char c = '\n';
+ ssize_t wl;
+ do {
+ wl = ks->writeBlock(&c, 1);
+ } while (wl <= 0 && errno == EINTR);
+ if (wl<=0 && errno != EINTR)
+ return false;
+ }
+ return true;
+}
+
+unsigned int CDDB::get_discid(QValueList<int>& track_ofs)
+{
+ unsigned int id = 0;
+ int num_tracks = track_ofs.count() - 2;
+
+ // the last two track_ofs[] are disc begin and disc end
+
+ for (int i = num_tracks - 1; i >= 0; i--)
+ {
+ int n = track_ofs[i];
+ n /= 75;
+ while (n > 0)
+ {
+ id += n % 10;
+ n /= 10;
+ }
+ }
+ unsigned int l = track_ofs[num_tracks + 1];
+ l -= track_ofs[num_tracks];
+ l /= 75;
+ id = ((id % 255) << 24) | (l << 8) | num_tracks;
+ return id;
+}
+
+static int get_code (const QCString &s)
+{
+ bool ok;
+ int code = s.left(3).toInt(&ok);
+ if (!ok)
+ code = -1;
+ return code;
+}
+
+static void parse_query_resp (const QCString& _r, QCString& catg, QCString& d_id, QCString& title)
+{
+ QCString r = _r.stripWhiteSpace();
+ int i = r.find(' ');
+ if (i)
+ {
+ catg = r.left(i).stripWhiteSpace();
+ r.remove(0, i+1);
+ r = r.stripWhiteSpace();
+ }
+ i = r.find(' ');
+ if (i)
+ {
+ d_id = r.left(i).stripWhiteSpace();
+ r.remove(0, i+1);
+ r = r.stripWhiteSpace();
+ }
+ title = r;
+}
+
+QString CDDB::track(int i) const
+{
+ if (i < 0 || i >= int(m_names.count()))
+ return QString();
+ return m_names[i].utf8();
+}
+
+bool CDDB::parse_read_resp(QTextStream *stream, QTextStream *write_stream)
+{
+ /* Note, that m_names and m_title should be empty */
+ QCString end = ".";
+
+ /* Fill table, so we can index it below. */
+ for (int i = 0; i < m_tracks; i++)
+ {
+ m_names.append("");
+ }
+ while (1)
+ {
+ QCString r;
+ if (stream)
+ {
+ if (stream->atEnd())
+ break;
+ r = stream->readLine().latin1();
+ }
+ else
+ {
+ if (!readLine(r))
+ return false;
+ }
+ /* Normally the "." is not saved into the local files, but be
+ tolerant about this. */
+ if (r == end)
+ break;
+ if (write_stream)
+ *write_stream << r << endl;
+ r = r.stripWhiteSpace();
+ if (r.isEmpty() || r[0] == '#')
+ continue;
+ if (r.left(7) == "DTITLE=")
+ {
+ r.remove(0, 7);
+ m_title += QString::fromLocal8Bit(r.stripWhiteSpace());
+ }
+ else if (r.left(6) == "TTITLE")
+ {
+ r.remove(0, 6);
+ int e = r.find('=');
+ if (e)
+ {
+ bool ok;
+ int i = r.left(e).toInt(&ok);
+ if (ok && i >= 0 && i < m_tracks)
+ {
+ r.remove(0, e+1);
+ m_names[i] += QString::fromLocal8Bit(r);
+ }
+ }
+ }
+ }
+
+ /* XXX We should canonicalize the strings ("\n" --> '\n' e.g.) */
+
+ int si = m_title.find(" / ");
+ if (si > 0)
+ {
+ m_artist = m_title.left(si).stripWhiteSpace();
+ m_title.remove(0, si+3);
+ m_title = m_title.stripWhiteSpace();
+ }
+
+ if (m_title.isEmpty())
+ m_title = i18n("No Title");
+ /*else
+ m_title.replace(QRegExp("/"), "%2f");*/
+ if (m_artist.isEmpty())
+ m_artist = i18n("Unknown");
+ /*else
+ m_artist.replace(QRegExp("/"), "%2f");*/
+
+ kdDebug(7101) << "CDDB: found Title: `" << m_title << "'" << endl;
+ for (int i = 0; i < m_tracks; i++)
+ {
+ if (m_names[i].isEmpty())
+ m_names[i] += i18n("Track %1").arg(i);
+ m_names[i].replace(QRegExp("/"), "%2f");
+ kdDebug(7101) << "CDDB: found Track " << i+1 << ": `" << m_names[i]
+ << "'" << endl;
+ }
+ return true;
+}
+
+void CDDB::add_cddb_dirs(const QStringList& list)
+{
+ QString s = QDir::homeDirPath()+"/.cddb";
+
+ cddb_dirs = list;
+ if (cddb_dirs.isEmpty())
+ cddb_dirs += s;
+}
+
+/* Locates and opens the local file corresponding to that discid.
+ Returns TRUE, if file is found and ready for reading.
+ Returns FALSE, if file isn't found. In this case ret_file is initialized
+ with a QFile which resides in the first cddb_dir, and has a temp name
+ (the ID + getpid()). You can open it for writing. */
+bool CDDB::searchLocal(unsigned int id, QFile *ret_file)
+{
+ QDir dir;
+ QString filename;
+ filename = QString("%1").arg(id, 0, 16).rightJustify(8, '0');
+ QStringList::ConstIterator it;
+ for (it = cddb_dirs.begin(); it != cddb_dirs.end(); ++it)
+ {
+ dir.setPath(*it);
+ if (!dir.exists())
+ continue;
+ /* First look in dir directly. */
+ ret_file->setName (*it + "/" + filename);
+ if (ret_file->exists() && ret_file->open(IO_ReadOnly))
+ return true;
+ /* And then in the subdirs of dir (representing the categories normally).
+ */
+ const QFileInfoList *subdirs = dir.entryInfoList (QDir::Dirs);
+ QFileInfoListIterator fiit(*subdirs);
+ QFileInfo *fi;
+ while ((fi = fiit.current()) != 0)
+ {
+ ret_file->setName (*it + "/" + fi->fileName() + "/" + filename);
+ if (ret_file->exists() && ret_file->open(IO_ReadOnly))
+ return true;
+ ++fiit;
+ }
+ }
+ QString pid;
+ pid.setNum(::getpid());
+ ret_file->setName (cddb_dirs[0] + "/" + filename + "." + pid);
+ /* Try to create the save location. */
+ dir.setPath(cddb_dirs[0]);
+ if (save_local && !dir.exists())
+ {
+ //dir = QDir::current();
+ dir.mkdir(cddb_dirs[0]);
+ }
+ return false;
+}
+
+bool CDDB::queryCD(QValueList<int>& track_ofs)
+{
+ int num_tracks = track_ofs.count() - 2;
+ if (num_tracks < 1)
+ return false;
+ unsigned int id = get_discid(track_ofs);
+ QFile file;
+ bool local;
+
+ /* Already read this ID. */
+ if (id == m_discid)
+ return true;
+
+ emit cddbMessage(i18n("Searching local cddb entry ..."));
+ qApp->processEvents();
+
+ /* First look for a local file. */
+ local = searchLocal (id, &file);
+ /* If we have no local file, and no remote connection, barf. */
+ if (!local && (!remote || ks == 0))
+ return false;
+
+ m_tracks = num_tracks;
+ m_title = "";
+ m_artist = "";
+ m_names.clear();
+ m_discid = id;
+ if (local)
+ {
+ QTextStream stream(&file);
+ /* XXX Hmm, what encoding is used by CDDB files? local? Unicode?
+ Nothing? */
+ //stream.setEncoding(QTextStream::Locale);
+ parse_read_resp(&stream, 0);
+ file.close();
+ return true;
+ }
+
+ emit cddbMessage(i18n("Searching remote cddb entry ..."));
+ qApp->processEvents();
+
+ /* Remote CDDB query. */
+ unsigned int length = track_ofs[num_tracks+1] - track_ofs[num_tracks];
+ QCString q;
+ q.sprintf("cddb query %08x %d", id, num_tracks);
+ QCString num;
+ for (int i = 0; i < num_tracks; i++)
+ q += " " + num.setNum(track_ofs[i]);
+ q += " " + num.setNum(length / 75);
+ if (!writeLine(q))
+ return false;
+ QCString r;
+ if (!readLine(r))
+ return false;
+ r = r.stripWhiteSpace();
+ int code = get_code(r);
+ if (code == 200)
+ {
+ QCString catg, d_id, title;
+ QDir dir;
+ QCString s, pid;
+
+ emit cddbMessage(i18n("Found exact match cddb entry ..."));
+ qApp->processEvents();
+
+ /* an exact match */
+ r.remove(0, 3);
+ parse_query_resp(r, catg, d_id, title);
+ kdDebug(7101) << "CDDB: found exact CD: category=" << catg << " DiscId="
+ << d_id << " Title=`" << title << "'" << endl;
+ q = "cddb read " + catg + " " + d_id;
+ if (!writeLine(q))
+ return false;
+ if (!readLine(r))
+ return false;
+ r = r.stripWhiteSpace();
+ code = get_code(r);
+ if (code != 210)
+ return false;
+
+ pid.setNum(::getpid());
+ s = cddb_dirs[0].latin1();
+ //s = s + "/" +catg; // xine seems to not search in local subdirs
+ dir.setPath( s );
+ if ( !dir.exists() ) dir.mkdir( s );
+ s = s+"/"+ d_id;
+ file.setName( s );
+
+ if (save_local && file.open(IO_WriteOnly))
+ {
+ kdDebug(7101) << "CDDB: file name to save =" << file.name() << endl;
+ QTextStream stream(&file);
+ if (!parse_read_resp(0, &stream))
+ {
+ file.remove();
+ return false;
+ }
+ file.close();
+ /*QString newname (file.name());
+ newname.truncate(newname.findRev('.'));
+ if (QDir::current().rename(file.name(), newname)) {
+ kdDebug(7101) << "CDDB: rename failed" << endl;
+ file.remove();
+ } */
+ }
+ else if (!parse_read_resp(0, 0))
+ return false;
+ }
+ else if (code == 211)
+ {
+ // Found some close matches. We'll read the query response and ask the user
+ // which one should be fetched from the server.
+ QCString end = ".";
+ QCString catg, d_id, title;
+ QDir dir;
+ QCString s, pid, first_match;
+ QStringList disc_ids;
+
+ /* some close matches */
+ //XXX may be try to find marker based on r
+ emit cddbMessage(i18n("Found close cddb entry ..."));
+ qApp->processEvents();
+
+ int i=0;
+ while (1)
+ {
+ if (!readLine(r))
+ return false;
+ r = r.stripWhiteSpace();
+ if (r == end)
+ break;
+ disc_ids.append(r);
+ if (i == 0)
+ first_match = r;
+ i++;
+ }
+
+ bool ok = false;
+
+ // We don't want to be thinking too much, do we?
+ QApplication::restoreOverrideCursor();
+
+ // Oh, mylord, which match should I serve you?
+ QString _answer = KInputDialog::getItem(i18n("CDDB Matches"), i18n("Several close CDDB entries found. Choose one:"),
+ disc_ids, 0, false, &ok );
+ QCString answer = _answer.utf8();
+
+ if (ok){ // Get user selected match
+ parse_query_resp(answer, catg, d_id, title);
+ }
+ else{ // Get first match
+ parse_query_resp(first_match, catg, d_id, title);
+ }
+
+ // Now we can continue thinking...
+ QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
+
+ kdDebug(7101) << "CDDB: found close CD: category=" << catg << " DiscId="
+ << d_id << " Title=`" << title << "'" << endl;
+
+ // ... and forth we go as usual
+
+ q = "cddb read " + catg + " " + d_id;
+ if (!writeLine(q))
+ return false;
+ if (!readLine(r))
+ return false;
+ r = r.stripWhiteSpace();
+ code = get_code(r);
+ if (code != 210)
+ return false;
+
+ pid.setNum(::getpid());
+ s = cddb_dirs[0].latin1();
+ dir.setPath( s );
+ if ( !dir.exists() ) dir.mkdir( s );
+ s = s+"/"+ d_id;
+ file.setName( s );
+
+ if (save_local && file.open(IO_WriteOnly))
+ {
+ kdDebug(7101) << "CDDB: file name to save =" << file.name() << endl;
+ QTextStream stream(&file);
+ if (!parse_read_resp(0, &stream))
+ {
+ file.remove();
+ return false;
+ }
+ file.close();
+ }
+ else if (!parse_read_resp(0, 0))
+ return false;
+
+ }
+ else
+ {
+ /* 202 - no match found
+ 403 - Database entry corrupt
+ 409 - no handshake */
+ kdDebug(7101) << "CDDB: query returned code " << code << endl;
+ return false;
+ }
+
+ return true;
+}
diff --git a/kaffeine/src/input/disc/cddb.h b/kaffeine/src/input/disc/cddb.h
new file mode 100644
index 0000000..e75eb2d
--- /dev/null
+++ b/kaffeine/src/input/disc/cddb.h
@@ -0,0 +1,77 @@
+/*
+ * cddb.h
+ *
+ * Copyright (C) 2000 Michael Matz <matz@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CDDB_H
+#define CDDB_H
+
+#include <qcstring.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include <qobject.h>
+
+class QFile;
+class QTextStream;
+class KExtendedSocket;
+
+class CDDB : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ CDDB();
+ ~CDDB();
+ bool set_server(const char *hostname = 0, unsigned short int port = 0);
+ void add_cddb_dirs(const QStringList& list);
+ void save_cddb (bool save) { save_local = save; }
+ unsigned int get_discid(QValueList<int>& track_ofs);
+ bool queryCD(QValueList<int>& track_ofs);
+ QString title() const { return m_title.utf8(); }
+ QString artist() const { return m_artist.utf8(); }
+ int trackCount() const { return m_tracks; }
+ QString track(int i) const;
+
+private:
+
+ bool readLine(QCString& s);
+ bool writeLine(const QCString& s);
+ bool deinit();
+ bool parse_read_resp(QTextStream*, QTextStream*);
+ bool searchLocal(unsigned int id, QFile *ret_file);
+ KExtendedSocket *ks;
+ QCString h_name;
+ unsigned short int port;
+ bool remote;
+ bool save_local;
+ QStringList cddb_dirs;
+ QCString buf;
+ unsigned int m_discid;
+
+ int m_tracks;
+ QString m_title;
+ QString m_artist;
+ QStringList m_names;
+
+signals:
+
+ void cddbMessage( QString );
+};
+
+#endif /* CDDB_H */
diff --git a/kaffeine/src/input/disc/disc.cpp b/kaffeine/src/input/disc/disc.cpp
new file mode 100644
index 0000000..224a270
--- /dev/null
+++ b/kaffeine/src/input/disc/disc.cpp
@@ -0,0 +1,767 @@
+/*
+ * disc.cpp
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qstringlist.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qvaluelist.h>
+#include <qcursor.h>
+#include <qtimer.h>
+#include <qfile.h>
+#include <qpopupmenu.h>
+#include <qapplication.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kdebug.h>
+#include <kinputdialog.h>
+#include <dcopref.h>
+
+#include "cddb.h"
+#include "mrl.h"
+#include "disc.h"
+#include "disc.moc"
+
+MLabel::MLabel( QWidget *parent ) : QLabel( parent )
+{
+ setText("<center><font size=\"6\"><b>"+i18n("Audio CD")+"</b></font></center>");
+}
+
+void MLabel::paintEvent( QPaintEvent *pe )
+{
+ QLabel::paintEvent( pe );
+ QColorGroup cg = parentWidget()->colorGroup();
+ QColor base = cg.base();
+ QColor selection = cg.highlight();
+ int r = (base.red() + selection.red()) / 2;
+ int b = (base.blue() + selection.blue()) / 2;
+ int g = (base.green() + selection.green()) / 2;
+ setPaletteBackgroundColor( QColor(r, g, b) );
+}
+
+MListView::MListView( QWidget *parent ) : KListView( parent )
+{
+}
+
+void MListView::resizeEvent( QResizeEvent *rev )
+{
+ int width = contentsRect().width();
+ setColumnWidth(0, 40); /* Track */
+ setColumnWidth(1, width-90); /* title */
+ setColumnWidth(2, 50); /* duration */
+
+ KListView::resizeEvent(rev);
+}
+
+Disc::Disc( QWidget* parent, QObject *objParent, const char *name ) : KaffeineInput(objParent , name)
+{
+ mainWidget = new QVBox( parent );
+ mainWidget->setSizePolicy( QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred) );
+ split = new QSplitter( mainWidget );
+ split->setOpaqueResize( true );
+ widg = new QWidget( split );
+ widg->setMinimumWidth( 200 );
+ widg->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ) );
+ QVBoxLayout *wb = new QVBoxLayout( widg, 0, 0 );
+ discLab = new MLabel( widg );
+ wb->addWidget( discLab );
+ playerBox = new QVBox( widg );
+ wb->addWidget( playerBox );
+ playerBox->setMinimumWidth( 200 );
+ playerBox->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ) );
+ panel = new QFrame( split );
+ split->moveToFirst( panel );
+ panel->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ) );
+ split->setResizeMode( panel, QSplitter::KeepSize );
+
+ QVBoxLayout *vb = new QVBoxLayout( panel, 3, 3 );
+ cdBtn = new QToolButton( panel );
+ cdBtn->setTextLabel( i18n("Play CD") );
+ cdBtn->setTextPosition( QToolButton::Under );
+ cdBtn->setUsesTextLabel( true );
+ cdBtn->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+ QToolTip::add( cdBtn, i18n("Play CD"));
+ ripBtn = new QToolButton( panel );
+ ripBtn->setTextLabel( i18n("Rip CD") );
+ ripBtn->setTextPosition( QToolButton::Under );
+ ripBtn->setUsesTextLabel( true );
+ ripBtn->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+ QToolTip::add( ripBtn, i18n("Rip CD"));
+
+ QHBoxLayout *h1 = new QHBoxLayout();
+ h1->addWidget( cdBtn );
+ h1->addWidget( ripBtn );
+ vb->addLayout( h1 );
+
+ cdBtn->setIconSet( KGlobal::iconLoader()->loadIconSet("cdaudio_unmount", KIcon::Toolbar) );
+ ripBtn->setIconSet( KGlobal::iconLoader()->loadIconSet("kilogram", KIcon::Toolbar) );
+
+ connect( cdBtn, SIGNAL(clicked()), this, SLOT(startCD()) );
+ connect( ripBtn, SIGNAL(clicked()), this, SLOT(startRIP()) );
+
+ h1 = new QHBoxLayout();
+ h1->addWidget( new QLabel( i18n("Artist:"), panel ) );
+ artistLab = new QLabel( "", panel );
+ artistLab->setLineWidth(1);
+ artistLab->setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ artistLab->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) );
+ h1->addWidget( artistLab );
+ vb->addLayout( h1 );
+ h1 = new QHBoxLayout();
+ h1->addWidget( new QLabel( i18n("Album:"), panel ) );
+ albumLab = new QLabel( "", panel );
+ albumLab->setLineWidth(1);
+ albumLab->setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ albumLab->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ) );
+ h1->addWidget( albumLab );
+ vb->addLayout( h1 );
+
+ list = new MListView( panel );
+ list->setHScrollBarMode( QListView::AlwaysOff );
+ connect( list, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(trackSelected(QListViewItem*)) );
+ list->addColumn( i18n("Track") );
+ list->addColumn( i18n("Title") );
+ list->addColumn( i18n("Duration") );
+ //list->setSortColumn( -1 );
+ list->setAllColumnsShowFocus( true );
+ list->setSelectionMode(QListView::Extended);
+ list->setColumnWidthMode( 0, QListView::Manual );
+ list->setColumnWidthMode( 1, QListView::Manual );
+ list->setColumnWidthMode( 2, QListView::Manual );
+ list->setResizeMode( QListView::NoColumn );
+ vb->addWidget( list );
+
+ encodeWidget = new QWidget( panel );
+ QGridLayout *grid = new QGridLayout( encodeWidget, 2, 2, 0, 3 );
+ QLabel *lab = new QLabel( i18n("Select the tracks you want to rip and click the <b>Encode</b> button."), encodeWidget );
+ grid->addMultiCellWidget( lab, 0, 1, 0, 0);
+ enc = new QToolButton( encodeWidget );
+ grid->addMultiCellWidget( enc, 0, 0, 1, 1);
+ enc->setTextLabel( i18n("Encode...") );
+ enc->setTextPosition( QToolButton::Under );
+ enc->setUsesTextLabel( true );
+ enc->setIconSet( KGlobal::iconLoader()->loadIconSet("kilogram", KIcon::Small) );
+ enc->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ connect( enc, SIGNAL(clicked()), this, SLOT(encode()) );
+ vb->addWidget( encodeWidget );
+ encodeWidget->hide();
+
+ progressBar = new QProgressBar( 100, panel );
+ vb->addWidget( progressBar );
+ progressBar->hide();
+
+ vb->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Preferred ) );
+
+ artistLab->setPaletteBackgroundColor( list->paletteBackgroundColor() );
+ albumLab->setPaletteBackgroundColor( list->paletteBackgroundColor() );
+
+ connect( &encodeTimer, SIGNAL(timeout()), this, SLOT(encodeProgress()) );
+
+ setXMLFile("kaffeinedisc.rc");
+ setupActions();
+
+ loadConfig( KGlobal::config() );
+
+ para = NULL;
+ trackCurrent = 0;
+ currentPixmap = UserIcon("playing");
+}
+
+Disc::~Disc()
+{
+}
+
+void Disc::togglePanel()
+{
+ if ( panel->isHidden() )
+ panel->show();
+ else
+ panel->hide();
+}
+
+void Disc::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames )
+{
+ uiNames.append( i18n("Audio CD encoding") );
+ iconNames.append( "kilogram" );
+ targetNames.append( "DISC_RIP" );
+ uiNames.append( i18n("Play Audio CD") );
+ iconNames.append( "cdaudio_unmount" );
+ targetNames.append( "DISC_CDDA" );
+ uiNames.append( i18n("Play DVD") );
+ iconNames.append( "dvd_unmount" );
+ targetNames.append( "DISC_DVD" );
+ uiNames.append( i18n("Play VCD") );
+ iconNames.append( "cdrom_unmount" );
+ targetNames.append( "DISC_VCD" );
+}
+
+bool Disc::execTarget( const QString &target )
+{
+ if ( target=="DISC_CDDA" ) {
+ //emit showMe( this );
+ QTimer::singleShot( 100, this, SLOT(startCD()) );
+ return true;
+ }
+ else if ( target=="DISC_RIP" ) {
+ QTimer::singleShot( 100, this, SLOT(startRIP()) );
+ return true;
+ }
+ else if ( target=="DISC_DVD" ) {
+ QTimer::singleShot( 100, this, SLOT(startDVD()) );
+ return true;
+ }
+ else if ( target=="DISC_VCD" ) {
+ QTimer::singleShot( 100, this, SLOT(startVCD()) );
+ return true;
+ }
+ return false;
+}
+
+void Disc::loadConfig( KConfig* config )
+{
+ QValueList<int> sl;
+
+ config->setGroup("Disc");
+ sl = config->readIntListEntry("SplitSizes");
+ split->setSizes( sl );
+}
+
+void Disc::saveConfig()
+{
+ KConfig* config = KGlobal::config();
+
+ config->setGroup("Disc");
+ config->writeEntry( "SplitSizes", split->sizes() );
+}
+
+QWidget* Disc::wantPlayerWindow()
+{
+ return playerBox;
+}
+
+QWidget* Disc::inputMainWidget()
+{
+ return mainWidget;
+}
+
+void Disc::setupActions()
+{
+ new KAction(i18n("Open &DVD"), "dvd_unmount", 0, this, SLOT(startDVD()), actionCollection(), "file_open_dvd");
+ new KAction(i18n("Open &VCD"), "cdrom_unmount", 0, this, SLOT(startVCD()), actionCollection(), "file_open_vcd");
+ new KAction(i18n("Open &Audio-CD"), "cdaudio_unmount", 0, this, SLOT(startCD()), actionCollection(), "file_open_audiocd");
+}
+
+void Disc::playerStopped()
+{
+ trackCurrent = 0;
+ if ( !list->isEnabled() )
+ return;
+ list->clear();
+ artistLab->setText( "" );
+ albumLab->setText( "" );
+ encodeWidget->hide();
+}
+
+void Disc::setEncoding( bool b )
+{
+ list->setEnabled( !b );
+ artistLab->setEnabled( !b );
+ albumLab->setEnabled( !b );
+ cdBtn->setEnabled( !b );
+ ripBtn->setEnabled( !b );
+ enc->setEnabled( !b );
+ if ( b ) {
+ progressBar->setProgress( 0 );
+ progressBar->show();
+ }
+ else
+ progressBar->hide();
+}
+
+void Disc::encode()
+{
+ QListViewItem *it;
+ QStringList tracklist;
+
+ it = list->firstChild();
+ if ( !it )
+ return;
+ tracklist.append( artistLab->text() );
+ tracklist.append( albumLab->text() );
+ while ( it!=0 ) {
+ if ( it->isSelected() )
+ tracklist.append( it->text(0)+"-"+it->text(1) );
+ it = it->nextSibling();
+ }
+ if ( (int)tracklist.count()<3 ) {
+ KMessageBox::information( mainWidget, i18n("You must select the tracks to rip."), i18n("Warning") );
+ return;
+ }
+ setEncoding( true );
+ if ( trackCurrent )
+ emit stop();
+ para = new Paranoia();
+ if ( !para->init( currentDevice ) ) {
+ KMessageBox::information( mainWidget, i18n("Unable to initialize cdparanoia."), i18n("Warning") );
+ delete para;
+ para = NULL;
+ setEncoding( false );
+ return;
+ }
+
+ if ( para->encode( tracklist, mainWidget ) )
+ encodeTimer.start( 1000 );
+ else {
+ delete para;
+ para = NULL;
+ setEncoding( false );
+ }
+}
+
+void Disc::encodeProgress()
+{
+ if ( para->running() )
+ progressBar->setProgress( para->getProgress() );
+ else {
+ encodeTimer.stop();
+ delete para;
+ para = NULL;
+ setEncoding( false );
+ }
+
+}
+
+void Disc::setCurrent( int n )
+{
+ QListViewItem *it;
+
+ it = list->firstChild();
+ while ( it!=0 ) {
+ if ( it->text(0).toInt()==n )
+ it->setPixmap( 1, currentPixmap );
+ else
+ it->setPixmap( 1, QPixmap() );
+ it = it->nextSibling();
+ }
+}
+
+void Disc::trackSelected( QListViewItem *it )
+{
+ if ( !it )
+ return;
+
+ MRL mrl( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) );
+ mrl.setTitle( it->text(1) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( it->text(0) );
+ mrl.setMime( QString("audio/cdda") );
+ trackCurrent = it->text(0).toInt();
+ setCurrent( trackCurrent );
+ emit play( mrl, this );
+}
+
+void Disc::startRIP()
+{
+ startCD( "", true );
+}
+
+void Disc::startCD( const QString &device, bool rip )
+{
+ QStringList s;
+ bool init=false;
+ QValueList<int> qvl;
+ int i;
+ KListViewItem *it;
+ MRL mrl;
+ QStringList dcopList, devList;
+ bool ok=false;
+
+ if ( !cdBtn->isEnabled() ) {
+ emit showMe( this );
+ return;
+ }
+
+
+ if ( !device.isEmpty() )
+ s.append( device );
+ else {
+ DCOPRef mediamanager("kded","mediamanager");
+ DCOPReply reply = mediamanager.call("fullList()");
+ if ( reply.isValid() ) {
+ dcopList = reply;
+ i=0;
+ while ( i<(int)dcopList.count() ) {
+ //kdDebug() << dcopList[i+5] << " * " << dcopList[i+6] << " * " << dcopList[i+10] << endl;
+ if ( dcopList[i+10]=="media/audiocd" ) {
+ devList.append( dcopList[i+5] );
+ }
+ i+=13;
+ }
+ if ( devList.count()>1 ) {
+ QString choice = KInputDialog::getItem( i18n("Audio CD"), i18n("Several Audio CD found. Choose one:"),
+ devList, 0, false, &ok );
+ if ( ok )
+ s.append( choice );
+ else
+ return;
+ }
+ else if ( devList.count()==1 )
+ s.append( devList[0] );
+ else {
+ s.append( "/dev/cdrom" );
+ s.append( "/dev/dvd" );
+ }
+ }
+ else {
+ s.append( "/dev/cdrom" );
+ s.append( "/dev/dvd" );
+ }
+ }
+
+ QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
+ qApp->processEvents();
+
+ para = new Paranoia();
+ for ( i=0; i<(int)s.count(); i++ ) {
+ if ( (init = para->init( s[i] )) ) {
+ currentDevice = s[i];
+ break;
+ }
+ }
+ if ( init ) {
+ list->clear();
+ artistLab->setText( "" );
+ albumLab->setText( "" );
+ for ( i=0; i<para->getTracks(); i++)
+ qvl.append( para->trackFirstSector(i+1) + 150 );
+ qvl.append( para->discFirstSector() );
+ qvl.append( para->discLastSector() );
+ CDDB *cddb = new CDDB();
+ cddb->save_cddb( true );
+ if ( cddb->queryCD(qvl) ) {
+ artistLab->setText( cddb->artist() );
+ albumLab->setText( cddb->title() );
+ for ( i=0; i<para->getTracks(); i++ ) {
+ it = new KListViewItem( list, QString().sprintf("%02d", i+1), cddb->track( i ), para->trackTime(i) );
+ if ( i==0 ) {
+ mrl.setURL( QString("cdda://%1/1").arg( currentDevice ) );
+ mrl.setTitle( cddb->track(i) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( QString().sprintf("%02d", i+1) );
+ }
+ }
+ }
+ else {
+ cddb->set_server( "freedb.freedb.org", 8880 );
+ if ( cddb->queryCD(qvl) ) {
+ artistLab->setText( cddb->artist() );
+ albumLab->setText( cddb->title() );
+ for ( i=0; i<para->getTracks(); i++ ) {
+ it = new KListViewItem( list, QString().sprintf("%02d", i+1), cddb->track( i ), para->trackTime(i) );
+ if ( i==0 ) {
+ mrl.setURL( QString("cdda://%1/1").arg( currentDevice ) );
+ mrl.setTitle( cddb->track(i) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( QString().sprintf("%02d", i+1) );
+ }
+ }
+ }
+ else {
+ artistLab->setText( i18n("Unknown") );
+ albumLab->setText( i18n("Unknown") );
+ for ( i=0; i<para->getTracks(); i++ ) {
+ it = new KListViewItem( list, QString().sprintf("%02d", i+1), i18n("Track")+QString().sprintf("%02d", i+1), para->trackTime(i) );
+ if ( i==0 ) {
+ mrl.setURL( QString("cdda://%1/1").arg( currentDevice ) );
+ mrl.setTitle( i18n("Track")+QString().sprintf("%02d", i+1) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( QString().sprintf("%02d", i+1) );
+ }
+ }
+ }
+ }
+ delete cddb;
+ QApplication::restoreOverrideCursor();
+ encodeWidget->show();
+ emit showMe( this );
+ if ( !rip && !mrl.isEmpty() ) {
+ mrl.setMime( QString("audio/cdda") );
+ trackCurrent = mrl.track().toInt();
+ setCurrent( trackCurrent );
+ emit play( mrl, this );
+ }
+ }
+ else {
+ QApplication::restoreOverrideCursor();
+ KMessageBox::information( 0, i18n("No audio CD found."), i18n("Warning") );
+ }
+ delete para;
+ para = NULL;
+}
+
+void Disc::startDVD( const QString &device )
+{
+ MRL mrl;
+ QStringList dcopList, devList;
+ int i;
+ bool ok=false;
+
+ if ( !device.isEmpty() )
+ mrl.setURL( QString("dvd://%1").arg(device) );
+ else {
+ DCOPRef mediamanager("kded","mediamanager");
+ DCOPReply reply = mediamanager.call("fullList()");
+ if ( reply.isValid() ) {
+ dcopList = reply;
+ i=0;
+ while ( i<(int)dcopList.count() ) {
+ //kdDebug() << dcopList[i+5] << " * " << dcopList[i+6] << " * " << dcopList[i+10] << endl;
+ if ( dcopList[i+10]=="media/dvdvideo" ) {
+ devList.append( dcopList[i+5] );
+ }
+ else if ( dcopList[i+10]=="media/cdrom_mounted"
+ || dcopList[i+10]=="media/cdwriter_mounted"
+ || dcopList[i+10]=="media/dvd_mounted" ) {
+ if ( QFile::exists(dcopList[i+6]+"/video_ts") || QFile::exists(dcopList[i+6]+"/VIDEO_TS") )
+ devList.append( dcopList[i+5] );
+ }
+ i+=13;
+ }
+ if ( devList.count()>1 ) {
+ QString choice = KInputDialog::getItem( i18n("DVD Video"), i18n("Several DVD Video found. Choose one:"),
+ devList, 0, false, &ok );
+ if ( ok )
+ mrl.setURL( QString("dvd://%1").arg(choice) );
+ else
+ return;
+ }
+ else if ( devList.count()==1 )
+ mrl.setURL( QString("dvd://%1").arg(devList[0]) );
+ else {
+ //KMessageBox::information( 0, i18n("No DVD Video found."), i18n("Warning") );
+ //return;
+ mrl.setURL( QString("dvd://") );
+ }
+ }
+ else
+ mrl.setURL( QString("dvd://") );
+ }
+
+ mrl.setMime( QString("video/dvd") );
+
+ if ( !progressBar->isVisible() ) {
+ list->clear();
+ artistLab->setText( "" );
+ albumLab->setText( "" );
+ encodeWidget->hide();
+ }
+ trackCurrent = 0;
+ emit play( mrl, this );
+}
+
+void Disc::startVCD( const QString &device )
+{
+ MRL mrl;
+ QStringList dcopList, devList;
+ int i;
+ bool ok=false;
+
+ if ( !device.isEmpty() )
+ mrl.setURL( QString("vcd://%1").arg(device) );
+ else {
+ DCOPRef mediamanager("kded","mediamanager");
+ DCOPReply reply = mediamanager.call("fullList()");
+ if ( reply.isValid() ) {
+ dcopList = reply;
+ i=0;
+ while ( i<(int)dcopList.count() ) {
+ //kdDebug() << dcopList[i+5] << " * " << dcopList[i+6] << " * " << dcopList[i+10] << endl;
+ if ( dcopList[i+10]=="media/vcd" || dcopList[i+10]=="media/svcd" ) {
+ devList.append( dcopList[i+5] );
+ }
+ i+=13;
+ }
+ if ( devList.count()>1 ) {
+ QString choice = KInputDialog::getItem( i18n("VCD-SVCD"), i18n("Several (S)VCD found. Choose one:"),
+ devList, 0, false, &ok );
+ if ( ok )
+ mrl.setURL( QString("vcd://%1").arg(choice) );
+ else
+ return;
+ }
+ else if ( devList.count()==1 )
+ mrl.setURL( QString("vcd://%1").arg(devList[0]) );
+ else {
+ //KMessageBox::information( 0, i18n("No (S)VCD found."), i18n("Warning") );
+ //return;
+ mrl.setURL( QString("vcd://") );
+ }
+ }
+ else
+ mrl.setURL( QString("vcd://") );
+ }
+
+ mrl.setMime( QString("video/vcd") );
+
+ if ( !progressBar->isVisible() ) {
+ list->clear();
+ artistLab->setText( "" );
+ albumLab->setText( "" );
+ encodeWidget->hide();
+ }
+ trackCurrent = 0;
+ emit play( mrl, this );
+}
+
+bool Disc::currentTrack( MRL &mrl )
+{
+ QListViewItem *it;
+
+ if ( !trackCurrent )
+ return false;
+
+ it = list->firstChild();
+ if ( !it )
+ return false;
+ while ( it!=0 ) {
+ if ( it->text(0).toInt()==trackCurrent ) {
+ mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) );
+ mrl.setTitle( it->text(1) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( it->text(0) );
+ mrl.setMime( QString("audio/cdda") );
+ setCurrent( trackCurrent );
+ return true;
+ }
+ it = it->nextSibling();
+ }
+
+ return false;
+}
+
+bool Disc::playbackFinished( MRL &mrl )
+{
+ return nextTrack( mrl );
+}
+
+bool Disc::nextTrack( MRL &mrl )
+{
+ QListViewItem *it;
+
+ if ( !trackCurrent )
+ return false;
+
+ it = list->firstChild();
+ if ( !it )
+ return false;
+ while ( it!=0 ) {
+ if ( it->text(0).toInt()==trackCurrent+1 ) {
+ mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) );
+ mrl.setTitle( it->text(1) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( it->text(0) );
+ mrl.setMime( QString("audio/cdda") );
+ ++trackCurrent;
+ setCurrent( trackCurrent );
+ return true;
+ }
+ it = it->nextSibling();
+ }
+
+ it = list->firstChild();
+ mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) );
+ mrl.setTitle( it->text(1) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( it->text(0) );
+ mrl.setMime( QString("audio/cdda") );
+ trackCurrent = 1;
+ setCurrent( trackCurrent );
+ return true;
+}
+
+bool Disc::previousTrack( MRL &mrl )
+{
+ QListViewItem *it;
+
+ if ( !trackCurrent )
+ return false;
+
+ it = list->firstChild();
+ if ( !it )
+ return false;
+ while ( it!=0 ) {
+ if ( it->text(0).toInt()==trackCurrent-1 ) {
+ mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) );
+ mrl.setTitle( it->text(1) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( it->text(0) );
+ mrl.setMime( QString("audio/cdda") );
+ --trackCurrent;
+ setCurrent( trackCurrent );
+ return true;
+ }
+ it = it->nextSibling();
+ }
+
+ return false;
+}
+
+bool Disc::trackNumber( int number, MRL &mrl )
+{
+ QListViewItem *it;
+
+ if ( !trackCurrent )
+ return false;
+
+ it = list->firstChild();
+ if ( !it )
+ return false;
+ while ( it!=0 ) {
+ if ( it->text(0).toInt()==number ) {
+ mrl.setURL( QString("cdda://%1/%2").arg( currentDevice ).arg( it->text(0).toInt() ) );
+ mrl.setTitle( it->text(1) );
+ mrl.setArtist( artistLab->text() );
+ mrl.setAlbum( albumLab->text() );
+ mrl.setTrack( it->text(0) );
+ mrl.setMime( QString("audio/cdda") );
+ trackCurrent=number;
+ setCurrent( trackCurrent );
+ return true;
+ }
+ it = it->nextSibling();
+ }
+
+ return false;
+}
+
+void Disc::mergeMeta( const MRL& )
+{
+}
diff --git a/kaffeine/src/input/disc/disc.h b/kaffeine/src/input/disc/disc.h
new file mode 100644
index 0000000..c62c905
--- /dev/null
+++ b/kaffeine/src/input/disc/disc.h
@@ -0,0 +1,140 @@
+/*
+ * disc.h
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DISC_H
+#define DISC_H
+
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kconfig.h>
+#include <klistview.h>
+
+#include <qframe.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+#include <qtoolbutton.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <qprogressbar.h>
+#include <qguardedptr.h>
+
+#include "kaffeineinput.h"
+#include "paranoia.h"
+
+class MRL;
+
+class MLabel : public QLabel
+{
+ Q_OBJECT
+
+public:
+ MLabel( QWidget *parent );
+ ~MLabel() {}
+
+protected:
+ void paintEvent( QPaintEvent * );
+};
+
+
+
+class MListView : public KListView
+{
+ Q_OBJECT
+
+public:
+ MListView( QWidget *parent );
+ ~MListView() {}
+
+protected:
+ virtual void resizeEvent(QResizeEvent*);
+};
+
+
+
+class Disc : public KaffeineInput
+{
+ Q_OBJECT
+
+public:
+ Disc(QWidget *parent, QObject *objParent, const char *name=0);
+ ~Disc();
+
+ // Reimplemented from KaffeineInput
+public:
+ QWidget *wantPlayerWindow();
+ QWidget *inputMainWidget();
+ void mergeMeta(const MRL&);
+ bool nextTrack( MRL& );
+ bool previousTrack( MRL& );
+ bool currentTrack( MRL& );
+ bool trackNumber( int, MRL& );
+ bool playbackFinished( MRL& );
+ void toggleLayout( bool );
+ void playerStopped();
+ void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames );
+ void togglePanel();
+ bool execTarget( const QString& );
+ void saveConfig();
+ //***************************************
+
+public slots:
+ void startCD( const QString &device="", bool rip=false );
+ void startDVD( const QString &device="" );
+ void startVCD( const QString &device="" );
+ void startRIP();
+
+public:
+ QVBox *mainWidget;
+ QVBox *playerBox;
+
+private:
+ void loadConfig( KConfig* config );
+ void saveConfig( KConfig* config );
+ void setCurrent( int n );
+ void setupActions();
+
+ QLabel *artistLab, *albumLab;
+ QGuardedPtr<QWidget> widg;
+ QToolButton *ripBtn, *cdBtn;
+ QToolButton *enc;
+ QSplitter *split;
+ QGuardedPtr<QFrame> panel;
+ MLabel *discLab;
+ Paranoia *para;
+ MListView *list;
+ int trackCurrent;
+ QString currentDevice;
+ QPixmap currentPixmap;
+ QWidget *encodeWidget;
+ QTimer encodeTimer;
+ QProgressBar *progressBar;
+
+private slots:
+ void trackSelected( QListViewItem* );
+ void encode();
+ void encodeProgress();
+ void setEncoding( bool );
+
+signals:
+ void signalRequestForDVD();
+ void signalRequestForVCD();
+};
+
+#endif /* DISC_H */
diff --git a/kaffeine/src/input/disc/kaffeinedisc.rc b/kaffeine/src/input/disc/kaffeinedisc.rc
new file mode 100644
index 0000000..326daee
--- /dev/null
+++ b/kaffeine/src/input/disc/kaffeinedisc.rc
@@ -0,0 +1,24 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kaffeineplaylist" version="9">
+<MenuBar>
+ <Menu name="file">
+ <Separator/>
+ <Action name="file_open_dvd"/>
+ <Action name="file_open_vcd"/>
+ <Action name="file_open_audiocd"/>
+ <Separator/>
+ </Menu>
+</MenuBar>
+<ToolBar name="discToolBar" hidden="true"><text>CD Toolbar</text>
+ <Action name="file_open_dvd"/>
+ <Action name="file_open_vcd"/>
+ <Action name="file_open_audiocd"/>
+</ToolBar>
+<State name="no_media_part">
+<disable>
+ <Action name="file_open_dvd"/>
+ <Action name="file_open_vcd"/>
+ <Action name="file_open_audiocd"/>
+</disable>
+</State>
+</kpartgui>
diff --git a/kaffeine/src/input/disc/paranoia.cpp b/kaffeine/src/input/disc/paranoia.cpp
new file mode 100644
index 0000000..60e2092
--- /dev/null
+++ b/kaffeine/src/input/disc/paranoia.cpp
@@ -0,0 +1,553 @@
+/*
+ * paranoia.cpp
+ *
+ * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <math.h>
+
+#include <qfile.h>
+#include <qslider.h>
+#include <qlcdnumber.h>
+#include <qdir.h>
+#include <qlineedit.h>
+#include <qbuttongroup.h>
+#include <qtoolbutton.h>
+#include <qcheckbox.h>
+
+#include <qcombobox.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <ktrader.h>
+#include <kpushbutton.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kparts/componentfactory.h>
+
+#include "paranoia.h"
+#include "paranoia.moc"
+
+#define DEFAULT_DRIVE "/dev/cdrom"
+
+KiloConfig::KiloConfig( QWidget *parent, KConfig *confile, const QStringList &encoders ) : ParanoiaSettings( parent )
+{
+ int i;
+
+ KIconLoader *icon = new KIconLoader();
+ okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) );
+ cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) );
+ baseDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) );
+ delete icon;
+ connect( baseDirBtn, SIGNAL( clicked() ), this, SLOT( setBaseDir() ) );
+ Conf = confile;
+ Conf->setGroup( "Paranoia" );
+ baseDirLineEdit->setText( Conf->readEntry( "Basedir", QDir::homeDirPath() ) );
+ paranoiaGroup->setButton( Conf->readNumEntry( "Mode", 0 ) );
+ normCb->setChecked( Conf->readBoolEntry( "Normalize", false ) );
+ encoderComb->insertStringList( encoders );
+ QString s = Conf->readEntry( "CurrentEncoder", "" );
+ if ( !s.isEmpty() ) {
+ for ( i=0; i<(int)encoders.count(); i++ ) {
+ if ( encoders[i]==s ) {
+ encoderComb->setCurrentText( s );
+ }
+ }
+ }
+}
+
+void KiloConfig::setBaseDir()
+{
+ Conf->setGroup( "Paranoia" );
+ QString d = Conf->readEntry( "Basedir", QDir::homeDirPath() );
+ QString u = KFileDialog::getExistingDirectory( d );
+ if ( u!="" ) {
+ baseDirLineEdit->setText( u );
+ Conf->writeEntry( "Basedir", u );
+ }
+}
+
+QString KiloConfig::getEncoder()
+{
+ return encoderComb->currentText();
+}
+
+bool KiloConfig::getNormalize()
+{
+ return normCb->isChecked();
+}
+
+QString KiloConfig::getBaseDir()
+{
+ return baseDirLineEdit->text().stripWhiteSpace();
+}
+
+int KiloConfig::getParanoiaMode()
+{
+ return paranoiaGroup->selectedId();
+}
+
+void KiloConfig::accept()
+{
+ Conf->setGroup( "Paranoia" );
+ Conf->writeEntry( "Mode", paranoiaGroup->id( paranoiaGroup->selected() ) );
+ Conf->writeEntry( "CurrentEncoder", encoderComb->currentText() );
+ Conf->writeEntry( "Normalize", normCb->isChecked() );
+ done(Accepted);
+}
+
+KiloConfig::~KiloConfig()
+{
+}
+
+void paranoiaCallback( long, int )
+{
+}
+
+Paranoia::Paranoia()
+{
+ d = 0;
+ p = 0;
+ isRunning = false;
+}
+
+bool Paranoia::init( QString dev )
+{
+ QString s;
+ QFile f;
+
+ if ( p!=0 ) paranoia_free( p );
+ if (d!=0 ) cdda_close( d );
+ nTracks = 0;
+
+ dev = dev.stripWhiteSpace();
+ f.setName( dev );
+ if ( !f.exists() ) {
+ /*if ( !findCdrom() ) {
+ d = cdda_find_a_cdrom( CDDA_MESSAGE_PRINTIT, 0 );
+ if ( cdda_open( d )!=0 )
+ return false;
+ }*/
+ return false;
+ }
+ else {
+ d = cdda_identify( dev.ascii(), CDDA_MESSAGE_PRINTIT, 0 );
+ if ( cdda_open( d )!=0 )
+ return false;
+ }
+ p = paranoia_init( d );
+ nTracks = cdda_tracks( d );
+ return true;
+}
+
+bool Paranoia::findCdrom()
+{
+ QFile *f;
+ QString c;
+ QString s="";
+ int pos, i;
+ bool stop=false;
+ char dev[4][4]={"","","",""};
+
+ f = new QFile( "/proc/sys/dev/cdrom/info" );
+ if ( !f->open(IO_ReadOnly) )
+ return false;
+
+ QTextStream t( f );
+ while ( !t.eof() && !stop ) {
+ s = t.readLine();
+ if ( s.contains("drive name:") )
+ stop = true;
+ }
+ if ( !stop )
+ return false;
+
+ pos = s.find(":");
+ c = s.right( s.length()-pos-1 );
+ sscanf( c.latin1(), "%s %s %s %s", dev[0], dev[1], dev[2], dev[3] );
+
+ for ( i=0; i<4; i++ )
+ if ( procCdrom( dev[i] ) )
+ return true;
+
+ f->close();
+ return false;
+}
+
+bool Paranoia::procCdrom( QString name )
+{
+ int pos;
+
+ if ( name.contains("sr") ) {
+ pos = name.find("r");
+ name = name.right( name.length()-pos-1 );
+ name = "/dev/scd"+name;
+ d = cdda_identify( name.ascii(), CDDA_MESSAGE_PRINTIT, 0 );
+ if ( cdda_open( d )==0 )
+ return true;
+ }
+ else if ( name.contains("hd") ) {
+ name = "/dev/"+name;
+ d = cdda_identify( name.ascii(), CDDA_MESSAGE_PRINTIT, 0 );
+ if ( cdda_open( d )==0 )
+ return true;
+ }
+ return false;
+}
+
+void Paranoia::setMode( int mode )
+{
+ switch ( mode ) {
+ case 0 : mode = PARANOIA_MODE_DISABLE;
+ break;
+ case 1 : mode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
+ break;
+ case 2 : mode = PARANOIA_MODE_FULL;
+ }
+ paranoia_modeset( p, mode );
+}
+
+bool Paranoia::encode( const QStringList &list, QWidget *parent )
+{
+ QStringList desktop;
+ QStringList encoderName;
+
+ encodingList.clear();
+ encodingList = list;
+ myParent = parent;
+
+ // check for encoders
+ KTrader::OfferList offers = KTrader::self()->query("KaffeineAudioEncoder");
+ KTrader::OfferList::Iterator end(offers.end());
+ for(KTrader::OfferList::Iterator it = offers.begin(); it != end; ++it) {
+ KService::Ptr ptr = (*it);
+ desktop.append( ptr->desktopEntryName() );
+ encoderName.append( ptr->name() );
+ }
+
+ if ( !encoderName.count() ) {
+ KMessageBox::error( myParent, i18n("No audio encoders could be found."), i18n("Warning") );
+ return false;
+ }
+
+ KiloConfig dlg( myParent, KGlobal::config(), encoderName );
+ int ret = dlg.exec();
+ if ( ret!=QDialog::Accepted )
+ return false;
+ normalize = dlg.getNormalize();
+ baseDir = dlg.getBaseDir();
+ paraMode = dlg.getParanoiaMode();
+
+ QString s = dlg.getEncoder();
+ for ( ret=0; ret<(int)encoderName.count(); ++ret ) {
+ if ( encoderName[ret]==s ) {
+ encoderDesktop = desktop[ret];
+ break;
+ }
+ }
+
+ if ( !loadEncoder( myParent ) )
+ return false;
+
+ if ( !currentEncoder->options( myParent, KGlobal::config() ) ) {
+ unloadEncoder();
+ return false;
+ }
+
+ if ( !setPath( baseDir, QString(encodingList[0]).replace("/","_"), QString(encodingList[1]).replace("/","_") ) ) {
+ return false;
+ }
+ isRunning = true;
+ start();
+ return true;
+}
+
+bool Paranoia::loadEncoder( QWidget *parent )
+{
+ int error = 0;
+
+ KService::Ptr service = KService::serviceByDesktopName( encoderDesktop );
+ if (!service) {
+ KMessageBox::error( parent, i18n("Loading of encoder '%1' failed.").arg(encoderDesktop) );
+ return false;
+ }
+
+ if ( service->serviceTypes().contains("KaffeineAudioEncoder") ) {
+ currentEncoder = KParts::ComponentFactory::createPartInstanceFromService<KaffeineAudioEncoder>(service, 0, service->name().ascii(), 0, 0, 0, &error);
+ if (error > 0) {
+ KMessageBox::error( parent, i18n("Loading of encoder '%1' failed.").arg(encoderDesktop) );
+ return false;
+ }
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+void Paranoia::unloadEncoder()
+{
+ //kdDebug()<<"Unload encoder ..."<<endl;
+ KService::Ptr service = KService::serviceByDesktopName( encoderDesktop );
+ KLibLoader::self()->unloadLibrary( service->library().ascii() );
+ //kdDebug()<<"... encoder unloaded."<<endl;
+}
+
+bool Paranoia::validPath( QString path )
+{
+ QDir dir;
+
+ dir.setPath( path );
+ if ( !dir.exists() ) {
+ if ( !dir.mkdir( path ) ) {
+ KMessageBox::error( 0, i18n("Unable to create folder: ")+path );
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Paranoia::setPath( QString &path, const QString &artist, const QString &album )
+{
+ QString s;
+
+ if ( !path.endsWith("/") )
+ path = path+"/";
+ if ( !validPath( path ) )
+ return false;
+
+ s = artist;
+ if ( s!="" )
+ path = path+s+"/";
+ if ( !validPath( path ) )
+ return false;
+
+ s = album;
+ if ( s!="" )
+ path = path+s+"/";
+ if ( !validPath( path ) )
+ return false;
+ return true;
+}
+
+bool Paranoia::initTrack( int t )
+{
+ currentSector = cdda_track_firstsector( d, t );
+ endOfTrack = cdda_track_lastsector( d, t );
+ paranoia_seek( p, currentSector, SEEK_SET );
+ return true;
+}
+
+static inline signed short paraSwap16( signed short x ) {
+ return ((((unsigned short)x & 0x00ffU) << 8) |
+ (((unsigned short )x & 0xff00U) >> 8));
+}
+
+void Paranoia::run()
+{
+ signed short *buf;
+ int i, n, len, retlen;
+ long curpos, endpos;
+ QFile f, fn;
+ float max;
+ float factor;
+ QString s;
+ char *encoded;
+ int overallSectors=0;
+ int sectorCount=0;
+
+ progress = 0;
+ sleep(2); // give some time for the player to be stopped
+
+ setMode( paraMode );
+ for ( i=2; i<(int)encodingList.count(); ++i ) {
+ n = encodingList[i].left(2).toInt();
+ overallSectors+= trackSectorSize( n );
+ }
+
+ fn.setName( baseDir+".temp" );
+
+ for ( i=2; i<(int)encodingList.count(); ++i ) {
+ n = encodingList[i].left(2).toInt();
+ s = QString(encodingList[i]).replace("/","_")+currentEncoder->getExtension();
+ f.setName( baseDir+s );
+ initTrack( n );
+ max = 0;
+ curpos = currentSector;
+ endpos = endOfTrack;
+ if ( normalize ) {
+ len = CD_FRAMESIZE_RAW;
+ fn.open( IO_ReadWrite | IO_Truncate );
+ do {
+ buf = paranoia_read_limited( p, paranoiaCallback, 3 );
+ if ( Q_BYTE_ORDER == Q_BIG_ENDIAN ) {
+ for ( i=0; i<len/2; i++)
+ buf[i] = paraSwap16(buf[i]);
+ }
+ ++curpos;
+ if ( len>0 ) {
+ for ( n=0; n<len/2; ++n )
+ if ( fabs(buf[n])>max )
+ max = fabs(buf[n]);
+ fn.writeBlock( (char*)buf, len );
+ ++sectorCount;
+ progress = sectorCount*50/overallSectors;
+ }
+ if ( !isRunning )
+ len=0;
+ }
+ while ( curpos<endpos && len!=0 );
+
+ factor = 32767.0/max;
+ buf = new signed short[CD_FRAMESIZE_RAW];
+ fn.at( 0 );
+ f.open( IO_ReadWrite | IO_Truncate );
+ currentEncoder->start( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) );
+ encoded = currentEncoder->getHeader( len );
+ if ( encoded )
+ f.writeBlock( encoded, len );
+
+ do {
+ len = fn.readBlock( (char*)buf, CD_FRAMESIZE_RAW );
+ if ( len>0 ) {
+ if ( max<32760 )
+ for ( n=0; n<len/2; ++n )
+ buf[n] = (float)buf[n]*factor;
+ encoded = currentEncoder->encode( (char*)buf, len, retlen );
+ if ( encoded )
+ f.writeBlock( encoded, retlen );
+ ++sectorCount;
+ progress = sectorCount*50/overallSectors;
+ if ( !isRunning )
+ len=0;
+ }
+ }
+ while ( len>0 );
+ encoded = currentEncoder->stop( len );
+ if ( encoded )
+ f.writeBlock( encoded, len );
+ delete [] buf;
+ fn.remove();
+ }
+ else {
+ f.open( IO_ReadWrite | IO_Truncate );
+ currentEncoder->start( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) );
+ encoded = currentEncoder->getHeader( len );
+ if ( encoded )
+ f.writeBlock( encoded, len );
+ len = CD_FRAMESIZE_RAW;
+ do {
+ buf = paranoia_read_limited( p, paranoiaCallback, 3 );
+ if ( Q_BYTE_ORDER == Q_BIG_ENDIAN ) {
+ for ( i=0; i<len/2; i++) {
+ buf[i] = paraSwap16(buf[i]);
+ }
+ }
+ ++curpos;
+ if ( len>0 ) {
+ encoded = currentEncoder->encode( (char*)buf, len, retlen );
+ if ( encoded )
+ f.writeBlock( encoded, retlen );
+ ++sectorCount;
+ progress = sectorCount*100/overallSectors;
+ }
+ if ( !isRunning )
+ len=0;
+ }
+ while ( curpos<endpos && len!=0 );
+ encoded = currentEncoder->stop( len );
+ if ( encoded )
+ f.writeBlock( encoded, len );
+ sleep(1); // cdparanoia seems to like that.
+ }
+ f.flush();
+ f.close();
+ }
+
+ unloadEncoder();
+ isRunning = false;
+}
+
+int Paranoia::trackFirstSector( int t )
+{
+ return cdda_track_firstsector( d, t );
+}
+
+int Paranoia::discFirstSector()
+{
+ return cdda_disc_firstsector( d );
+}
+
+int Paranoia::discLastSector()
+{
+ return cdda_disc_lastsector( d );
+}
+
+bool Paranoia::isAudio( int t )
+{
+ if ( cdda_track_audiop( d, t+1 ) ) return true;
+ else return false;
+}
+
+QString Paranoia::trackSize( int t )
+{
+ QString s, c;
+ long total;
+
+ total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) );
+ if ( total>(1048576 ) ) s = c.setNum(total/1048576.0, 'f', 2)+" "+i18n("MB");
+ else if ( total>1024 ) s = c.setNum(total/1024.0, 'f', 2)+" "+i18n("KB");
+ else s = c.setNum(total*1.0, 'f', 2)+" "+i18n("Bytes");
+ return s;
+}
+
+long Paranoia::trackSectorSize( int t )
+{
+ return cdda_track_lastsector( d, t )-cdda_track_firstsector( d, t );
+}
+
+QString Paranoia::trackTime( int t )
+{
+ QString c;
+ long total, time;
+ int m, s;
+
+ if ( t<0 ) total = CD_FRAMESIZE_RAW * (cdda_disc_lastsector( d )-cdda_disc_firstsector( d ) );
+ else total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) );
+ time = (8 * total) / (44100 * 2 * 16);
+ m = time/60;
+ s = time%60;
+ c.sprintf( "%.2i:%.2i", m, s );
+ return c;
+}
+
+Paranoia::~Paranoia()
+{
+ if ( p!=0 ) paranoia_free( p );
+ if (d!=0 ) cdda_close( d );
+}
+
+long Paranoia::getTracks()
+{
+ return nTracks;
+}
diff --git a/kaffeine/src/input/disc/paranoia.h b/kaffeine/src/input/disc/paranoia.h
new file mode 100644
index 0000000..4864b06
--- /dev/null
+++ b/kaffeine/src/input/disc/paranoia.h
@@ -0,0 +1,108 @@
+/*
+ * paranoia.h
+ *
+ * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef PARANOIA_H
+#define PARANOIA_H
+
+#include <qstringlist.h>
+#include <qthread.h>
+#include <qwidget.h>
+
+#include <kconfig.h>
+
+#include "kaffeineaudioencoder.h"
+#include "paranoiasettings.h"
+
+extern "C"
+{
+#include <cdda_interface.h>
+#include <cdda_paranoia.h>
+}
+
+class KiloConfig : public ParanoiaSettings
+{
+ Q_OBJECT
+
+public:
+
+ KiloConfig( QWidget *parent, KConfig *confile, const QStringList &encoders );
+ ~KiloConfig();
+
+ QString getEncoder();
+ bool getNormalize();
+ QString getBaseDir();
+ int getParanoiaMode();
+
+public slots:
+
+ virtual void accept();
+ void setBaseDir();
+
+private:
+
+ KConfig *Conf;
+};
+
+class Paranoia : public QThread
+{
+public:
+ Paranoia();
+ bool init( QString dev );
+ ~Paranoia();
+ bool encode( const QStringList&, QWidget* );
+ long getTracks();
+ QString trackTime( int t );
+ int trackFirstSector( int t );
+ int discFirstSector();
+ int discLastSector();
+ virtual void run();
+ bool running() {return isRunning;}
+ int getProgress() {return progress;}
+
+private:
+
+ bool findCdrom();
+ bool procCdrom( QString name );
+ bool initTrack( int t );
+ void setMode( int mode );
+ bool isAudio( int t );
+ QString trackSize( int t );
+ long trackSectorSize( int t );
+ bool loadEncoder( QWidget* );
+ void unloadEncoder();
+ bool validPath( QString path );
+ bool setPath( QString &path, const QString &artist, const QString &album );
+
+ long nTracks;
+ cdrom_drive *d;
+ cdrom_paranoia *p;
+ long currentSector, endOfTrack;
+ bool isRunning;
+ QStringList encodingList;
+ QWidget *myParent;
+ KaffeineAudioEncoder *currentEncoder;
+ QString encoderDesktop;
+ bool normalize;
+ QString baseDir;
+ int paraMode;
+ int progress;
+};
+
+#endif /* PARANOIA_H */
diff --git a/kaffeine/src/input/disc/paranoiasettings.ui b/kaffeine/src/input/disc/paranoiasettings.ui
new file mode 100644
index 0000000..487899c
--- /dev/null
+++ b/kaffeine/src/input/disc/paranoiasettings.ui
@@ -0,0 +1,252 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ParanoiaSettings</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ParanoiaSettings</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>295</width>
+ <height>338</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Encoding Preferences</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>encoderGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Encoder:</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="0" column="0">
+ <property name="name">
+ <cstring>encoderComb</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>basedirGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Base directory:</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QToolButton" row="0" column="1">
+ <property name="name">
+ <cstring>baseDirBtn</cstring>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="0">
+ <property name="name">
+ <cstring>baseDirLineEdit</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>paranoiaGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Paranoia:</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>paranoiaRb0</cstring>
+ </property>
+ <property name="text">
+ <string>Disable all checking</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>paranoiaRb1</cstring>
+ </property>
+ <property name="text">
+ <string>Normal mode</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>paranoiaRb2</cstring>
+ </property>
+ <property name="text">
+ <string>Paranoia mode</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>normCb</cstring>
+ </property>
+ <property name="text">
+ <string>Normalize</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>60</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>152</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>ParanoiaSettings</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>ParanoiaSettings</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kaffeine/src/input/disc/plugins/Makefile.am b/kaffeine/src/input/disc/plugins/Makefile.am
new file mode 100644
index 0000000..ee42503
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/Makefile.am
@@ -0,0 +1,24 @@
+if with_lame
+ LAME_SUBDIR = mp3lame
+endif
+
+if with_oggvorbis
+ OGGVORBIS_SUBDIR = oggvorbis
+endif
+
+lib_LTLIBRARIES = libkaffeineaudioencoder.la
+
+METASOURCES = AUTO
+
+SUBDIRS = . $(LAME_SUBDIR) $(OGGVORBIS_SUBDIR)
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src $(all_includes)
+
+kaffeineincludedir = $(includedir)/kaffeine
+kaffeineinclude_HEADERS = kaffeineaudioencoder.h
+
+libkaffeineaudioencoder_la_SOURCES = kaffeineaudioencoder.cpp
+libkaffeineaudioencoder_la_LIBADD = $(LIB_KPARTS)
+libkaffeineaudioencoder_la_LDFLAGS = $(all_libraries) -version-info 0:1:0 -no-undefined
+
+kde_servicetypes_DATA = kaffeineaudioencoder.desktop
diff --git a/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.cpp b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.cpp
new file mode 100644
index 0000000..5198e43
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.cpp
@@ -0,0 +1,30 @@
+/*
+ * kaffeineaudioencoder.cpp
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "kaffeineaudioencoder.h"
+#include "kaffeineaudioencoder.moc"
+
+KaffeineAudioEncoder::KaffeineAudioEncoder(QObject* parent, const char* name) : KParts::Part( parent, name )
+{
+}
+
+KaffeineAudioEncoder::~KaffeineAudioEncoder()
+{
+}
diff --git a/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.desktop b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.desktop
new file mode 100644
index 0000000..821cabb
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=ServiceType
+X-KDE-ServiceType=KaffeineAudioEncoder
diff --git a/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.h b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.h
new file mode 100644
index 0000000..1dc3616
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/kaffeineaudioencoder.h
@@ -0,0 +1,53 @@
+/*
+ * kaffeineaudioencoder.h
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KAFFEINEAUDIOENCODER_H
+#define KAFFEINEAUDIOENCODER_H
+
+#include <kparts/part.h>
+#include <kconfig.h>
+
+#include <qstring.h>
+#include <qwidget.h>
+
+/*
+ * Base-Class for Kaffeine audio encoder plugins.
+ */
+
+class KDE_EXPORT KaffeineAudioEncoder : public KParts::Part
+{
+ Q_OBJECT
+public:
+ KaffeineAudioEncoder(QObject* parent, const char* name);
+ virtual ~KaffeineAudioEncoder();
+
+ // return false if the user's canceled.
+ virtual bool options( QWidget*, KConfig* ) {return false;}
+
+ // your file extension, e.g. ".ogg"
+ virtual QString getExtension() {return QString();}
+
+ virtual void start( QString/*title*/=0, QString/*artist*/=0, QString/*album*/=0, QString/*tracknumber*/=0, QString/*genre*/=0 ) {}
+ virtual char* getHeader( int&/*len*/ ) {return NULL;}
+ virtual char* encode( char*/*data*/, int /*datalen*/, int&/*len*/ ) {return NULL;}
+ virtual char* stop( int& /*len*/) {return NULL;}
+};
+
+#endif /* KAFFEINEAUDIOENCODER_H */
diff --git a/kaffeine/src/input/disc/plugins/mp3lame/Makefile.am b/kaffeine/src/input/disc/plugins/mp3lame/Makefile.am
new file mode 100644
index 0000000..6a58eb9
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/mp3lame/Makefile.am
@@ -0,0 +1,17 @@
+kde_module_LTLIBRARIES = libkaffeinemp3lame.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/ -I$(top_srcdir)/kaffeine/src/input/disc/plugins/ $(all_includes)
+
+METASOURCES = AUTO
+
+kaffeineincludedir = $(includedir)/kaffeine
+
+noinst_HEADERS = klameenc.h
+
+libkaffeinemp3lame_la_SOURCES = klameenc.cpp lameconfig.ui
+libkaffeinemp3lame_la_LIBADD = ../libkaffeineaudioencoder.la $(LIB_LAME)
+libkaffeinemp3lame_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -avoid-version -no-undefined
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kaffeinemp3lame.desktop
diff --git a/kaffeine/src/input/disc/plugins/mp3lame/kaffeinemp3lame.desktop b/kaffeine/src/input/disc/plugins/mp3lame/kaffeinemp3lame.desktop
new file mode 100644
index 0000000..df941d8
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/mp3lame/kaffeinemp3lame.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Lame mp3
+Name[af]=LAME MP3
+Name[hu]=LAME MP3
+Name[ka]=Lame-ის mp3
+Name[nb]=LAME MP3
+Name[pt]=MP3 do LAME
+Name[xx]=xxLame mp3xx
+ServiceTypes=KaffeineAudioEncoder
+Type=Service
+X-KDE-Library=libkaffeinemp3lame
diff --git a/kaffeine/src/input/disc/plugins/mp3lame/klameenc.cpp b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.cpp
new file mode 100644
index 0000000..ddfc5c2
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.cpp
@@ -0,0 +1,176 @@
+/*
+ * klameenc.cpp
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qcombobox.h>
+#include <qcheckbox.h>
+
+#include <kparts/genericfactory.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+
+#include "klameenc.h"
+#include "klameenc.moc"
+
+LameSettings::LameSettings( QWidget *parent, KConfig *confile ) : LameConfig( parent )
+{
+ KIconLoader *icon = new KIconLoader();
+ okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) );
+ cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) );
+ delete icon;
+ brateComb->insertItem( "32" );
+ brateComb->insertItem( "40" );
+ brateComb->insertItem( "48" );
+ brateComb->insertItem( "56" );
+ brateComb->insertItem( "64" );
+ brateComb->insertItem( "80" );
+ brateComb->insertItem( "96" );
+ brateComb->insertItem( "112" );
+ brateComb->insertItem( "128" );
+ brateComb->insertItem( "160" );
+ brateComb->insertItem( "192" );
+ brateComb->insertItem( "224" );
+ brateComb->insertItem( "256" );
+ brateComb->insertItem( "320" );
+ Conf = confile;
+ Conf->setGroup("LameMp3");
+ brateComb->setCurrentText( Conf->readEntry( "BitRate", "128" ) );
+ vbrCb->setChecked( Conf->readBoolEntry( "VBR", false ) );
+}
+
+LameSettings::~LameSettings()
+{
+}
+
+void LameSettings::accept()
+{
+ Conf->setGroup("LameMp3");
+ Conf->writeEntry( "BitRate", brateComb->currentText() );
+ Conf->writeEntry( "VBR", vbrCb->isChecked() );
+ done( Accepted );
+}
+
+int LameSettings::getBitrate()
+{
+ return brateComb->currentText().toInt();
+}
+
+bool LameSettings::isVBR()
+{
+ return vbrCb->isChecked();
+}
+
+K_EXPORT_COMPONENT_FACTORY (libkaffeinemp3lame, KParts::GenericFactory<KLameEnc>)
+
+KLameEnc::KLameEnc( QWidget*, const char*, QObject* parent, const char* name, const QStringList& )
+ : KaffeineAudioEncoder(parent,name)
+{
+ setInstance(KParts::GenericFactory<KLameEnc>::instance());
+}
+
+KAboutData *KLameEnc::createAboutData()
+{
+ KAboutData* aboutData = new KAboutData( "kaffeinemp3lame", I18N_NOOP("KaffeineMp3Lame"),
+ "0.1", I18N_NOOP("A Lame mp3 encoder plugin for Kaffeine."),
+ KAboutData::License_GPL,
+ "(c) 2006, Christophe Thommeret.", 0, "http://kaffeine.sourceforge.net");
+ aboutData->addAuthor("Christophe Thommeret.",0, "hftom@free.fr");
+
+ return aboutData;
+}
+
+QString KLameEnc::getExtension()
+{
+ return QString(".mp3");
+}
+
+bool KLameEnc::options( QWidget *parent, KConfig *conf )
+{
+ LameSettings dlg( parent, conf );
+ int ret = dlg.exec();
+ if ( ret!=QDialog::Accepted )
+ return false;
+ bitrate = dlg.getBitrate();
+ vbr = dlg.isVBR();
+ return true;
+}
+
+void KLameEnc::start( QString title, QString artist, QString album, QString tracknumber, QString genre )
+{
+ flags = lame_init();
+ lame_set_mode( flags, STEREO );
+ if ( vbr ) {
+ lame_set_VBR( flags, vbr_abr );
+ lame_set_VBR_mean_bitrate_kbps( flags, bitrate );
+ }
+ else {
+ lame_set_VBR( flags, vbr_off );
+ lame_set_brate( flags, bitrate );
+ }
+ lame_init_params( flags );
+
+ id3tag_init( flags );
+ id3tag_v2_only( flags );
+ if ( !title.isNull() )
+ id3tag_set_title( flags, title.latin1() );
+ if ( !artist.isNull() )
+ id3tag_set_artist( flags, artist.latin1() );
+ if ( !album.isNull() )
+ id3tag_set_album( flags, album.latin1() );
+ if ( !tracknumber.isNull() )
+ id3tag_set_track( flags, tracknumber.latin1() );
+ if ( !genre.isNull() )
+ id3tag_set_genre( flags, genre.latin1() );
+ id3tag_set_comment( flags, "Encoded by Kaffeine" );
+ lame_init_params( flags );
+}
+
+char* KLameEnc::getHeader( int &len )
+{
+ len = 0;
+ return NULL;
+}
+
+char* KLameEnc::encode( char *data, int datalen, int &len )
+{
+ len = lame_encode_buffer_interleaved( flags, (short int*)data, datalen/4, (unsigned char*)bufEncode, 8000 );
+
+ if ( len>0 )
+ return bufEncode;
+ else
+ return NULL;
+}
+
+char* KLameEnc::stop( int &len )
+{
+ len = lame_encode_flush( flags, (unsigned char*)bufEncode, 8000 );
+
+ lame_close( flags );
+ flags = 0;
+
+ if ( len>0 )
+ return bufEncode;
+ else
+ return NULL;
+}
+
+KLameEnc::~KLameEnc()
+{
+}
diff --git a/kaffeine/src/input/disc/plugins/mp3lame/klameenc.h b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.h
new file mode 100644
index 0000000..0550149
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/mp3lame/klameenc.h
@@ -0,0 +1,76 @@
+/*
+ * klameenc.h
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KLAMEENC_H
+#define KLAMEENC_H
+
+#include <lame/lame.h>
+
+#include <kconfig.h>
+
+#include "kaffeineaudioencoder.h"
+#include "lameconfig.h"
+
+class LameSettings : public LameConfig
+{
+ Q_OBJECT
+public:
+ LameSettings( QWidget *parent, KConfig *confile );
+ ~LameSettings();
+
+ int getBitrate();
+ bool isVBR();
+
+public slots:
+ virtual void accept();
+
+private:
+ KConfig *Conf;
+};
+
+class KLameEnc : public KaffeineAudioEncoder
+{
+ Q_OBJECT
+
+public:
+
+ KLameEnc( QWidget*, const char*, QObject*, const char*, const QStringList& );
+ ~KLameEnc();
+
+ // Reimplemented from KaffeineAudioEncoder
+ bool options( QWidget*, KConfig* );
+ QString getExtension();
+ void start( QString title=0, QString artist=0, QString album=0, QString tracknumber=0, QString genre=0 );
+ char* getHeader( int &len );
+ char* encode( char *data, int datalen, int &len );
+ char* stop( int &len );
+ //****************************
+
+ static KAboutData* createAboutData();
+
+private:
+
+ char bufEncode[8000];
+ lame_global_flags *flags;
+ int bitrate;
+ bool vbr;
+};
+
+#endif /* KLAMEENC_H */
diff --git a/kaffeine/src/input/disc/plugins/mp3lame/lameconfig.ui b/kaffeine/src/input/disc/plugins/mp3lame/lameconfig.ui
new file mode 100644
index 0000000..202040a
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/mp3lame/lameconfig.ui
@@ -0,0 +1,195 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>LameConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>LameConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>232</width>
+ <height>142</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Lame mp3 options</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>vbrCb</cstring>
+ </property>
+ <property name="text">
+ <string>VBR</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Bitrate:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>brateComb</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Kb/s</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>107</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>LameConfig</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>LameConfig</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am b/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am
new file mode 100644
index 0000000..7ac8f45
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/oggvorbis/Makefile.am
@@ -0,0 +1,17 @@
+kde_module_LTLIBRARIES = libkaffeineoggvorbis.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/ -I$(top_srcdir)/kaffeine/src/input/disc/plugins/ $(all_includes) $(CFLAGS_OGGVORBIS)
+
+METASOURCES = AUTO
+
+kaffeineincludedir = $(includedir)/kaffeine
+
+noinst_HEADERS = koggenc.h
+
+libkaffeineoggvorbis_la_SOURCES = koggenc.cpp oggconfig.ui
+libkaffeineoggvorbis_la_LIBADD = ../libkaffeineaudioencoder.la $(LIB_OGGVORBIS)
+libkaffeineoggvorbis_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -avoid-version -no-undefined
+
+# this is where the desktop file will go
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kaffeineoggvorbis.desktop
diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/kaffeineoggvorbis.desktop b/kaffeine/src/input/disc/plugins/oggvorbis/kaffeineoggvorbis.desktop
new file mode 100644
index 0000000..cf51bf8
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/oggvorbis/kaffeineoggvorbis.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Ogg Vorbis
+Name[nb]=OGG Vorbis
+Name[pa]=Ogg ਵੋਰਬਿਸ
+Name[xx]=xxOgg Vorbisxx
+ServiceTypes=KaffeineAudioEncoder
+Type=Service
+X-KDE-Library=libkaffeineoggvorbis
diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.cpp b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.cpp
new file mode 100644
index 0000000..f5352b8
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.cpp
@@ -0,0 +1,236 @@
+/*
+ * koggenc.cpp
+ *
+ * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qslider.h>
+
+#include <kparts/genericfactory.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+
+#include "koggenc.h"
+#include "koggenc.moc"
+
+OggSettings::OggSettings( QWidget *parent, KConfig *confile ) : OggConfig( parent )
+{
+ KIconLoader *icon = new KIconLoader();
+ okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) );
+ cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) );
+ delete icon;
+ Conf = confile;
+ Conf->setGroup("OggVorbis");
+ oggSlid->setValue( Conf->readNumEntry( "Quality", 4 ) );
+}
+
+OggSettings::~OggSettings()
+{
+}
+
+void OggSettings::accept()
+{
+ Conf->setGroup("OggVorbis");
+ Conf->writeEntry( "Quality", oggSlid->value() );
+ done( Accepted );
+}
+
+int OggSettings::getQuality()
+{
+ return oggSlid->value();
+}
+
+K_EXPORT_COMPONENT_FACTORY (libkaffeineoggvorbis, KParts::GenericFactory<KOggEnc>)
+
+KOggEnc::KOggEnc( QWidget*, const char*, QObject* parent, const char* name, const QStringList& )
+ : KaffeineAudioEncoder(parent,name)
+{
+ setInstance(KParts::GenericFactory<KOggEnc>::instance());
+ encodingQuality = 0.4;
+ bufEncode = new char[1];
+ tmpBuf = new char[1];
+}
+
+KAboutData *KOggEnc::createAboutData()
+{
+ KAboutData* aboutData = new KAboutData( "kaffeineoggvorbis", I18N_NOOP("KaffeineOggVorbis"),
+ "0.1", I18N_NOOP("A Ogg Vorbis encoder plugin for Kaffeine."),
+ KAboutData::License_GPL,
+ "(c) 2006, Christophe Thommeret.", 0, "http://kaffeine.sourceforge.net");
+ aboutData->addAuthor("Christophe Thommeret.",0, "hftom@free.fr");
+
+ return aboutData;
+}
+
+QString KOggEnc::getExtension()
+{
+ return QString(".ogg");
+}
+
+bool KOggEnc::options( QWidget *parent, KConfig *conf )
+{
+ OggSettings dlg( parent, conf );
+ int ret = dlg.exec();
+ if ( ret!=QDialog::Accepted )
+ return false;
+ encodingQuality = dlg.getQuality()/10.0;
+ return true;
+}
+
+void KOggEnc::start( QString title, QString artist, QString album, QString tracknumber, QString genre )
+{
+ char* tag;
+
+ vorbis_info_init( &vi );
+ vorbis_encode_init_vbr( &vi, 2, 44100, encodingQuality );
+ /* add a comment */
+ vorbis_comment_init( &vc );
+ vorbis_comment_add_tag( &vc, "description", "Encoded by Kaffeine" );
+ //vorbis_comment_add_tag( &vc, "vendor", "KOggEnc (Kilogram)" );
+ /* set up the analysis state and auxiliary encoding storage */
+ vorbis_analysis_init( &vd, &vi );
+ vorbis_block_init( &vd, &vb );
+ /* set up our packet->stream encoder */
+ /* pick a random serial number; that way we can more likely build
+ chained streams just by concatenation */
+ srand( time(NULL) );
+ ogg_stream_init( &os, rand() );
+ if ( !title.isNull() ) {
+ tag = qstrdup( title.utf8() );
+ vorbis_comment_add_tag( &vc, "title", tag );
+ delete [] tag;
+ }
+ if ( !artist.isNull() ) {
+ tag = qstrdup( artist.utf8() );
+ vorbis_comment_add_tag( &vc, "artist", tag );
+ delete [] tag;
+ }
+ if ( !album.isNull() ) {
+ tag = qstrdup( album.utf8() );
+ vorbis_comment_add_tag( &vc, "album", tag );
+ delete [] tag;
+ }
+ if ( !tracknumber.isNull() ) {
+ tag = qstrdup( tracknumber.utf8() );
+ vorbis_comment_add_tag( &vc, "tracknumber", tag );
+ delete [] tag;
+ }
+ if ( !genre.isNull() ) {
+ tag = qstrdup( genre.utf8() );
+ vorbis_comment_add_tag( &vc, "genre", tag );
+ delete [] tag;
+ }
+}
+
+char* KOggEnc::getHeader( int &len )
+{
+ int buflen=0;
+
+ vorbis_analysis_headerout( &vd, &vc, &header, &header_comm, &header_code );
+ ogg_stream_packetin( &os, &header ); /* automatically placed in its own page */
+ ogg_stream_packetin( &os, &header_comm );
+ ogg_stream_packetin( &os, &header_code );
+
+ while( ogg_stream_flush( &os, &og ) ){
+ delete [] bufEncode;
+ bufEncode = new char[ og.header_len+og.body_len+buflen ];
+ //memcpy( mempcpy( mempcpy( bufEncode, tmpBuf, buflen ), og.header, og.header_len ), og.body, og.body_len );
+ memcpy( (char*)memcpy( (char*)memcpy( bufEncode, tmpBuf, buflen )+buflen, og.header, og.header_len )+og.header_len, og.body, og.body_len );
+ buflen+= og.header_len;
+ buflen+= og.body_len;
+ delete [] tmpBuf;
+ tmpBuf = new char[ buflen ];
+ memcpy( tmpBuf, bufEncode, buflen );
+ }
+ len = buflen;
+ return bufEncode;
+}
+
+char* KOggEnc::encode( char *data, int datalen, int &len )
+{
+ int buflen=0;
+ int i;
+ float **buffer=vorbis_analysis_buffer( &vd, datalen/4 );
+
+ for( i=0; i<datalen/4; i++ ){
+ buffer[0][i] = ((data[i*4+1]<<8) | (0x00ff&(int)data[i*4]))/32768.f;
+ buffer[1][i] = ((data[i*4+3]<<8) | (0x00ff&(int)data[i*4+2]))/32768.f;
+ }
+ vorbis_analysis_wrote( &vd, i );
+
+ while( vorbis_analysis_blockout( &vd, &vb)==1 ) {
+ vorbis_analysis( &vb, NULL );
+ vorbis_bitrate_addblock( &vb );
+ while( vorbis_bitrate_flushpacket( &vd, &op ) ) {
+ ogg_stream_packetin( &os, &op );
+ while( ogg_stream_pageout( &os, &og ) ) {
+ delete [] bufEncode;
+ bufEncode = new char[ og.header_len+og.body_len+buflen ];
+ //memcpy( mempcpy( mempcpy( bufEncode, tmpBuf, buflen ), og.header, og.header_len ), og.body, og.body_len );
+ memcpy( (char*)memcpy( (char*)memcpy( bufEncode, tmpBuf, buflen )+buflen, og.header, og.header_len )+og.header_len, og.body, og.body_len );
+ buflen+= og.header_len;
+ buflen+= og.body_len;
+ delete [] tmpBuf;
+ tmpBuf = new char[ buflen ];
+ memcpy( tmpBuf, bufEncode, buflen );
+ }
+ }
+ }
+ len = buflen;
+ return bufEncode;
+}
+
+char* KOggEnc::stop( int &len )
+{
+ int buflen=0;
+
+ vorbis_analysis_wrote( &vd, 0 );
+ while( vorbis_analysis_blockout( &vd, &vb)==1 ) {
+ vorbis_analysis( &vb, NULL );
+ vorbis_bitrate_addblock( &vb );
+ while( vorbis_bitrate_flushpacket( &vd, &op ) ) {
+ ogg_stream_packetin( &os, &op );
+ while( ogg_stream_pageout( &os, &og ) ) {
+ delete [] bufEncode;
+ bufEncode = new char[ og.header_len+og.body_len+buflen ];
+ //memcpy( mempcpy( mempcpy( bufEncode, tmpBuf, buflen ), og.header, og.header_len ), og.body, og.body_len );
+ memcpy( (char*)memcpy( (char*)memcpy( bufEncode, tmpBuf, buflen )+buflen, og.header, og.header_len )+og.header_len, og.body, og.body_len );
+ buflen+= og.header_len;
+ buflen+= og.body_len;
+ delete [] tmpBuf;
+ tmpBuf = new char[ buflen ];
+ memcpy( tmpBuf, bufEncode, buflen );
+ }
+ }
+ }
+ ogg_stream_clear( &os );
+ vorbis_block_clear( &vb );
+ vorbis_dsp_clear( &vd );
+ vorbis_comment_clear( &vc );
+ vorbis_info_clear( &vi );
+ len = buflen;
+ if ( len>0 )
+ return bufEncode;
+ else
+ return NULL;
+}
+
+KOggEnc::~KOggEnc()
+{
+ delete [] bufEncode;
+ delete [] tmpBuf;
+}
diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.h b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.h
new file mode 100644
index 0000000..9560a53
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/oggvorbis/koggenc.h
@@ -0,0 +1,92 @@
+/*
+ * koggenc.h
+ *
+ * Copyright (C) 2002-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KOGGENC_H
+#define KOGGENC_H
+
+extern "C"
+{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <vorbis/vorbisenc.h>
+}
+
+#include <kconfig.h>
+
+#include "kaffeineaudioencoder.h"
+#include "oggconfig.h"
+
+class OggSettings : public OggConfig
+{
+ Q_OBJECT
+public:
+ OggSettings( QWidget *parent, KConfig *confile );
+ ~OggSettings();
+
+ int getQuality();
+
+public slots:
+ virtual void accept();
+
+private:
+ KConfig *Conf;
+};
+
+class KOggEnc : public KaffeineAudioEncoder
+{
+ Q_OBJECT
+
+public:
+
+ KOggEnc( QWidget*, const char*, QObject*, const char*, const QStringList& );
+ ~KOggEnc();
+
+ // Reimplemented from KaffeineAudioEncoder
+ bool options( QWidget*, KConfig* );
+ QString getExtension();
+ void start( QString title=0, QString artist=0, QString album=0, QString tracknumber=0, QString genre=0 );
+ char* getHeader( int &len );
+ char* encode( char *data, int datalen, int &len );
+ char* stop( int &len );
+ //****************************
+
+ static KAboutData* createAboutData();
+
+private:
+
+ ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
+ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
+ ogg_packet op; /* one raw packet of data for decode */
+ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */
+ vorbis_comment vc; /* struct that stores all the user comments */
+ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+ vorbis_block vb; /* local working space for packet->PCM decode */
+ ogg_packet header;
+ ogg_packet header_comm;
+ ogg_packet header_code;
+ char *bufEncode;
+ char *tmpBuf;
+ float encodingQuality;
+};
+
+#endif /* KOGGENC_H */
diff --git a/kaffeine/src/input/disc/plugins/oggvorbis/oggconfig.ui b/kaffeine/src/input/disc/plugins/oggvorbis/oggconfig.ui
new file mode 100644
index 0000000..178e938
--- /dev/null
+++ b/kaffeine/src/input/disc/plugins/oggvorbis/oggconfig.ui
@@ -0,0 +1,191 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>OggConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>OggConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>327</width>
+ <height>131</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Ogg Vorbis Options</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox1</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLCDNumber" row="1" column="1">
+ <property name="name">
+ <cstring>oggLCD</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <property name="numDigits">
+ <number>3</number>
+ </property>
+ <property name="value" stdset="0">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QSlider" row="1" column="0">
+ <property name="name">
+ <cstring>oggSlid</cstring>
+ </property>
+ <property name="minValue">
+ <number>-1</number>
+ </property>
+ <property name="maxValue">
+ <number>10</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Quality :</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>81</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Horizontal Spacing2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>157</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>OggConfig</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>OggConfig</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>oggSlid</sender>
+ <signal>valueChanged(int)</signal>
+ <receiver>oggLCD</receiver>
+ <slot>display(int)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kaffeine/src/input/dvb/Makefile.am b/kaffeine/src/input/dvb/Makefile.am
new file mode 100644
index 0000000..7b6c866
--- /dev/null
+++ b/kaffeine/src/input/dvb/Makefile.am
@@ -0,0 +1,81 @@
+SUBDIRS = lib plugins .
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \
+ -I$(top_srcdir)/kaffeine/src/input/dvb/lib \
+ -I$(top_srcdir)/kaffeine/src/input/dvb/plugins/stream \
+ -I$(top_srcdir)/kaffeine/src/input/dvb/plugins/epg \
+ -I$(top_srcdir)/kaffeine/src \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libkaffeinedvb.la
+
+libkaffeinedvb_la_SOURCES = audioeditor.cpp \
+ audioeditor.h \
+ audioeditorui.ui \
+ channeldesc.cpp \
+ channeldesc.h \
+ channeleditor.cpp \
+ channeleditor.h \
+ channeleditorui.ui \
+ dvbconfig.cpp \
+ dvbconfig.h \
+ dvbevents.cpp \
+ dvbevents.h \
+ dvbout.cpp \
+ dvbout.h \
+ dvbpanel.cpp \
+ dvbpanel.h \
+ dvbsection.h \
+ dvbsi.cpp \
+ dvbsi.h \
+ dvbstream.cpp \
+ dvbstream.h \
+ gdvb.h \
+ kevents.cpp \
+ kevents.h \
+ kgradprogress.cpp \
+ kgradprogress.h \
+ krecord.cpp \
+ krecord.h \
+ ktimereditor.cpp \
+ ktimereditor.h \
+ scandialog.cpp \
+ scandialog.h \
+ scandialogui.ui \
+ sender.cpp \
+ sender.h \
+ ts2rtp.cpp \
+ ts2rtp.h \
+ subeditorui.ui \
+ subeditor.cpp \
+ subeditor.h \
+ broadcasteditorui.ui \
+ broadcasteditor.cpp \
+ broadcasteditor.h \
+ cleaner.cpp \
+ cleaner.h \
+ crontimerui.ui \
+ crontimer.cpp \
+ crontimer.h \
+ dvbcam.cpp \
+ dvbcam.h
+
+libkaffeinedvb_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) \
+ -L$(top_srcdir)/kaffeine/src/input \
+ -L$(top_srcdir)/kaffeine/src/input/dvb/plugins/stream \
+ -L$(top_srcdir)/kaffeine/src/input/dvb/plugins/epg \
+ ./lib/libdvbapi \
+ ./lib/libdvben50221 \
+ ./lib/libucsi
+
+libkaffeinedvb_la_LIBADD = \
+ $(top_builddir)/kaffeine/src/input/dvb/plugins/stream/libkaffeinedvbplugin.la \
+ $(top_builddir)/kaffeine/src/input/dvb/plugins/epg/libkaffeineepgplugin.la \
+ $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \
+ ./lib/libdvbapi/libdvbapi.la ./lib/libdvben50221/libdvben50221.la ./lib/libucsi/libucsi.la
+
+# this is where the XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kaffeine
+shellrc_DATA = kaffeinedvb.rc
diff --git a/kaffeine/src/input/dvb/audioeditor.cpp b/kaffeine/src/input/dvb/audioeditor.cpp
new file mode 100644
index 0000000..a8d8a5f
--- /dev/null
+++ b/kaffeine/src/input/dvb/audioeditor.cpp
@@ -0,0 +1,160 @@
+/*
+ * audioeditor.cpp
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qlistbox.h>
+#include <qspinbox.h>
+#include <qpushbutton.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include "audioeditor.h"
+
+AudioEditor::AudioEditor( ChannelDesc *chan, QWidget *parent ) : AudioEditorUI( parent )
+{
+ QString s, t;
+ int i;
+
+ channel = chan;
+ pidList->clear();
+
+ for ( i=0; i<channel->napid; i++ ) insertItem( i );
+
+ if ( channel->napid==channel->maxapid ) newBtn->setEnabled( false );
+
+ connect( pidList, SIGNAL(highlighted(int)), this, SLOT(showProp(int)) );
+ connect( upBtn, SIGNAL(clicked()), this, SLOT(itemUp()) );
+ connect( downBtn, SIGNAL(clicked()), this, SLOT(itemDown()) );
+ connect( delBtn, SIGNAL(clicked()), this, SLOT(itemDelete()) );
+ connect( updateBtn, SIGNAL(clicked()), this, SLOT(itemUpdate()) );
+ connect( newBtn, SIGNAL(clicked()), this, SLOT(itemNew()) );
+}
+
+void AudioEditor::insertItem( int index, bool updt )
+{
+ QString s, t;
+
+ s = t.setNum( channel->apid[index].pid );
+ if ( !channel->apid[index].lang.isEmpty() ) s = s+"("+channel->apid[index].lang+")";
+ if ( channel->apid[index].ac3 ) s = s+"(ac3)";
+ if ( updt ) pidList->changeItem( s, index );
+ else pidList->insertItem( s, index );
+}
+
+void AudioEditor::showProp( int index )
+{
+ if ( index<0 ) {
+ pidSpin->setValue( 0 );
+ langLe->setText( "" );
+ ac3Cb->setChecked( false );
+ }
+ else {
+ pidSpin->setValue( channel->apid[index].pid );
+ langLe->setText( channel->apid[index].lang );
+ ac3Cb->setChecked( channel->apid[index].ac3 );
+ }
+}
+
+void AudioEditor::itemUp()
+{
+ AudioPid a;
+
+ int n = pidList->currentItem();
+
+ if ( n<1 ) return;
+
+ a = channel->apid[n-1];
+ channel->apid[n-1] = channel->apid[n];
+ channel->apid[n] = a;
+
+ insertItem( n, true );
+ insertItem( n-1, true );
+}
+
+void AudioEditor::itemDown()
+{
+ AudioPid a;
+
+ int n = pidList->currentItem();
+
+ if ( (n<0) || (n>(channel->napid-2)) ) return;
+
+ a = channel->apid[n+1];
+ channel->apid[n+1] = channel->apid[n];
+ channel->apid[n] = a;
+
+ insertItem( n, true );
+ insertItem( n+1, true );
+}
+
+void AudioEditor::itemDelete()
+{
+ int n = pidList->currentItem();
+
+ if ( channel->napid==0 || (n<0) ) return; //for sure
+
+ for ( int i=n; i<channel->napid-1; i++ ) channel->apid[i] = channel->apid[i+1];
+ channel->napid--;
+ pidList->removeItem( n );
+
+ newBtn->setEnabled( true );
+}
+
+void AudioEditor::itemUpdate()
+{
+ int n = pidList->currentItem();
+
+ if ( n<0 ) return;
+
+ channel->apid[n].pid = pidSpin->value();
+ channel->apid[n].lang = langLe->text().stripWhiteSpace();
+ if ( ac3Cb->isChecked() ) channel->apid[n].ac3 = 1;
+ else channel->apid[n].ac3 = 0;
+
+ insertItem( n, true );
+}
+
+void AudioEditor::itemNew()
+{
+ if ( channel->napid==channel->maxapid ) { //for sure
+ newBtn->setEnabled( false );
+ return;
+ }
+
+ if ( !pidSpin->value() ) {
+ KMessageBox::sorry( this, i18n("Pid must be non zero!") );
+ return;
+ }
+ channel->napid++;
+ channel->apid[channel->napid-1].pid = pidSpin->value();
+ channel->apid[channel->napid-1].lang = langLe->text().stripWhiteSpace();
+ if ( ac3Cb->isChecked() ) channel->apid[channel->napid-1].ac3 = 1;
+ else channel->apid[channel->napid-1].ac3 = 0;
+ insertItem( channel->napid-1 );
+ if ( channel->napid==channel->maxapid ) newBtn->setEnabled( false );
+}
+
+AudioEditor::~AudioEditor()
+{
+}
+
+#include "audioeditor.moc"
diff --git a/kaffeine/src/input/dvb/audioeditor.h b/kaffeine/src/input/dvb/audioeditor.h
new file mode 100644
index 0000000..8751505
--- /dev/null
+++ b/kaffeine/src/input/dvb/audioeditor.h
@@ -0,0 +1,53 @@
+/*
+ * audioeditor.h
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef AUDIOEDITOR_H
+#define AUDIOEDITOR_H
+
+#include "channeldesc.h"
+#include "audioeditorui.h"
+
+class AudioEditor : public AudioEditorUI
+{
+ Q_OBJECT
+
+public:
+
+ AudioEditor( ChannelDesc *chan, QWidget *parent );
+ ~AudioEditor();
+
+private slots:
+
+ void showProp( int index );
+ void itemUp();
+ void itemDown();
+ void itemDelete();
+ void itemUpdate();
+ void itemNew();
+
+private:
+
+ void insertItem( int index, bool updt=false );
+
+ ChannelDesc *channel;
+
+};
+
+#endif /* AUDIOEDITOR_H */
diff --git a/kaffeine/src/input/dvb/audioeditorui.ui b/kaffeine/src/input/dvb/audioeditorui.ui
new file mode 100644
index 0000000..20b07ef
--- /dev/null
+++ b/kaffeine/src/input/dvb/audioeditorui.ui
@@ -0,0 +1,319 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AudioEditorUI</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>AudioEditorUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>439</width>
+ <height>284</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Audio PIDs editor</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout23</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox10</cstring>
+ </property>
+ <property name="title">
+ <string>Audio PIDs</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox" row="0" column="0">
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>pidList</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout21</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>upBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Move Up</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>downBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Move Down</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>delBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>updateBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;&lt; Update Selected</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>newBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;&lt; New</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox9</cstring>
+ </property>
+ <property name="title">
+ <string>Properties</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>pidSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>8192</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Pid:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Lang:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>ac3Cb</cstring>
+ </property>
+ <property name="text">
+ <string>AC3</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>langLe</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>2</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>AudioEditorUI</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>okBtn</tabstop>
+ <tabstop>pidList</tabstop>
+ <tabstop>upBtn</tabstop>
+ <tabstop>downBtn</tabstop>
+ <tabstop>delBtn</tabstop>
+ <tabstop>updateBtn</tabstop>
+ <tabstop>newBtn</tabstop>
+ <tabstop>pidSpin</tabstop>
+ <tabstop>langLe</tabstop>
+ <tabstop>ac3Cb</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kaffeine/src/input/dvb/broadcasteditor.cpp b/kaffeine/src/input/dvb/broadcasteditor.cpp
new file mode 100644
index 0000000..0e6c8a6
--- /dev/null
+++ b/kaffeine/src/input/dvb/broadcasteditor.cpp
@@ -0,0 +1,132 @@
+/*
+ * broadcasteditor.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qdir.h>
+#include <qvaluelist.h>
+
+#include <kpushbutton.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "broadcasteditor.h"
+
+BroadcastEditor::BroadcastEditor( QWidget *parent, QPtrList<ChannelDesc> *ch, QPtrList<ChannelDesc> *ret ) : BroadcastEditorUI( parent )
+{
+ KIconLoader *icon = new KIconLoader();
+
+ tvPix = icon->loadIcon( "kdvbtv", KIcon::Small );
+ tvcPix = icon->loadIcon( "kdvbtvc", KIcon::Small );
+ raPix = icon->loadIcon( "kdvbra", KIcon::Small );
+ racPix = icon->loadIcon( "kdvbrac", KIcon::Small );
+ addBtn->setGuiItem( KGuiItem(i18n("Add"), icon->loadIconSet("forward", KIcon::Small) ) );
+ resetBtn->setGuiItem( KGuiItem(i18n("Reset"), icon->loadIconSet("reload", KIcon::Small) ) );
+ cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) );
+ okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) );
+
+ connect( channelLb, SIGNAL(doubleClicked(QListBoxItem*)), this, SLOT(slotAddChannel(QListBoxItem*)) );
+
+ chan = ch;
+ list = ret;
+
+ resetList();
+ delete icon;
+}
+
+BroadcastEditor::~BroadcastEditor()
+{
+}
+
+ChannelDesc* BroadcastEditor::getChannel( const QString &name )
+{
+ int i;
+
+ for ( i=0; i<(int)chan->count(); i++ ) {
+ if ( chan->at(i)->name==name ) return chan->at(i);
+ }
+ return 0;
+}
+
+void BroadcastEditor::slotAddChannel(QListBoxItem*)
+{
+ addToList();
+}
+
+void BroadcastEditor::addToList()
+{
+ int i;
+ QString curName;
+ QValueList<QListBoxItem*> qvl;
+ ChannelDesc *c=0, *d=0;
+
+ for ( i=0; i<(int)channelLb->count(); i++ ) {
+ if ( channelLb->isSelected(i) ) {
+ curName = channelLb->text(i);
+ c = getChannel( curName );
+ if ( !c ) continue;
+ broadcastLb->insertItem( *channelLb->pixmap(i), channelLb->text(i) );
+ list->append( c );
+ qvl.append(channelLb->item(i));
+ }
+ }
+ if ( !c ) return;
+ for ( i=0; i<(int)qvl.count(); i++ ) channelLb->takeItem( qvl[i] );
+
+ qvl.clear();
+ for ( i=0; i<(int)channelLb->count(); i++ ) {
+ d = getChannel( channelLb->text(i) );
+ if ( !d ) continue;
+ if ( d->tp!=c->tp ) qvl.append(channelLb->item(i));
+ }
+ for ( i=0; i<(int)qvl.count(); i++ ) channelLb->takeItem( qvl[i] );
+
+ channelLb->setSelectionMode( QListBox::Extended );
+}
+
+bool BroadcastEditor::getChannelList()
+{
+ int i;
+ ChannelDesc *c;
+
+ for ( i=0; i<(int)chan->count(); i++ ) {
+ c = chan->at(i);
+ if ( c->fta ) {
+ if ( c->type==1 ) channelLb->insertItem( tvcPix, c->name );
+ else channelLb->insertItem( racPix, c->name );
+ }
+ else {
+ if ( c->type==1 ) channelLb->insertItem( tvPix, c->name );
+ else channelLb->insertItem( raPix, c->name );
+ }
+ }
+ return true;
+}
+
+void BroadcastEditor::resetList()
+{
+ addBtn->setEnabled( true );
+ channelLb->clear();
+ broadcastLb->clear();
+ list->clear();
+ getChannelList();
+ channelLb->sort();
+ channelLb->setSelectionMode( QListBox::Single );
+}
+
+#include "broadcasteditor.moc"
diff --git a/kaffeine/src/input/dvb/broadcasteditor.h b/kaffeine/src/input/dvb/broadcasteditor.h
new file mode 100644
index 0000000..13c619f
--- /dev/null
+++ b/kaffeine/src/input/dvb/broadcasteditor.h
@@ -0,0 +1,58 @@
+/*
+ * broadcasteditor.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef BROADCASTEDITOR_H
+#define BROADCASTEDITOR_H
+
+#include <qpixmap.h>
+#include <qfile.h>
+#include <qlistbox.h>
+
+#include "broadcasteditorui.h"
+#include "channeldesc.h"
+
+class BroadcastEditor : public BroadcastEditorUI
+{
+ Q_OBJECT
+
+public:
+
+ BroadcastEditor( QWidget *parent, QPtrList<ChannelDesc> *ch, QPtrList<ChannelDesc> *ret );
+ ~BroadcastEditor();
+
+ QPtrList<ChannelDesc> *chan;
+ QPtrList<ChannelDesc> *list;
+
+public slots:
+
+ virtual void addToList();
+ virtual void resetList();
+ void slotAddChannel(QListBoxItem*);
+
+private:
+
+ bool getChannelList();
+ ChannelDesc* getChannel( const QString &name );
+
+ QPixmap tvPix, raPix, tvcPix, racPix;
+
+};
+
+#endif /* BROADCASTEDITOR_H */
diff --git a/kaffeine/src/input/dvb/broadcasteditorui.ui b/kaffeine/src/input/dvb/broadcasteditorui.ui
new file mode 100644
index 0000000..034bd39
--- /dev/null
+++ b/kaffeine/src/input/dvb/broadcasteditorui.ui
@@ -0,0 +1,315 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>BroadcastEditorUI</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>BroadcastEditorUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>458</width>
+ <height>378</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Broadcasting Editor</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Available channels:</string>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QListBox">
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>channelLb</cstring>
+ </property>
+ <property name="columnMode">
+ <enum>FixedNumber</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout1</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>addBtn</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>resetBtn</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Broadcasting list:</string>
+ </property>
+ </widget>
+ <widget class="QListBox">
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>broadcastLb</cstring>
+ </property>
+ <property name="columnMode">
+ <enum>FixedNumber</enum>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>Line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>addBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>BroadcastEditorUI</receiver>
+ <slot>addToList()</slot>
+ </connection>
+ <connection>
+ <sender>resetBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>BroadcastEditorUI</receiver>
+ <slot>resetList()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>BroadcastEditorUI</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>BroadcastEditorUI</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>channelLb</tabstop>
+ <tabstop>addBtn</tabstop>
+ <tabstop>resetBtn</tabstop>
+ <tabstop>broadcastLb</tabstop>
+ <tabstop>cancelBtn</tabstop>
+ <tabstop>okBtn</tabstop>
+</tabstops>
+<slots>
+ <slot>addToList()</slot>
+ <slot>resetList()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kaffeine/src/input/dvb/channeldesc.cpp b/kaffeine/src/input/dvb/channeldesc.cpp
new file mode 100644
index 0000000..5ab4acf
--- /dev/null
+++ b/kaffeine/src/input/dvb/channeldesc.cpp
@@ -0,0 +1,184 @@
+/*
+ * channeldesc.cpp
+ *
+ * Copyright (C) 2003-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <math.h>
+
+#include "channeldesc.h"
+
+AudioPid::AudioPid()
+{
+ pid=ac3=0;
+ lang="";
+}
+
+AudioPid::AudioPid( unsigned short apid )
+{
+ pid = apid;
+ ac3=0;
+ lang="";
+}
+
+AudioPid::~AudioPid()
+{
+}
+
+ChannelDesc::ChannelDesc()
+{
+ fta=sid=ttpid=vpid=pmtpid=type=0;
+ vType=0;
+ num=0;
+ name=provider=category="";
+ completed = 0;
+ tp.freq=tp.sr=0;
+ tp.pol='v';
+ maxapid=MAXAPID;
+ for ( int i=0; i<maxapid; i++ ) {
+ apid[i].pid=apid[i].ac3=0;
+ apid[i].lang="";
+ }
+ napid=0;
+ maxsubpid=MAXSUBPID;
+ for ( int i=0; i<maxsubpid; i++ ) {
+ subpid[i].pid=subpid[i].page=subpid[i].id=0;
+ subpid[i].type=0;
+ subpid[i].lang="???";
+ }
+ nsubpid=0;
+}
+
+ChannelDesc::ChannelDesc( const ChannelDesc &chan )
+{
+ num = chan.num;
+ fta = chan.fta;
+ sid = chan.sid;
+ vpid = chan.vpid;
+ vType = chan.vType;
+ pmtpid = chan.pmtpid;
+ type = chan.type;
+ ttpid = chan.ttpid;
+ name = chan.name;
+ provider = chan.provider;
+ category = chan.category;
+ completed = chan.completed;
+ tp = chan.tp;
+ maxapid = chan.maxapid;
+ for ( int i=0; i<maxapid; i++ ) {
+ apid[i] = chan.apid[i];
+ apid[i].ac3 = chan.apid[i].ac3;
+ apid[i].lang = chan.apid[i].lang;
+ }
+ napid = chan.napid;
+ maxsubpid = chan.maxsubpid;
+ for ( int i=0; i<maxsubpid; i++ ) {
+ subpid[i] = chan.subpid[i];
+ subpid[i].type = chan.subpid[i].type;
+ subpid[i].lang = chan.subpid[i].lang;
+ }
+ nsubpid = chan.nsubpid;
+}
+
+ChannelDesc::~ChannelDesc()
+{
+}
+
+Transponder::Transponder()
+{
+ source = "";
+ type = FE_QPSK;
+ freq = 0;
+ sr = 0;
+ pol = 'v';
+ nid=tsid = 0;
+ inversion=INVERSION_AUTO;
+ modulation=QAM_AUTO;
+ hierarchy=HIERARCHY_AUTO;
+ guard=GUARD_INTERVAL_AUTO;
+ transmission=TRANSMISSION_MODE_AUTO;
+ coderateL=FEC_AUTO;
+ coderateH=FEC_AUTO;
+ bandwidth=BANDWIDTH_AUTO;
+ snr = 0;
+}
+
+Transponder::Transponder( const Transponder &trans )
+{
+ source = trans.source;
+ type = trans.type;
+ freq = trans.freq;
+ sr = trans.sr;
+ pol = trans.pol;
+ tsid = trans.tsid;
+ nid = trans.nid;
+ inversion=trans.inversion;
+ modulation=trans.modulation;
+ hierarchy=trans.hierarchy;
+ guard=trans.guard;
+ transmission=trans.transmission;
+ coderateL=trans.coderateL;
+ coderateH=trans.coderateH;
+ bandwidth=trans.bandwidth;
+}
+
+bool Transponder::sameAs( Transponder *trans )
+{
+ int f1 = this->freq*1000;
+ int f2 = trans->freq*1000;
+
+ if ( fabs(f1-f2) < 2000 ) return true;
+ return false;
+}
+
+bool Transponder::operator==( const Transponder &t )
+{
+ if ( this->bandwidth==t.bandwidth
+ && this->source==t.source
+ && this->coderateH==t.coderateH
+ && this->coderateL==t.coderateL
+ && this->freq==t.freq
+ && this->guard==t.guard
+ && this->hierarchy==t.hierarchy
+ && this->inversion==t.inversion
+ && this->modulation==t.modulation
+ && this->pol==t.pol
+ && this->sr==t.sr
+ && this->transmission==t.transmission ) return true;
+ return false;
+}
+
+bool Transponder::operator!=( const Transponder &t )
+{
+ if ( this->bandwidth!=t.bandwidth
+ || this->source!=t.source
+ || this->coderateH!=t.coderateH
+ || this->coderateL!=t.coderateL
+ || this->freq!=t.freq
+ || this->guard!=t.guard
+ || this->hierarchy!=t.hierarchy
+ || this->inversion!=t.inversion
+ || this->modulation!=t.modulation
+ || this->pol!=t.pol
+ || this->sr!=t.sr
+ || this->transmission!=t.transmission ) return true;
+ return false;
+}
+
+Transponder::~Transponder()
+{
+}
diff --git a/kaffeine/src/input/dvb/channeldesc.h b/kaffeine/src/input/dvb/channeldesc.h
new file mode 100644
index 0000000..f4bc1ab
--- /dev/null
+++ b/kaffeine/src/input/dvb/channeldesc.h
@@ -0,0 +1,137 @@
+/*
+ * channeldesc.h
+ *
+ * Copyright (C) 2003-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CHANNELDESC_H
+#define CHANNELDESC_H
+
+#include <qstring.h>
+#include <qptrlist.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+#include <qpixmap.h>
+
+#include <linux/dvb/frontend.h>
+
+#include "kaffeinedvbevents.h"
+
+#define MAXAPID 20
+#define MAXSUBPID 10
+
+class RecTimer
+{
+
+public:
+
+ QString name;
+ QString fullPath;
+ QString channel;
+ QDateTime begin;
+ QTime duration;
+ char running;
+ int mode;
+};
+
+class AudioPid
+{
+
+public:
+
+ AudioPid();
+ AudioPid( unsigned short apid );
+ ~AudioPid();
+
+ unsigned short pid;
+ QString lang;
+ char ac3;
+};
+
+class SubPid
+{
+
+public:
+
+ unsigned short pid, page, id;
+ unsigned char type;
+ QString lang;
+};
+
+class Transponder
+{
+
+public:
+
+ Transponder();
+ Transponder( const Transponder &trans ); //copy
+ ~Transponder();
+ bool sameAs( Transponder *trans );
+ bool operator==( const Transponder &t );
+ bool operator!=( const Transponder &t );
+
+ QString source;
+ fe_type_t type; // S, C or T
+ unsigned long freq;
+ QValueList<unsigned long> freqlist;
+ char pol;
+ unsigned long sr;
+ unsigned short nid;
+ unsigned short tsid;
+ fe_spectral_inversion_t inversion;
+ fe_modulation_t modulation;
+ fe_hierarchy_t hierarchy;
+ fe_guard_interval_t guard;
+ fe_transmit_mode_t transmission;
+ fe_code_rate_t coderateL;
+ fe_code_rate_t coderateH;
+ fe_bandwidth_t bandwidth;
+ int snr;
+};
+
+class ChannelDesc
+{
+
+public:
+
+ ChannelDesc();
+ ChannelDesc( const ChannelDesc &chan ); //copy
+ ~ChannelDesc();
+
+ QString provider;
+ QString name;
+ QString category;
+ unsigned int num;
+ unsigned short sid;
+ unsigned short vpid;
+ unsigned char vType; // video stream type
+ AudioPid apid[MAXAPID];
+ char napid;
+ char maxapid;
+ unsigned short ttpid;
+ SubPid subpid[MAXSUBPID];
+ char nsubpid;
+ char maxsubpid;
+ unsigned short pmtpid;
+ unsigned char fta; // 0 for free
+ unsigned char type; // 1 for TV , 2 for RA
+ int completed;
+ Transponder tp;
+ QPixmap pix;
+};
+
+#endif /* CHANNELDESC_H */
diff --git a/kaffeine/src/input/dvb/channeleditor.cpp b/kaffeine/src/input/dvb/channeleditor.cpp
new file mode 100644
index 0000000..6b04fe4
--- /dev/null
+++ b/kaffeine/src/input/dvb/channeleditor.cpp
@@ -0,0 +1,330 @@
+/*
+ * channeleditor.cpp
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qspinbox.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "channeleditor.h"
+#include "audioeditor.h"
+#include "subeditor.h"
+
+ChannelEditor::ChannelEditor( QStringList src, bool m, ChannelDesc *chan, QPtrList<ChannelDesc> *cdesc, QWidget *parent ) : ChannelEditorUI( parent )
+{
+ int i;
+ channel = chan;
+ mode = m;
+ chandesc = cdesc;
+ orgName = channel->name;
+
+ sourceComb->insertStringList( src );
+ for ( i=0; i<(int)sourceComb->count(); i++ ) {
+ if ( sourceComb->text(i)==channel->tp.source ) {
+ sourceComb->setCurrentItem(i);
+ break;
+ }
+ }
+
+ if ( channel->tp.type==FE_QAM ) initC();
+ else if ( channel->tp.type==FE_OFDM ) initT();
+ else if ( channel->tp.type==FE_QPSK ) initS();
+ else initA();
+
+ if ( mode ) {
+ ftaCb->setEnabled( false );
+ pidsGroup->setEnabled( false );
+ numSpin->setEnabled( false );
+ setCaption( i18n("Initial Transponder Settings") );
+ }
+ else {
+ numSpin->setMinValue( 1 );
+ numSpin->setMaxValue( chandesc->count() );
+ chanNum = channel->num;
+ numSpin->setValue( channel->num );
+ sidSpin->setValue( channel->sid );
+ vpidSpin->setValue( channel->vpid );
+ ttpidSpin->setValue( channel->ttpid );
+ tsidSpin->setValue( channel->tp.tsid );
+ nidSpin->setValue( channel->tp.nid );
+ ftaCb->setChecked( channel->fta );
+ }
+ nameLe->setText( channel->name );
+
+ connect( apidBtn, SIGNAL(clicked()), this, SLOT(editAudio()) );
+ connect( subpidBtn, SIGNAL(clicked()), this, SLOT(editSubtitle()) );
+}
+
+void ChannelEditor::editAudio()
+{
+ AudioEditor dlg( channel, this );
+
+ dlg.exec();
+}
+
+void ChannelEditor::editSubtitle()
+{
+ SubEditor dlg( channel, this );
+
+ dlg.exec();
+}
+
+void ChannelEditor::accept()
+{
+ int ret, i;
+ QString name;
+
+ name = nameLe->text().stripWhiteSpace();
+ if ( name.isEmpty() ) {
+ KMessageBox::sorry( this, i18n("You must give it a name!") );
+ return;
+ }
+
+ if ( !mode ) {
+ for ( ret=0; ret<(int)chandesc->count(); ret++ ) {
+ if ( (channel->name==chandesc->at(ret)->name) && (channel->name!=orgName) ) {
+ KMessageBox::sorry( this, i18n("This name is not unique.") );
+ return;
+ }
+ }
+ if ( ftaCb->isChecked() ) channel->fta = 1;
+ else channel->fta = 0;
+ channel->vpid = vpidSpin->value();
+ channel->sid = sidSpin->value();
+ channel->ttpid = ttpidSpin->value();
+ channel->tp.tsid = tsidSpin->value();
+ channel->tp.nid = nidSpin->value();
+ if ( !channel->napid ) {
+ KMessageBox::sorry( this, i18n("Missing audio pid(s)!") );
+ return;
+ }
+ if ( numSpin->value()!=chanNum ) {
+ for ( i=0; i<(int)chandesc->count(); i++ ) {
+ if ( (int)chandesc->at(i)->num==numSpin->value() ) {
+ chandesc->at(i)->num = chanNum;
+ break;
+ }
+ }
+ }
+ channel->num = numSpin->value();
+ if ( channel->vpid ) channel->type = 1;
+ else channel->type = 2;
+ }
+ channel->name = name;
+ channel->tp.source = sourceComb->currentText();
+ if ( channel->tp.type==FE_QPSK ) {
+ channel->tp.freq = freqSpin->value();
+ channel->tp.sr = srSpin->value();
+ if ( verticalRadio->isChecked() ) channel->tp.pol = 'v';
+ else channel->tp.pol = 'h';
+ channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem());
+ channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem());
+ }
+ else if ( channel->tp.type==FE_QAM ) {
+ channel->tp.freq = freqSpin->value();
+ channel->tp.sr = srSpin->value();
+ channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem());
+ channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem());
+ channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem());
+ }
+ else if ( channel->tp.type==FE_OFDM ) {
+ channel->tp.freq = freqSpin->value();
+ channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem());
+ channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem());
+ channel->tp.coderateL = (fe_code_rate_t)(FEC_NONE+coderateLComb->currentItem());
+ channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem());
+ channel->tp.transmission = (fe_transmit_mode_t)(TRANSMISSION_MODE_2K+transmissionComb->currentItem());
+ channel->tp.bandwidth = (fe_bandwidth_t)(BANDWIDTH_8_MHZ+bandwidthComb->currentItem());
+ channel->tp.hierarchy = (fe_hierarchy_t)(HIERARCHY_NONE+hierarchyComb->currentItem());
+ channel->tp.guard = (fe_guard_interval_t)(GUARD_INTERVAL_1_32+guardComb->currentItem());
+ }
+ else {
+ channel->tp.freq = freqSpin->value();
+ channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem());
+ switch (modulationComb->currentItem()) {
+ case 0: channel->tp.modulation = QAM_64; break;
+ case 1: channel->tp.modulation = QAM_256; break;
+ case 2: channel->tp.modulation = VSB_8; break;
+ case 3: channel->tp.modulation = VSB_16; break;
+ default: channel->tp.modulation = QAM_AUTO; break;
+ }
+ }
+
+ done( Accepted );
+}
+
+void ChannelEditor::initS()
+{
+ freqSpin->setValue( channel->tp.freq );
+ srSpin->setValue( channel->tp.sr );
+ if ( channel->tp.pol=='v' ) polGroup->setButton( 0 ) ;
+ else polGroup->setButton( 1 ) ;
+ inversionComb->insertStringList( inversionList() );
+ inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion );
+ coderateHComb->insertStringList( coderateList() );
+ coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH );
+ transmissionComb->setEnabled( false );
+ coderateLComb->setEnabled( false );
+ bandwidthComb->setEnabled( false );
+ modulationComb->setEnabled( false );
+ hierarchyComb->setEnabled( false );
+ guardComb->setEnabled( false );
+}
+
+void ChannelEditor::initC()
+{
+ freqSpin->setValue( channel->tp.freq );
+ srSpin->setValue( channel->tp.sr );
+ inversionComb->insertStringList( inversionList() );
+ inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion );
+ coderateHComb->insertStringList( coderateList() );
+ coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH );
+ modulationComb->insertStringList( modulationList() );
+ modulationComb->setCurrentItem( QPSK+channel->tp.modulation );
+ polGroup->setEnabled( false );
+ transmissionComb->setEnabled( false );
+ coderateLComb->setEnabled( false );
+ bandwidthComb->setEnabled( false );
+ hierarchyComb->setEnabled( false );
+ guardComb->setEnabled( false );
+}
+
+void ChannelEditor::initT()
+{
+ freqSpin->setValue( channel->tp.freq );
+ inversionComb->insertStringList( inversionList() );
+ inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion );
+ coderateHComb->insertStringList( coderateList() );
+ coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH );
+ coderateLComb->insertStringList( coderateList() );
+ coderateLComb->setCurrentItem( FEC_NONE+channel->tp.coderateL );
+ modulationComb->insertStringList( modulationList() );
+ modulationComb->setCurrentItem( QPSK+channel->tp.modulation );
+ transmissionComb->insertStringList( transmissionList() );
+ transmissionComb->setCurrentItem( TRANSMISSION_MODE_2K+channel->tp.transmission );
+ bandwidthComb->insertStringList( bandwidthList() );
+ bandwidthComb->setCurrentItem( BANDWIDTH_8_MHZ+channel->tp.bandwidth );
+ hierarchyComb->insertStringList( hierarchyList() );
+ hierarchyComb->setCurrentItem( HIERARCHY_NONE+channel->tp.hierarchy );
+ guardComb->insertStringList( guardList() );
+ guardComb->setCurrentItem( GUARD_INTERVAL_1_32+channel->tp.guard );
+ srSpin->setEnabled( false );
+ polGroup->setEnabled( false );
+}
+
+void ChannelEditor::initA()
+{
+ freqSpin->setValue( channel->tp.freq );
+ inversionComb->insertStringList( inversionList() );
+ inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion );
+ modulationComb->insertStringList( modulationListAtsc() );
+ switch (channel->tp.modulation) {
+ case QAM_64: modulationComb->setCurrentItem(0); break;
+ case QAM_256: modulationComb->setCurrentItem(1); break;
+ case VSB_8: modulationComb->setCurrentItem(2); break;
+ case VSB_16: modulationComb->setCurrentItem(3); break;
+ default: modulationComb->setCurrentItem(4); break;
+ }
+ srSpin->setEnabled( false );
+ polGroup->setEnabled( false );
+ transmissionComb->setEnabled( false );
+ coderateHComb->setEnabled( false );
+ coderateLComb->setEnabled( false );
+ bandwidthComb->setEnabled( false );
+ hierarchyComb->setEnabled( false );
+ guardComb->setEnabled( false );
+}
+
+QStringList ChannelEditor::inversionList()
+{
+ QStringList list;
+
+ list<<"OFF"<<"ON"<<"AUTO";
+ return list;
+}
+
+QStringList ChannelEditor::coderateList()
+{
+ QStringList list;
+
+ list<<"NONE"<<"1/2"<<"2/3"<<"3/4"<<"4/5"<<"5/6"<<"6/7"<<"7/8"<<"8/9"<<"AUTO";
+ return list;
+}
+
+QStringList ChannelEditor::modulationList()
+{
+ QStringList list;
+
+ list<<"QPSK"<<"QAM 16"<<"QAM 32"<<"QAM 64"<<"QAM 128"<<"QAM 256"<<"AUTO";
+ return list;
+}
+
+QStringList ChannelEditor::modulationListAtsc()
+{
+ QStringList list;
+
+ list<<"QAM 64"<<"QAM 256"<<"VSB 8"<<"VSB 16"<<"AUTO";
+ return list;
+}
+
+QStringList ChannelEditor::transmissionList()
+{
+ QStringList list;
+
+ list<<"2K"<<"8K"<<"AUTO";
+ return list;
+}
+
+QStringList ChannelEditor::bandwidthList()
+{
+ QStringList list;
+
+ list<<"8 MHz"<<"7 MHz"<<"6 MHz"<<"AUTO";
+ return list;
+}
+
+QStringList ChannelEditor::hierarchyList()
+{
+ QStringList list;
+
+ list<<"NONE"<<"1"<<"2"<<"4"<<"AUTO";
+ return list;
+}
+
+QStringList ChannelEditor::guardList()
+{
+ QStringList list;
+
+ list<<"1/32"<<"1/16"<<"1/8"<<"1/4"<<"AUTO";
+ return list;
+}
+
+ChannelEditor::~ChannelEditor()
+{
+}
+
+#include "channeleditor.moc"
diff --git a/kaffeine/src/input/dvb/channeleditor.h b/kaffeine/src/input/dvb/channeleditor.h
new file mode 100644
index 0000000..6a3b3f8
--- /dev/null
+++ b/kaffeine/src/input/dvb/channeleditor.h
@@ -0,0 +1,70 @@
+/*
+ * channeleditor.h
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CHANNELEDITOR_H
+#define CHANNELEDITOR_H
+
+#include <qstringlist.h>
+
+#include "channeleditorui.h"
+#include "channeldesc.h"
+
+class ChannelEditor : public ChannelEditorUI
+{
+ Q_OBJECT
+
+public:
+
+ ChannelEditor( QStringList src, bool m, ChannelDesc *chan, QPtrList<ChannelDesc> *cdesc, QWidget *parent );
+ ~ChannelEditor();
+
+protected:
+
+ virtual void accept();
+
+private slots:
+
+ void editAudio();
+ void editSubtitle();
+
+private:
+
+ void initS();
+ void initC();
+ void initT();
+ void initA();
+ QStringList inversionList();
+ QStringList coderateList();
+ QStringList modulationList();
+ QStringList modulationListAtsc();
+ QStringList transmissionList();
+ QStringList bandwidthList();
+ QStringList hierarchyList();
+ QStringList guardList();
+
+ ChannelDesc *channel;
+ QPtrList<ChannelDesc> *chandesc;
+ bool mode;
+ QString orgName;
+ int chanNum;
+
+};
+
+#endif /* CHANNELEDITOR_H */
diff --git a/kaffeine/src/input/dvb/channeleditorui.ui b/kaffeine/src/input/dvb/channeleditorui.ui
new file mode 100644
index 0000000..5b75f18
--- /dev/null
+++ b/kaffeine/src/input/dvb/channeleditorui.ui
@@ -0,0 +1,704 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ChannelEditorUI</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ChannelEditorUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>477</width>
+ <height>533</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Channel Editor</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="Line" row="1" column="0">
+ <property name="name">
+ <cstring>line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_4</cstring>
+ </property>
+ <property name="text">
+ <string>Source:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>sourceComb</cstring>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>nameLe</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Nr:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>numSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>freqGroup</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>polGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Polarity</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>verticalRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Vertical</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="0" column="1">
+ <property name="name">
+ <cstring>horizontalRadio</cstring>
+ </property>
+ <property name="text">
+ <string>Horizontal</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Frequency:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Symbol rate:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>srSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>freqSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>999999</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ftaCb</cstring>
+ </property>
+ <property name="text">
+ <string>Scrambled</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>pidsGroup</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>tsidSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="4" column="1">
+ <property name="name">
+ <cstring>ttpidSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>8191</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel12</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Service ID:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>Network ID:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel15</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Teletext PID:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="1">
+ <property name="name">
+ <cstring>vpidSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>8191</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="2" column="1">
+ <property name="name">
+ <cstring>sidSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>nidSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>65535</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel13</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Video PID:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Transport stream ID:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>subpidBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Subtitle PIDs...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>apidBtn</cstring>
+ </property>
+ <property name="focusPolicy">
+ <enum>TabFocus</enum>
+ </property>
+ <property name="text">
+ <string>Audio PIDs...</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>extendedGroup</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>transmissionComb</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel11</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Bandwidth:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel10</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>FEC high:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel8</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Transmission:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>bandwidthComb</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <property name="name">
+ <cstring>coderateHComb</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>coderateLComb</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel9</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>FEC low:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="3">
+ <property name="name">
+ <cstring>guardComb</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="2">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Guard interval:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="3">
+ <property name="name">
+ <cstring>hierarchyComb</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="2">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Hierarchy:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="2">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Modulation:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="3">
+ <property name="name">
+ <cstring>modulationComb</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="3">
+ <property name="name">
+ <cstring>inversionComb</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Inversion:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>98</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout14</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>150</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>ChannelEditorUI</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>ChannelEditorUI</receiver>
+ <slot>reject()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>nameLe</tabstop>
+ <tabstop>numSpin</tabstop>
+ <tabstop>freqSpin</tabstop>
+ <tabstop>srSpin</tabstop>
+ <tabstop>verticalRadio</tabstop>
+ <tabstop>horizontalRadio</tabstop>
+ <tabstop>ftaCb</tabstop>
+ <tabstop>tsidSpin</tabstop>
+ <tabstop>sidSpin</tabstop>
+ <tabstop>vpidSpin</tabstop>
+ <tabstop>ttpidSpin</tabstop>
+ <tabstop>apidBtn</tabstop>
+ <tabstop>transmissionComb</tabstop>
+ <tabstop>coderateLComb</tabstop>
+ <tabstop>coderateHComb</tabstop>
+ <tabstop>bandwidthComb</tabstop>
+ <tabstop>inversionComb</tabstop>
+ <tabstop>modulationComb</tabstop>
+ <tabstop>hierarchyComb</tabstop>
+ <tabstop>guardComb</tabstop>
+ <tabstop>cancelBtn</tabstop>
+ <tabstop>okBtn</tabstop>
+ <tabstop>sourceComb</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kaffeine/src/input/dvb/cleaner.cpp b/kaffeine/src/input/dvb/cleaner.cpp
new file mode 100644
index 0000000..8214bc9
--- /dev/null
+++ b/kaffeine/src/input/dvb/cleaner.cpp
@@ -0,0 +1,82 @@
+/*
+ * cleaner.cpp
+ *
+ * Copyright (C) 2005-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <sys/statvfs.h>
+
+#include <qdir.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <qfileinfo.h>
+
+#include "cleaner.h"
+
+Cleaner::Cleaner( const QString &lpath, const QString &rpath )
+{
+ setPaths( lpath, rpath );
+
+ connect( &timer, SIGNAL(timeout()), this, SLOT(doClean()) );
+ timer.start( 60*1000 );
+}
+
+Cleaner::~Cleaner()
+{
+ wait();
+}
+
+void Cleaner::doClean()
+{
+ start(IdlePriority);
+}
+
+void Cleaner::setPaths( const QString &lpath, const QString &rpath )
+{
+ livePath = lpath;
+ recordPath = rpath;
+}
+
+void Cleaner::run()
+{
+ QStringList list;
+ QDir d;
+ double freemb;
+ struct statvfs buf;
+
+ d.setPath( livePath );
+ list = d.entryList( "DVBLive-*", QDir::Files, QDir::Name );
+ if ( list.count()>1 ) d.remove( list[0] );
+
+
+ if ( statvfs( recordPath.local8Bit(), &buf ) ) {
+ fprintf(stderr,"Couldn't get file system statistics\n");
+ return;
+ }
+
+ freemb = (double)(((double)(buf.f_bavail)*(double)(buf.f_bsize))/(1024.0*1024.0));
+ if ( freemb<1000 ) {
+ d.setPath( recordPath );
+ const QFileInfoList *infos = d.entryInfoList( "*.m2t", QDir::Files|QDir::NoSymLinks|QDir::Writable, QDir::Time|QDir::Reversed );
+ QFileInfoListIterator it( *infos );
+ QFileInfo *i;
+ /*if ( ( i=it.current() )!=0 )
+ d.remove( i->absFilePath() );*/
+ }
+}
+
+#include "cleaner.moc"
diff --git a/kaffeine/src/input/dvb/cleaner.h b/kaffeine/src/input/dvb/cleaner.h
new file mode 100644
index 0000000..215af32
--- /dev/null
+++ b/kaffeine/src/input/dvb/cleaner.h
@@ -0,0 +1,54 @@
+/*
+ * cleaner.h
+ *
+ * Copyright (C) 2005-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CLEANER_H
+#define CLEANER_H
+
+#include <qobject.h>
+#include <qthread.h>
+#include <qstring.h>
+#include <qtimer.h>
+
+class Cleaner : public QObject, public QThread
+{
+
+ Q_OBJECT
+
+public:
+
+ Cleaner( const QString &lpath, const QString &rpath );
+ ~Cleaner();
+ void setPaths( const QString &lpath, const QString &rpath );
+
+protected:
+
+ virtual void run();
+
+private slots:
+
+ void doClean();
+
+private:
+
+ QTimer timer;
+ QString livePath, recordPath;
+};
+
+#endif /* CLEANER_H */
diff --git a/kaffeine/src/input/dvb/crontimer.cpp b/kaffeine/src/input/dvb/crontimer.cpp
new file mode 100644
index 0000000..00078ea
--- /dev/null
+++ b/kaffeine/src/input/dvb/crontimer.cpp
@@ -0,0 +1,109 @@
+/*
+ * crontimer.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kpushbutton.h>
+
+#include "crontimer.h"
+
+CronTimer::CronTimer( int m, QWidget *parent ) : CronTimerUI( parent )
+{
+ connect( cronBtnGrp, SIGNAL(clicked(int)), this, SLOT(modeSelected(int)) );
+ mode = m;
+ switch ( mode ) {
+ case Noone : cronBtnGrp->setButton( 0 ); break;
+ case Daily : cronBtnGrp->setButton( 1 ); break;
+ case Weekly : cronBtnGrp->setButton( 2 ); break;
+ case Monthly : cronBtnGrp->setButton( 3 ); break;
+ default : cronBtnGrp->setButton( 4 );
+ }
+ if ( mode>Monthly ) {
+ daysGb->setEnabled( true );
+ if ( mode&Monday ) monCb->setChecked( true );
+ if ( mode&Tuesday ) tueCb->setChecked( true );
+ if ( mode&Wednesday ) wedCb->setChecked( true );
+ if ( mode&Thursday ) thuCb->setChecked( true );
+ if ( mode&Friday ) friCb->setChecked( true );
+ if ( mode&Saturday ) satCb->setChecked( true );
+ if ( mode&Sunday ) sunCb->setChecked( true );
+ }
+ else
+ daysGb->setEnabled( false );
+
+ KIconLoader *icon = new KIconLoader();
+ cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", KIcon::Small) ) );
+ okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", KIcon::Small) ) );
+ delete icon;
+}
+
+
+
+CronTimer::~CronTimer()
+{
+}
+
+
+
+int CronTimer::getMode() const
+{
+ return mode;
+}
+
+
+
+void CronTimer::modeSelected( int id )
+{
+ if ( id==4 )
+ daysGb->setEnabled( true );
+ else
+ daysGb->setEnabled( false );
+}
+
+
+
+void CronTimer::accept()
+{
+ switch ( cronBtnGrp->selectedId() ) {
+ case 0 : mode = Noone; break;
+ case 1 : mode = Daily; break;
+ case 2 : mode = Weekly; break;
+ case 3 : mode = Monthly; break;
+ case 4 : {
+ mode = Custom;
+ if ( monCb->isChecked() ) mode+=Monday;
+ if ( tueCb->isChecked() ) mode+=Tuesday;
+ if ( wedCb->isChecked() ) mode+=Wednesday;
+ if ( thuCb->isChecked() ) mode+=Thursday;
+ if ( friCb->isChecked() ) mode+=Friday;
+ if ( satCb->isChecked() ) mode+=Saturday;
+ if ( sunCb->isChecked() ) mode+=Sunday;
+ if ( mode<Monday ) {
+ KMessageBox::sorry( this, i18n("You have to choose some days.") );
+ return;
+ }
+ }
+ }
+
+ done( Accepted );
+}
+
+#include "crontimer.moc"
diff --git a/kaffeine/src/input/dvb/crontimer.h b/kaffeine/src/input/dvb/crontimer.h
new file mode 100644
index 0000000..bb079bd
--- /dev/null
+++ b/kaffeine/src/input/dvb/crontimer.h
@@ -0,0 +1,58 @@
+/*
+ * crontimer.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CRONTIMER_H
+#define CRONTIMER_H
+
+#include <qwidget.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+
+#include "crontimerui.h"
+
+class CronTimer : public CronTimerUI
+{
+
+ Q_OBJECT
+
+public:
+
+ CronTimer( int m, QWidget *parent );
+ ~CronTimer();
+ int getMode() const;
+
+ enum Type { Noone=0, Daily=1, Weekly=2, Monthly=4, Custom=8, Monday=16, Tuesday=32, Wednesday=64, Thursday=128, Friday=256, Saturday=512, Sunday=1024 };
+
+protected:
+
+ virtual void accept();
+
+private slots:
+
+ void modeSelected( int id );
+
+private:
+
+ int mode;
+
+};
+
+#endif /* CRONTIMER_H */
diff --git a/kaffeine/src/input/dvb/crontimerui.ui b/kaffeine/src/input/dvb/crontimerui.ui
new file mode 100644
index 0000000..1a70361
--- /dev/null
+++ b/kaffeine/src/input/dvb/crontimerui.ui
@@ -0,0 +1,354 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>CronTimerUI</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>CronTimerUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>317</width>
+ <height>288</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Repeated Timer</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>32</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>cronBtnGrp</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>noneRad</cstring>
+ </property>
+ <property name="text">
+ <string>None</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>dailyRad</cstring>
+ </property>
+ <property name="text">
+ <string>Daily</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>weeklyRad</cstring>
+ </property>
+ <property name="text">
+ <string>Weekly</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>mnthlyRad</cstring>
+ </property>
+ <property name="text">
+ <string>Monthly</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>3</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>customRad</cstring>
+ </property>
+ <property name="text">
+ <string>Custom</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>4</number>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>67</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>39</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>daysGb</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>monCb</cstring>
+ </property>
+ <property name="text">
+ <string>Monday</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>tueCb</cstring>
+ </property>
+ <property name="text">
+ <string>Tuesday</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>wedCb</cstring>
+ </property>
+ <property name="text">
+ <string>Wednesday</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>thuCb</cstring>
+ </property>
+ <property name="text">
+ <string>Thursday</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>friCb</cstring>
+ </property>
+ <property name="text">
+ <string>Friday</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>satCb</cstring>
+ </property>
+ <property name="text">
+ <string>Saturday</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>sunCb</cstring>
+ </property>
+ <property name="text">
+ <string>Sunday</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>32</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>95</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton" row="1" column="0">
+ <property name="name">
+ <cstring>cancelBtn</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="1" column="1">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>177</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="Line" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="KPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>cancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>CronTimerUI</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>CronTimerUI</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kaffeine/src/input/dvb/dvbcam.cpp b/kaffeine/src/input/dvb/dvbcam.cpp
new file mode 100644
index 0000000..1cb5b86
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbcam.cpp
@@ -0,0 +1,926 @@
+/*
+ * dvbcam.cpp
+ *
+ * Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com>
+ *
+ * code based on ca_zap (LGPL)
+ * Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ * Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <linux/dvb/ca.h>
+
+#include <libdvbapi/dvbca.h>
+#include <libdvbapi/dvbdemux.h>
+#include <libdvben50221/en50221_app_ai.h>
+#include <libdvben50221/en50221_app_ca.h>
+#include <libdvben50221/en50221_app_rm.h>
+#include <libdvben50221/en50221_app_tags.h>
+#include <libdvben50221/en50221_session.h>
+#include <libucsi/mpeg/section.h>
+
+#include <qthread.h>
+#include <qstring.h>
+
+#include "dvbcam.h"
+
+class DvbCamCamHandler
+{
+public:
+ virtual ~DvbCamCamHandler();
+
+ bool init();
+
+ virtual void poll() = 0;
+ virtual bool registerCam(int ca_fd, uint8_t slot) = 0;
+
+ bool sendPmt(char *pmt_buffer, int size);
+
+protected:
+ DvbCamCamHandler();
+
+ static int infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids);
+
+ virtual bool sub_init() = 0;
+
+ void *AiResource;
+ void *CaResource;
+ en50221_app_send_functions SendFuncs;
+
+ volatile int SessionNumber;
+};
+
+class DvbCamCamThread : protected QThread
+{
+public:
+ DvbCamCamThread(int adapter, int ca_device, int ci_type);
+ ~DvbCamCamThread();
+
+ void start();
+ void stop();
+ void wait();
+
+ bool processPmt(int demux_fd);
+
+private:
+ void run();
+
+ int Adapter;
+ int CaDevice;
+ int ciType;
+
+ DvbCamCamHandler *CamHandler;
+
+ char PmtBuffer[4096]; // we imply that processPmt is only once called
+
+ volatile int PmtSize; // PmtSize <= 0 means PmtBuffer invalid
+ volatile bool Stopped;
+};
+
+class DvbCamPmtThread : protected QThread
+{
+public:
+ DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id);
+ ~DvbCamPmtThread();
+
+ void start();
+ void stop();
+ void wait();
+
+private:
+ int createSectionFilter(uint16_t pid, uint8_t table_id);
+ int processPat(int demux_fd);
+ void run();
+
+ DvbCamCamThread *CamThread;
+ int Adapter;
+ int DemuxDevice;
+ int ServiceId;
+
+ volatile bool Stopped;
+};
+
+class DvbCamCamHandlerLLCI : public DvbCamCamHandler
+{
+public:
+ DvbCamCamHandlerLLCI();
+ ~DvbCamCamHandlerLLCI();
+
+private:
+ struct SlResource
+ {
+ en50221_app_public_resource_id resid;
+ uint32_t binary_resource_id;
+ en50221_sl_resource_callback callback;
+ void *arg;
+ };
+
+ static int llci_rm_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number);
+ static int llci_rm_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *resource_ids);
+ static int llci_rm_changed_callback(void *arg, uint8_t slot_id, uint16_t session_number);
+ static int llci_lookup_callback(void *arg, uint8_t slot_id, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id);
+ static int llci_session_callback(void *arg, int reason, uint8_t slot_id, uint16_t session_number, uint32_t resource_id);
+
+ void poll();
+ bool registerCam(int ca_fd, uint8_t slot);
+ bool sub_init();
+
+ void *RmResource;
+ void *SessionLayer;
+ void *TransportLayer;
+
+ SlResource Resources[3];
+};
+
+class DvbCamCamHandlerHLCI : public DvbCamCamHandler
+{
+public:
+ DvbCamCamHandlerHLCI();
+ ~DvbCamCamHandlerHLCI();
+
+private:
+ static int hlci_send_data(void *arg, uint16_t session_number, uint8_t *data, uint16_t data_length);
+ static int hlci_send_datav(void *arg, uint16_t session_number, iovec *vector, int iov_count);
+
+ void poll();
+ bool registerCam(int ca_fd, uint8_t slot);
+ bool sub_init();
+};
+
+// class DvbCam
+
+DvbCam::DvbCam(int adapter, int ca_device, int demux_device, int ci_type)
+{
+ Adapter = adapter;
+ CaDevice = ca_device;
+ DemuxDevice = demux_device;
+ ciType = ci_type;
+
+ isRunning = false;
+
+ CamThread = NULL;
+ PmtThread = NULL;
+
+ // at that time, we do reset in cam_thread
+ /*if ( ciType!=CA_CI ) { //do not reset HLCI
+ int ca_fd = dvbca_open( Adapter, CaDevice );
+ if(ca_fd < 0) // should not happen
+ fprintf(stderr, "CamThread: [error] opening ca device failed\n");
+ else {
+ if(dvbca_reset(ca_fd, 0))
+ fprintf(stderr, "CamThread: [error] resetting cam slot failed\n");
+ close(ca_fd);
+ }
+ }*/
+}
+
+DvbCam::~DvbCam()
+{
+ stop();
+}
+
+int DvbCam::probe( int adapter, int ca_device )
+{
+ int fdCa;
+ ca_caps_t cap;
+ ca_slot_info_t info;
+ QString s = QString("/dev/dvb/adapter%1/ca%2").arg( adapter ).arg( ca_device );
+
+ if ( (fdCa = open( s.ascii(), O_RDWR )) < 0) {
+ fprintf(stderr, "DvbCam::probe(): %s:", s.ascii());
+ perror(" ");
+ return -1;
+ }
+
+ if ( ioctl(fdCa, CA_GET_CAP, &cap) == 0) {
+ if ( cap.slot_num>0 ) {
+ info.num = 0;
+ if ( ioctl(fdCa, CA_GET_SLOT_INFO, &info) == 0) {
+ if ( (info.type & CA_CI_LINK)!=0) {
+ fprintf(stderr, "DvbCam::probe(): LLCI slot found on %s\n", s.ascii());
+ if ( (info.flags & CA_CI_MODULE_PRESENT)!=0 ) {
+ fprintf(stderr, "DvbCam::probe(): CA module present on %s\n", s.ascii());
+ close (fdCa);
+ return CA_CI_LINK;
+ }
+ else
+ fprintf(stderr, "DvbCam::probe(): no CA module present on %s\n", s.ascii());
+ }
+ else if ( (info.type & CA_CI)!=0 ) {
+ fprintf(stderr, "DvbCam::probe(): HLCI slot found on %s\n", s.ascii());
+ if ( (info.flags & CA_CI_MODULE_PRESENT)!=0 ) {
+ fprintf(stderr, "DvbCam::probe(): CA module present on %s\n", s.ascii());
+ close (fdCa);
+ return CA_CI;
+ }
+ else
+ fprintf(stderr, "DvbCam::probe(): no CA module present on %s\n", s.ascii());
+ }
+ else
+ fprintf(stderr, "DvbCam::probe(): unsupported CI interface on %s\n", s.ascii());
+ }
+ else
+ fprintf(stderr, "DvbCam::Probe(): ioctl failed on %s\n", s.ascii());
+ }
+ else
+ fprintf(stderr, "DvbCam::Probe(): no CI slot found on %s\n", s.ascii());
+ }
+ else
+ fprintf(stderr, "DvbCam::Probe(): ioctl failed on %s\n", s.ascii());
+
+ close (fdCa);
+ return -1;
+}
+
+void DvbCam::restart(int service_id)
+{
+ stop();
+
+ isRunning = true;
+ sid = service_id;
+
+ CamThread = new DvbCamCamThread(Adapter, CaDevice, ciType);
+ CamThread->start();
+
+ PmtThread = new DvbCamPmtThread(CamThread, Adapter, DemuxDevice, service_id);
+ PmtThread->start();
+}
+
+void DvbCam::stop()
+{
+ if(PmtThread != NULL) {
+ PmtThread->stop();
+ }
+ if(CamThread != NULL) {
+ CamThread->stop();
+ }
+ if(PmtThread != NULL) {
+ PmtThread->wait();
+ delete PmtThread;
+ PmtThread = NULL;
+ }
+ if(CamThread != NULL) {
+ CamThread->wait();
+ delete CamThread; // be careful about deletion: PmtThread uses CamThread internally
+ CamThread = NULL;
+ }
+ isRunning = false;
+}
+
+// class DvbCamCamThread
+
+DvbCamCamThread::DvbCamCamThread(int adapter, int ca_device, int ci_type)
+{
+ Adapter = adapter;
+ CaDevice = ca_device;
+ ciType = ci_type;
+
+ CamHandler = NULL;
+}
+
+DvbCamCamThread::~DvbCamCamThread()
+{
+ wait(); // should never be necessary
+}
+
+void DvbCamCamThread::start()
+{
+ PmtSize = 0;
+ Stopped = false;
+ QThread::start();
+}
+
+void DvbCamCamThread::stop()
+{
+ Stopped = true;
+}
+
+void DvbCamCamThread::wait()
+{
+ QThread::wait();
+}
+
+bool DvbCamCamThread::processPmt(int demux_fd)
+{
+ // read section
+ char si_buf[4096];
+ int size = read(demux_fd, si_buf, sizeof(si_buf));
+ if(size <= 0) {
+ return false;
+ }
+
+ // parse section
+ section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size);
+ if(parsed_section == NULL) {
+ return false;
+ }
+
+ // parse section_ext
+ section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on
+ if(parsed_section_ext == NULL) {
+ return false;
+ }
+
+ // parse pmt
+ mpeg_pmt_section *parsed_pmt = mpeg_pmt_section_codec(parsed_section_ext);
+ if(parsed_pmt == NULL) {
+ return false;
+ }
+
+ // translate it into a cam pmt
+ PmtSize = en50221_ca_format_pmt(parsed_pmt, reinterpret_cast<unsigned char *> (PmtBuffer), sizeof(PmtBuffer), 0, CA_LIST_MANAGEMENT_ONLY, CA_PMT_CMD_ID_OK_DESCRAMBLING);
+ if(PmtSize <= 0) {
+ return false;
+ }
+
+ // the DvbCamCamThread will send it to the cam
+ return true;
+}
+
+void DvbCamCamThread::run()
+{
+ fprintf(stderr, "CamThread: started\n");
+
+ int ca_fd = dvbca_open(Adapter, CaDevice);
+ if(ca_fd < 0) {
+ fprintf(stderr, "CamThread: [error] opening ca device failed\n");
+ return;
+ }
+
+ fprintf(stderr, "CamThread: just using the first cam slot\n");
+
+ if ( ciType!=CA_CI ) { // do not reset HLCI
+ if(dvbca_reset(ca_fd, 0)) {
+ fprintf(stderr, "CamThread: [error] resetting cam slot failed\n");
+ close(ca_fd);
+ return;
+ }
+ }
+
+ while(!Stopped) {
+ bool cam_ready = false;
+ switch(dvbca_get_cam_state(ca_fd, 0)) {
+ case DVBCA_CAMSTATE_MISSING: {
+ /*fprintf(stderr, "CamThread: [error] no cam detected\n");
+ close(ca_fd);
+ return; */ // FIXME: find a more reliable solution
+ break;
+ }
+ case DVBCA_CAMSTATE_READY: {
+ fprintf(stderr, "CamThread: cam 0 is ready\n");
+ cam_ready = true;
+ break;
+ }
+ case DVBCA_CAMSTATE_INITIALISING: {
+ if ( ciType==CA_CI ) { // workaround needed for hlci
+ fprintf(stderr, "CamThread: cam 0 is ready [hlci workaround]\n");
+ cam_ready = true;
+ }
+ break;
+ }
+ default: {
+ fprintf(stderr, "CamThread: [error] querying the cam state failed\n");
+ close(ca_fd);
+ return;
+ }
+ }
+ if(cam_ready) {
+ break;
+ }
+ usleep(100000); // 100 ms
+ }
+
+ if(!Stopped) {
+ switch(dvbca_get_interface_type(ca_fd, 0)) {
+ case DVBCA_INTERFACE_LINK: {
+ fprintf(stderr, "CamThread: LLCI cam slot detected\n");
+ CamHandler = new DvbCamCamHandlerLLCI();
+ break;
+ }
+ case DVBCA_INTERFACE_HLCI: {
+ fprintf(stderr, "CamThread: HLCI cam slot detected\n");
+ CamHandler = new DvbCamCamHandlerHLCI();
+ break;
+ }
+ default: {
+ fprintf(stderr, "CamThread: [error] unknown cam slot type\n");
+ close(ca_fd);
+ return;
+ }
+ }
+ }
+
+ if(!Stopped) {
+ if(!CamHandler->init()) {
+ fprintf(stderr, "CamThread: [error] cam slot initialization failed\n");
+ delete CamHandler;
+ CamHandler = NULL;
+ close(ca_fd);
+ return;
+ }
+ }
+
+ if(!Stopped) {
+ if(!CamHandler->registerCam(ca_fd, 0)) {
+ fprintf(stderr, "CamThread: [error] registering cam 0 failed\n");
+ delete CamHandler;
+ CamHandler = NULL;
+ close(ca_fd);
+ return;
+ }
+ }
+
+ while(!Stopped) {
+ CamHandler->poll();
+ if(PmtSize > 0) {
+ if(CamHandler->sendPmt(PmtBuffer, PmtSize)) {
+ fprintf(stderr, "CamThread: pmt sent to cam\n");
+ PmtSize = 0;
+ }
+ }
+ }
+
+ fprintf(stderr, "CamThread: stopping requested\n");
+
+ delete CamHandler;
+ CamHandler = NULL;
+ close(ca_fd);
+
+ fprintf(stderr, "CamThread: stopped\n");
+ return;
+}
+
+// class DvbCamPmtThread
+
+DvbCamPmtThread::DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id)
+{
+ CamThread = cam_thread;
+ Adapter = adapter;
+ DemuxDevice = demux_device;
+ ServiceId = service_id;
+}
+
+DvbCamPmtThread::~DvbCamPmtThread()
+{
+ wait(); // should never be necessary
+}
+
+void DvbCamPmtThread::start()
+{
+ Stopped = false;
+ QThread::start();
+}
+
+void DvbCamPmtThread::stop()
+{
+ Stopped = true;
+}
+
+void DvbCamPmtThread::wait()
+{
+ QThread::wait();
+}
+
+int DvbCamPmtThread::createSectionFilter(uint16_t pid, uint8_t table_id)
+{
+ // open the demuxer
+ int demux_fd = dvbdemux_open_demux(Adapter, DemuxDevice, 0);
+ if(demux_fd < 0) {
+ return -1;
+ }
+
+ // create a section filter
+ uint8_t filter[18] = {table_id};
+ uint8_t mask[18] = {0xff};
+ if(dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) { // crc check on
+ close(demux_fd);
+ return -1;
+ }
+
+ return demux_fd;
+}
+
+int DvbCamPmtThread::processPat(int demux_fd)
+{
+ // read section
+ char si_buf[4096];
+ int size = read(demux_fd, si_buf, sizeof(si_buf));
+ if(size < 0) {
+ return -1;
+ }
+
+ // parse section
+ section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size);
+ if(parsed_section == NULL) {
+ return -1;
+ }
+
+ // parse section_ext
+ section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on
+ if(parsed_section_ext == NULL) {
+ return -1;
+ }
+
+ // parse pat
+ mpeg_pat_section *parsed_pat = mpeg_pat_section_codec(parsed_section_ext);
+ if(parsed_pat == NULL) {
+ return -1;
+ }
+
+ // try and find the requested program
+ mpeg_pat_program *cur_program;
+ mpeg_pat_section_programs_for_each(parsed_pat, cur_program) {
+ if(cur_program->program_number == ServiceId) {
+ return cur_program->pid;
+ }
+ }
+
+ fprintf(stderr, "PmtThread: [warning] the requested service id couldn't be found\n");
+
+ return -1;
+}
+
+void DvbCamPmtThread::run()
+{
+ fprintf(stderr, "PmtThread: started\n");
+
+ int demux_fd = createSectionFilter(TRANSPORT_PAT_PID, stag_mpeg_program_association);
+ if(demux_fd < 0) {
+ fprintf(stderr, "PmtThread: [error] opening demux device failed\n");
+ return;
+ }
+
+ pollfd poll_desc;
+ poll_desc.fd = demux_fd;
+ poll_desc.events = POLLIN | POLLPRI;
+ while(!Stopped) {
+ int ret = poll(&poll_desc, 1, 100); // 100 ms
+ if(ret < 0) {
+ fprintf(stderr, "PmtThread: [error] polling demux device failed\n");
+ close(demux_fd);
+ return;
+ }
+ if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) {
+ int processed_pat = processPat(demux_fd);
+ if(processed_pat >= 0) {
+ close(demux_fd);
+ demux_fd = createSectionFilter(processed_pat, stag_mpeg_program_map);
+ if(demux_fd < 0) {
+ fprintf(stderr, "PmtThread: [error] opening demux device failed\n");
+ return;
+ }
+ poll_desc.fd = demux_fd;
+ break;
+ }
+ }
+ }
+
+ while(!Stopped) {
+ int ret = poll(&poll_desc, 1, 100); // 100 ms
+ if(ret < 0) {
+ fprintf(stderr, "PmtThread: [error] polling demux device failed\n");
+ close(demux_fd);
+ return;
+ }
+ if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) {
+ if(CamThread->processPmt(demux_fd)) {
+ fprintf(stderr, "PmtThread: new pmt received\n");
+ close(demux_fd);
+ fprintf(stderr, "PmtThread: stopped\n");
+ return;
+ }
+ }
+ }
+
+ fprintf(stderr, "PmtThread: stopping requested\n");
+
+ close(demux_fd);
+
+ fprintf(stderr, "PmtThread: stopped\n");
+ return;
+}
+
+// class DvbCamCamHandler
+
+DvbCamCamHandler::DvbCamCamHandler()
+{
+ AiResource = NULL;
+ CaResource = NULL;
+
+ SessionNumber = -1;
+}
+
+DvbCamCamHandler::~DvbCamCamHandler()
+{
+ if(CaResource != NULL) {
+ en50221_app_ca_destroy(CaResource);
+ CaResource = NULL;
+ }
+ if(AiResource != NULL) {
+ en50221_app_ai_destroy(AiResource);
+ AiResource = NULL;
+ }
+}
+
+bool DvbCamCamHandler::init()
+{
+ AiResource = en50221_app_ai_create(&SendFuncs);
+ CaResource = en50221_app_ca_create(&SendFuncs);
+
+ if(CaResource != NULL) {
+ en50221_app_ca_register_info_callback(CaResource, infoCallback, this);
+ }
+
+ return sub_init();
+}
+
+bool DvbCamCamHandler::sendPmt(char *pmt_buffer, int size)
+{
+ if((CaResource != NULL) && (SessionNumber >= 0)) {
+ if(!en50221_app_ca_pmt(CaResource, SessionNumber, reinterpret_cast<unsigned char *> (pmt_buffer), size)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int DvbCamCamHandler::infoCallback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*ca_id_count*/, uint16_t */*ca_ids*/)
+{
+ (static_cast<DvbCamCamHandler *> (arg))->SessionNumber = session_number;
+ return 0;
+}
+
+// class DvbCamCamHandlerLLCI
+
+#define MAX_CARDS 1
+#define MAX_TC 16
+#define MAX_SESSIONS 16
+
+DvbCamCamHandlerLLCI::DvbCamCamHandlerLLCI()
+{
+ RmResource = NULL;
+ SessionLayer = NULL;
+ TransportLayer = NULL;
+}
+
+DvbCamCamHandlerLLCI::~DvbCamCamHandlerLLCI()
+{
+ if(SessionLayer != NULL) {
+ en50221_sl_destroy(SessionLayer);
+ SessionLayer = NULL;
+ }
+ if(TransportLayer != NULL) {
+ en50221_tl_destroy(TransportLayer);
+ TransportLayer = NULL;
+ }
+ if(RmResource != NULL) {
+ en50221_app_rm_destroy(RmResource);
+ RmResource = NULL;
+ }
+}
+
+int DvbCamCamHandlerLLCI::llci_rm_enq_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number)
+{
+ uint32_t resource_ids[] = {EN50221_APP_RM_RESOURCEID, EN50221_APP_AI_RESOURCEID, EN50221_APP_CA_RESOURCEID};
+ en50221_app_rm_reply(arg, session_number, sizeof(resource_ids) / 4, resource_ids);
+ return 0;
+}
+
+int DvbCamCamHandlerLLCI::llci_rm_reply_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*resource_id_count*/, uint32_t */*resource_ids*/)
+{
+ en50221_app_rm_changed(arg, session_number);
+ return 0;
+}
+
+int DvbCamCamHandlerLLCI::llci_rm_changed_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number)
+{
+ en50221_app_rm_enq(arg, session_number);
+ return 0;
+}
+
+int DvbCamCamHandlerLLCI::llci_lookup_callback(void *arg, uint8_t /*slot_id*/, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id)
+{
+ // decode the resource id
+ en50221_app_public_resource_id resid;
+ if(!en50221_app_decode_public_resource_id(&resid, requested_resource_id)) {
+ return -1;
+ }
+
+ // try and find an instance of the resource
+ const SlResource *Resources = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources;
+ int i;
+ for(i = 0; i < 3; ++i) {
+ if((resid.resource_class == Resources[i].resid.resource_class) && (resid.resource_type == Resources[i].resid.resource_type)) {
+ *callback_out = Resources[i].callback;
+ *arg_out = Resources[i].arg;
+ *connected_resource_id = Resources[i].binary_resource_id;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int DvbCamCamHandlerLLCI::llci_session_callback(void *arg, int reason, uint8_t /*slot_id*/, uint16_t session_number, uint32_t resource_id)
+{
+ if(reason == S_SCALLBACK_REASON_CAMCONNECTED) {
+ if(resource_id == EN50221_APP_RM_RESOURCEID) {
+ void *RmResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[0].arg;
+ en50221_app_rm_enq(RmResource, session_number);
+ }
+ else if(resource_id == EN50221_APP_AI_RESOURCEID) {
+ void *AiResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[1].arg;
+ en50221_app_ai_enquiry(AiResource, session_number);
+ }
+ else if(resource_id == EN50221_APP_CA_RESOURCEID) {
+ void *CaResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[2].arg;
+ en50221_app_ca_info_enq(CaResource, session_number);
+ }
+ }
+ return 0;
+}
+
+void DvbCamCamHandlerLLCI::poll()
+{
+ if(en50221_tl_poll(TransportLayer)) {
+ fprintf(stderr, "CamThread: [warning] polling the stack failed\n");
+ usleep(10000); // wait 10 ms to not block
+ }
+}
+
+bool DvbCamCamHandlerLLCI::registerCam(int ca_fd, uint8_t slot)
+{
+ // register the slot
+ int slot_id = en50221_tl_register_slot(TransportLayer, ca_fd, slot, 1000, 100);
+ if(slot_id < 0) {
+ return false;
+ }
+
+ // create a new connection on the slot
+ if(en50221_tl_new_tc(TransportLayer, slot_id) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+bool DvbCamCamHandlerLLCI::sub_init()
+{
+ // create transport layer
+ TransportLayer = en50221_tl_create(MAX_CARDS, MAX_TC);
+ if(TransportLayer == NULL) {
+ return false;
+ }
+
+ // create session layer
+ SessionLayer = en50221_sl_create(TransportLayer, MAX_SESSIONS);
+ if(SessionLayer == NULL) {
+ en50221_tl_destroy(TransportLayer);
+ TransportLayer = NULL;
+ return false;
+ }
+
+ // create sendfuncs
+ SendFuncs.arg = SessionLayer;
+ SendFuncs.send_data = en50221_sl_send_data;
+ SendFuncs.send_datav = en50221_sl_send_datav;
+
+ // create the resource manager resource
+ RmResource = en50221_app_rm_create(&SendFuncs);
+ en50221_app_decode_public_resource_id(&Resources[0].resid, EN50221_APP_RM_RESOURCEID);
+ Resources[0].binary_resource_id = EN50221_APP_RM_RESOURCEID;
+ Resources[0].callback = en50221_app_rm_message;
+ Resources[0].arg = RmResource;
+ en50221_app_rm_register_enq_callback(RmResource, llci_rm_enq_callback, RmResource);
+ en50221_app_rm_register_reply_callback(RmResource, llci_rm_reply_callback, RmResource);
+ en50221_app_rm_register_changed_callback(RmResource, llci_rm_changed_callback, RmResource);
+
+ // integrate the application information resource
+ en50221_app_decode_public_resource_id(&Resources[1].resid, EN50221_APP_AI_RESOURCEID);
+ Resources[1].binary_resource_id = EN50221_APP_AI_RESOURCEID;
+ Resources[1].callback = en50221_app_ai_message;
+ Resources[1].arg = AiResource;
+
+ // integrate the ca resource
+ en50221_app_decode_public_resource_id(&Resources[2].resid, EN50221_APP_CA_RESOURCEID);
+ Resources[2].binary_resource_id = EN50221_APP_CA_RESOURCEID;
+ Resources[2].callback = en50221_app_ca_message;
+ Resources[2].arg = CaResource;
+
+ // register session layer callbacks
+ en50221_sl_register_lookup_callback(SessionLayer, llci_lookup_callback, this);
+ en50221_sl_register_session_callback(SessionLayer, llci_session_callback, this);
+
+ return true;
+}
+
+// class DvbCamCamHandlerHLCI
+
+DvbCamCamHandlerHLCI::DvbCamCamHandlerHLCI()
+{
+}
+
+DvbCamCamHandlerHLCI::~DvbCamCamHandlerHLCI()
+{
+}
+
+int DvbCamCamHandlerHLCI::hlci_send_data(void *arg, uint16_t /*session_number*/, uint8_t *data, uint16_t data_length)
+{
+ return dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), data, data_length);
+}
+
+int DvbCamCamHandlerHLCI::hlci_send_datav(void *arg, uint16_t /*session_number*/, iovec *vector, int iov_count)
+{
+ // calculate the total length of the data to send
+ uint32_t data_size = 0;
+ for(int i = 0; i < iov_count; ++i) {
+ data_size += vector[i].iov_len;
+ }
+
+ // allocate memory for it
+ uint8_t *buf = new uint8_t[data_size];
+
+ // merge the iovecs
+ uint8_t *pos = buf;
+ for(int i = 0; i < iov_count; ++i) {
+ memcpy(pos, vector[i].iov_base, vector[i].iov_len);
+ pos += vector[i].iov_len;
+ }
+
+ // send it
+ int status = dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), buf, data_size);
+ delete buf;
+ return status;
+}
+
+void DvbCamCamHandlerHLCI::poll()
+{
+ // we do nothing here for the moment
+ usleep(100000); // 100 ms
+}
+
+bool DvbCamCamHandlerHLCI::registerCam(int ca_fd, uint8_t /*slot*/)
+{
+ SendFuncs.arg = reinterpret_cast<void *> (ca_fd);
+
+ // get application information
+ if(en50221_app_ai_enquiry(AiResource, 0)) {
+ fprintf(stderr, "CamThread: [DEBUG #1]\n");
+ return false;
+ }
+
+ uint8_t buf[256];
+ int size = dvbca_hlci_read(ca_fd, TAG_APP_INFO, buf, sizeof(buf));
+ if(size <= 0) {
+ fprintf(stderr, "CamThread: [DEBUG #2]\n");
+ return false;
+ }
+
+ if(en50221_app_ai_message(AiResource, 0, 0, EN50221_APP_AI_RESOURCEID, buf, size)) {
+ fprintf(stderr, "CamThread: [DEBUG #3]\n");
+ return false;
+ }
+
+ // FIXME: try to change this soon
+ buf[0] = TAG_CA_INFO >> 16;
+ buf[1] = TAG_CA_INFO >> 8;
+ buf[2] = TAG_CA_INFO;
+ buf[3] = 0;
+ if(en50221_app_ca_message(CaResource, 0, 0, EN50221_APP_CA_RESOURCEID, buf, 4)) {
+ fprintf(stderr, "CamThread: [DEBUG #4]\n");
+ return false;
+ }
+
+ fprintf(stderr, "CamThread: [DEBUG #5]\n");
+
+ return true;
+}
+
+bool DvbCamCamHandlerHLCI::sub_init()
+{
+ // create sendfuncs
+ SendFuncs.arg = NULL;
+ SendFuncs.send_data = hlci_send_data;
+ SendFuncs.send_datav = hlci_send_datav;
+
+ return true;
+}
diff --git a/kaffeine/src/input/dvb/dvbcam.h b/kaffeine/src/input/dvb/dvbcam.h
new file mode 100644
index 0000000..47a4012
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbcam.h
@@ -0,0 +1,52 @@
+/*
+ * dvbcam.h
+ *
+ * Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBCAM_H
+#define DVBCAM_H
+
+class DvbCamCamThread;
+class DvbCamPmtThread;
+
+class DvbCam
+{
+public:
+ DvbCam(int adapter, int ca_device, int demux_device, int ci_type);
+ ~DvbCam();
+
+ void restart(int service_id);
+ void stop();
+ bool running() { return isRunning; }
+ int serviceId() { return sid; }
+
+ static int probe( int adapter, int ca_device );
+
+private:
+ int Adapter;
+ int CaDevice;
+ int DemuxDevice;
+ bool isRunning;
+ int sid;
+ int ciType;
+
+ DvbCamCamThread *CamThread;
+ DvbCamPmtThread *PmtThread;
+};
+
+#endif /* DVBCAM_H */
diff --git a/kaffeine/src/input/dvb/dvbconfig.cpp b/kaffeine/src/input/dvb/dvbconfig.cpp
new file mode 100644
index 0000000..746d745
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbconfig.cpp
@@ -0,0 +1,1478 @@
+/*
+ * dvbconfig.cpp
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <qdir.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qregexp.h>
+#include <qradiobutton.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <ktar.h>
+#include <kstandarddirs.h>
+
+#include "dvbconfig.h"
+#include "kaffeinedvbplugin.h"
+
+
+
+MSpinBox::MSpinBox( QWidget *parent, int devNum ) : QSpinBox( 1, 4, 1, parent )
+{
+ deviceNumber = devNum;
+ connect( this, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)) );
+}
+
+
+
+void MSpinBox::slotValueChanged( int value )
+{
+ emit signalValueChanged( value, deviceNumber );
+}
+
+
+
+MPushButton::MPushButton( QWidget *parent, int devNum, int lnbNum ) : KPushButton( parent )
+{
+ deviceNumber = devNum;
+ lnbNumber = lnbNum;
+ connect( this, SIGNAL(clicked()), this, SLOT(isClicked()) );
+}
+
+
+
+void MPushButton::isClicked()
+{
+ emit clicked( deviceNumber, lnbNumber );
+}
+
+
+
+MComboBox::MComboBox( QWidget *parent, int devNum, int lnbNum ) : QComboBox( parent )
+{
+ deviceNumber = devNum;
+ lnbNumber = lnbNum;
+ connect( this, SIGNAL(activated(int)), this, SLOT(isActivated(int)) );
+}
+
+
+
+void MComboBox::isActivated( int index )
+{
+ emit activated( index, deviceNumber, lnbNumber );
+}
+
+
+
+LNB::LNB()
+{
+ switchFreq = 11700;
+ loFreq = 9750;
+ hiFreq = 10600;
+ rotorType = 0;
+ speed13v = 2.5;
+ speed18v = 1.5;
+}
+
+
+
+Device::Device( int anum, int tnum, fe_type_t t, const QString &n, bool as )
+{
+ adapter = anum;
+ tuner = tnum;
+ type = t;
+ name = n;
+ source = "";
+ canAutoscan= as;
+ tuningTimeout = 1500;
+}
+
+
+
+Category::Category( const QString &tname, const QString &ticon )
+{
+ name = tname;
+ icon = ticon;
+}
+
+
+
+DVBconfig::DVBconfig( const QString &dvbConf )
+{
+ dvbConfigDir = dvbConf;
+ dvbConfigIconsDir = dvbConf+"icons/";
+ QDir dir;
+ dir.setPath( dvbConfigIconsDir );
+ if ( !dir.exists() )
+ dir.mkdir( dvbConfigIconsDir );
+ config = new KConfig( dvbConfigDir+"dvbrc" );
+ downProgress = 0;
+ sizeFile = 0;
+ categories.setAutoDelete( true );
+ devList.setAutoDelete( true );
+ startup();
+ readConfig();
+}
+
+
+
+DVBconfig::~DVBconfig()
+{
+ saveConfig();
+ delete config;
+ categories.clear();
+ devList.clear();
+}
+
+
+
+bool DVBconfig::haveDvbDevice()
+{
+ int i, j, res, fdFrontend=0;
+ struct dvb_frontend_info info;
+
+ QStringList list, flist;
+ QDir d;
+ d.setPath( "/dev/dvb/" );
+ list = d.entryList( "adapter*", QDir::Dirs, QDir::Name );
+
+ for ( i=0; i<(int)list.count(); i++ ) {
+ d.setPath( "/dev/dvb/"+list[i]+"/" );
+ flist = d.entryList( "frontend*", QDir::System, QDir::Name );
+ for ( j=0; j<(int)flist.count(); j++ ) {
+ fdFrontend = open( QString("/dev/dvb/%1/%2").arg( list[i] ).arg( flist[j] ).ascii(), O_RDWR);
+ if ( fdFrontend>0 ) {
+ if ( (res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) )
+ perror( QString("/dev/dvb/%1/%2 FE_GET_INFO: ").arg( list[i] ).arg( flist[j] ).ascii() );
+ else {
+ close( fdFrontend );
+ return true;
+ }
+ close( fdFrontend );
+ }
+ }
+ }
+
+ return false;
+}
+
+
+
+void DVBconfig::startup()
+{
+ int i=0, j=0, res, fdFrontend=0;
+ struct dvb_frontend_info info;
+ bool as;
+
+ QStringList list, flist;
+ QString s, t;
+ QDir d;
+ d.setPath( "/dev/dvb/" );
+ list = d.entryList( "adapter*", QDir::Dirs, QDir::Name );
+
+ for ( i=0; i<(int)list.count(); i++ ) {
+ d.setPath( "/dev/dvb/"+list[i]+"/" );
+ flist = d.entryList( "frontend*", QDir::System, QDir::Name );
+ for ( j=0; j<(int)flist.count(); j++ ) {
+ s = list[i];
+ t = flist[j];
+ fdFrontend = open( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii(), O_RDWR);
+ if ( fdFrontend>0 ) {
+ if ( !(res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) ) {
+ if ( (info.type==FE_OFDM)
+ && (info.caps & FE_CAN_QAM_AUTO)
+ && (info.caps & FE_CAN_TRANSMISSION_MODE_AUTO)
+ && (info.caps & FE_CAN_GUARD_INTERVAL_AUTO)
+ && (info.caps & FE_CAN_HIERARCHY_AUTO)
+ && (info.caps & FE_CAN_FEC_AUTO) )
+ as = true;
+ else
+ as = false;
+ fprintf(stderr,"/dev/dvb/%s/%s : opened ( %s )\n", s.ascii(), t.ascii(), info.name );
+ devList.append( new Device( s.replace("adapter","").toInt(), t.replace("frontend","").toInt(), info.type, info.name, as ) );
+ }
+ close( fdFrontend );
+ }
+ else
+ perror( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii() );
+ }
+ }
+
+ //devList.append( new Device( 3, 0, FE_QPSK, "Dummy S", false ) );
+}
+
+
+
+void DVBconfig::setDownloadResult( Job *job )
+{
+ if ( downProgress && job ) {
+ delete downProgress;
+ downProgress = 0;
+ }
+}
+
+
+
+void DVBconfig::setDownloadPercent( Job *job, unsigned long percent )
+{
+ if ( downProgress && job )
+ downProgress->progressBar()->setProgress( percent );
+}
+
+
+
+bool DVBconfig::loadDvbData( QWidget *parent )
+{
+ QString s="";
+ FileCopyJob *job;
+ QFile f( dvbConfigDir+"dvbdata.tar.gz" );
+
+ //if ( f.exists() ) f.remove();
+ downProgress = new KProgressDialog( parent, "progress", i18n("Downloading... "), i18n("Copying data files..."), true );
+ downProgress->progressBar()->setTotalSteps( 100 );
+ //job = file_copy( KURL( "http://hftom.free.fr/kaxtv/dvbdata.tar.gz" ), KURL( dvbConfigDir+"dvbdata.tar.gz" ), -1, true, false, false );
+ job = file_copy( KURL( "http://hftom.free.fr/kaxtv/dvbdata.tar.gz" ), KURL( dvbConfigDir+"dvbdata.tar.gz" ), -1, true, false, false );
+ connect( job, SIGNAL(result(KIO::Job*)), this, SLOT(setDownloadResult(KIO::Job*)) );
+ connect( job, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(setDownloadPercent(KIO::Job*,unsigned long)) );
+ downProgress->exec();
+ disconnect( job, SIGNAL(result(KIO::Job*)), this, SLOT(setDownloadResult(KIO::Job*)) );
+ disconnect( job, SIGNAL(percent(KIO::Job*,unsigned long)), this, SLOT(setDownloadPercent(KIO::Job*,unsigned long)) );
+ if ( downProgress ) {
+ delete downProgress;
+ downProgress = 0;
+ }
+ KTar tar( dvbConfigDir+"dvbdata.tar.gz");
+ if ( tar.open( IO_ReadOnly ) ) {
+ tar.directory()->copyTo( dvbConfigDir );
+ return true;
+ }
+ else
+ return false;
+}
+
+
+
+bool DVBconfig::localData()
+{
+ QString s = locate("data","kaffeine/dvbdata.tar.gz");
+ KTar tar( s );
+ if ( tar.open( IO_ReadOnly ) ) {
+ tar.directory()->copyTo( dvbConfigDir );
+ return true;
+ }
+ else
+ return false;
+}
+
+
+
+bool DVBconfig::haveData()
+{
+ if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) {
+ loadDvbData(0);
+ if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) {
+ if ( !localData() )
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+QStringList DVBconfig::getSourcesList( fe_type_t type )
+{
+ QString s;
+ QStringList list;
+
+ switch ( type ) {
+ case FE_QPSK : s = "dvb-s"; break;
+ case FE_QAM : s = "dvb-c"; break;
+ case FE_OFDM : s = "dvb-t"; break;
+ default : return list;
+ }
+ list = QDir( dvbConfigDir+s ).entryList( QDir::Files, QDir::Name );
+ return list;
+}
+
+
+
+void DVBconfig::addCategory( const QString &name, const QString &icon )
+{
+ categories.append( new Category( name, icon ) );
+}
+
+
+
+void DVBconfig::removeCategory( const QString &name )
+{
+ int i;
+
+ for ( i=0; i<(int)categories.count(); i++ ) {
+ if ( categories.at(i)->name==name ) {
+ categories.remove( i );
+ break;
+ }
+ }
+}
+
+
+
+void DVBconfig::changeIconCategory( const QString &name, const QString &icon )
+{
+ int i;
+
+ if ( name==i18n("All") )
+ allIcon = icon;
+ else if ( name==i18n("TV") )
+ tvIcon = icon;
+ else if ( name==i18n("Radio") )
+ radioIcon = icon;
+ else {
+ for ( i=0; i<(int)categories.count(); i++ ) {
+ if ( categories.at(i)->name==name ) {
+ categories.at(i)->icon = icon;
+ break;
+ }
+ }
+ }
+}
+
+
+
+int DVBconfig::readDvbChanOrder()
+{
+ config->setGroup( "DVB Options" );
+ int sort = config->readNumEntry("ChannelsSorting", 0);
+ return sort;
+}
+
+
+
+void DVBconfig::saveDvbChanOrder( int s, int col )
+{
+ int sort = (s<<1) | col;
+ config->setGroup( "DVB Options" );
+ config->writeEntry("ChannelsSorting", sort);
+ config->sync();
+}
+
+
+
+void DVBconfig::readConfig()
+{
+ QSize size;
+ QString s;
+ int i, j;
+
+ config->setGroup( "DVB Options" );
+ broadcastAddress = config->readEntry( "BroadcastAddress", "192.168.0.255" );
+ broadcastPort = config->readNumEntry( "BroadcastPort", 1234 );
+ senderPort = config->readNumEntry( "SenderPort", 1235 );
+ size = QSize(600, 350);
+ epgSize = config->readSizeEntry( "EPG Geometry", &size );
+ size = QSize(600, 300);
+ timerSize = config->readSizeEntry( "Timers Geometry", &size );
+ size = QSize(300, 300);
+ scanSize = config->readSizeEntry( "Scan Geometry", &size );
+ beginMargin = config->readNumEntry( "BeginMargin", 5 );
+ endMargin = config->readNumEntry( "EndMargin", 10 );
+ instantDuration = config->readNumEntry( "InstantDuration", 120 );
+ recordDir = config->readEntry( "RecordDir", QDir::homeDirPath() );
+ if ( !recordDir.endsWith("/") )
+ recordDir+= "/";
+ sizeFile = config->readNumEntry("SizeFile",0);
+ shiftDir = config->readEntry( "ShiftDir", QDir::homeDirPath() );
+ if ( !shiftDir.endsWith("/") )
+ shiftDir+= "/";
+ filenameFormat = config->readEntry( "filenameFormat", "%name" );
+ for ( i=0; i<(int)devList.count(); i++ ) {
+ devList.at(i)->source = config->readEntry( QString("DVB%1").arg(i), "" );
+ devList.at(i)->tuningTimeout = config->readNumEntry( QString("DVB%1_TIMEOUT").arg(i), 1500 );
+ if ( devList.at(i)->type!=FE_QPSK )
+ continue;
+ devList.at(i)->numLnb = config->readNumEntry( QString("DVB%1_NLNB").arg(i), 1 );
+ for ( j=0; j<devList.at(i)->numLnb; j++ ) {
+ devList.at(i)->lnb[j].switchFreq = config->readNumEntry( QString("DVB%1_LNB%2_switch").arg(i).arg(j), 11700 );
+ devList.at(i)->lnb[j].loFreq = config->readNumEntry( QString("DVB%1_LNB%2_lo").arg(i).arg(j), 9750 );
+ devList.at(i)->lnb[j].hiFreq = config->readNumEntry( QString("DVB%1_LNB%2_hi").arg(i).arg(j), 10600 );
+ devList.at(i)->lnb[j].rotorType = config->readNumEntry( QString("DVB%1_LNB%2_rotor").arg(i).arg(j), 0 );
+ devList.at(i)->lnb[j].source = config->readListEntry( QString("DVB%1_LNB%2_source").arg(i).arg(j) );
+ devList.at(i)->lnb[j].position = config->readIntListEntry( QString("DVB%1_LNB%2_position").arg(i).arg(j) );
+ devList.at(i)->lnb[j].speed13v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), 2.5 );
+ devList.at(i)->lnb[j].speed18v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), 1.5 );
+ }
+ }
+ j = config->readNumEntry( "NumCategories", 0 );
+ for ( i=0; i<j; i++ )
+ categories.append( new Category( config->readEntry( QString("CategoryName%1").arg(i), "" ), config->readEntry( QString("CategoryIcon%1").arg(i), "kaffeine" ) ) );
+ allIcon = config->readEntry( "AllIcon", "kaffeine" );
+ tvIcon = config->readEntry( "TvIcon", "kdvbtv" );
+ radioIcon = config->readEntry( "RadioIcon", "kdvbra" );
+ lastChannel = config->readNumEntry( "LastChannel", 1 );
+ splitSizes = config->readIntListEntry("SplitSizes");
+ defaultCharset = config->readEntry( "DefaultCharset", "ISO8859-1" );
+ usalsLatitude = config->readDoubleNumEntry( "UsalsLatitude", 0.0 );
+ usalsLongitude = config->readDoubleNumEntry( "UsalsLongitude", 0.0 );
+ for ( i=0; i<(int)devList.count(); i++ ) {
+ devList.at(i)->usalsLatitude = usalsLatitude;
+ devList.at(i)->usalsLongitude = usalsLongitude;
+ }
+}
+
+
+
+void DVBconfig::saveConfig()
+{
+ int i, j;
+
+ config->setGroup( "DVB Options" );
+ config->writeEntry( "EPG Geometry", epgSize );
+ config->writeEntry( "Timers Geometry", timerSize );
+ config->writeEntry( "Scan Geometry", scanSize );
+ config->writeEntry( "BeginMargin", beginMargin );
+ config->writeEntry( "EndMargin", endMargin );
+ config->writeEntry( "InstantDuration", instantDuration );
+ config->writeEntry( "RecordDir", recordDir );
+ config->writeEntry( "ShiftDir", shiftDir );
+ config->writeEntry( "filenameFormat", filenameFormat );
+ config->writeEntry( "BroadcastAddress", broadcastAddress );
+ config->writeEntry( "BroadcastPort", broadcastPort );
+ config->writeEntry( "SenderPort", senderPort );
+ for ( i=0; i<(int)devList.count(); i++ ) {
+ config->writeEntry( QString("DVB%1").arg(i), devList.at(i)->source );
+ config->writeEntry( QString("DVB%1_TIMEOUT").arg(i), devList.at(i)->tuningTimeout );
+ if ( devList.at(i)->type!=FE_QPSK )
+ continue;
+ config->writeEntry( QString("DVB%1_NLNB").arg(i), devList.at(i)->numLnb );
+ for ( j=0; j<devList.at(i)->numLnb; j++ ) {
+ config->writeEntry( QString("DVB%1_LNB%2_switch").arg(i).arg(j), devList.at(i)->lnb[j].switchFreq );
+ config->writeEntry( QString("DVB%1_LNB%2_lo").arg(i).arg(j), devList.at(i)->lnb[j].loFreq );
+ config->writeEntry( QString("DVB%1_LNB%2_hi").arg(i).arg(j), devList.at(i)->lnb[j].hiFreq );
+ config->writeEntry( QString("DVB%1_LNB%2_rotor").arg(i).arg(j), devList.at(i)->lnb[j].rotorType );
+ config->writeEntry( QString("DVB%1_LNB%2_source").arg(i).arg(j), devList.at(i)->lnb[j].source );
+ config->writeEntry( QString("DVB%1_LNB%2_position").arg(i).arg(j), devList.at(i)->lnb[j].position );
+ config->writeEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), devList.at(i)->lnb[j].speed13v );
+ config->writeEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), devList.at(i)->lnb[j].speed18v );
+ }
+ }
+ config->writeEntry( "NumCategories", categories.count() );
+ for ( i=0; i<(int)categories.count(); i++ ) {
+ config->writeEntry( QString("CategoryName%1").arg(i), categories.at(i)->name );
+ config->writeEntry( QString("CategoryIcon%1").arg(i), categories.at(i)->icon );
+ }
+ config->writeEntry( "AllIcon", allIcon );
+ config->writeEntry( "TvIcon", tvIcon );
+ config->writeEntry( "RadioIcon", radioIcon );
+ config->writeEntry( "LastChannel", lastChannel );
+ config->writeEntry( "SplitSizes", splitSizes );
+ config->writeEntry( "DefaultCharset", defaultCharset );
+ config->writeEntry( "UsalsLatitude", usalsLatitude );
+ config->writeEntry( "UsalsLongitude", usalsLongitude );
+ config->writeEntry( "SizeFile", sizeFile );
+ config->sync();
+}
+
+
+
+bool DVBconfig::firstRun()
+{
+ config->setGroup( "DVB Options" );
+ if ( config->readNumEntry( "FirstRun", 0 )<3 ) {
+ config->writeEntry( "FirstRun", 3 );
+ return true;
+ }
+ return false;
+}
+
+
+
+DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ) :
+ KDialogBase ( IconList, i18n("DVB Settings"), Ok|Cancel, Ok, parent, "dvbConfigDialog", true, true )
+{
+ QLabel *lab;
+ KIconLoader *icon = new KIconLoader();
+ QHBoxLayout *h1;
+ QString s;
+ int i;
+ QVBoxLayout *vb;
+ QGroupBox *gb;
+ QGridLayout *grid, *sgrid;
+ QLabel *ident;
+ QLabel *dvbType;
+ int gridLine;
+ QFrame *page;
+ QSpinBox *spin;
+ KPushButton *usals;
+ QWidget *swidg;
+ QStringList rotorList; rotorList<<i18n("No rotor")<<i18n("USALS rotor")<<i18n("Positions rotor");
+
+ dvbConfig = dc;
+ timeoutSpin.setAutoDelete( true );
+
+ for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) {
+ page = addPage( i18n("DVB Device")+" "+QString("%1:%2").arg(dvbConfig->devList.at(i)->adapter).arg(dvbConfig->devList.at(i)->tuner), i18n("Device Settings"),
+ KGlobal::instance()->iconLoader()->loadIcon( "hwinfo", KIcon::NoGroup, KIcon::SizeMedium ) );
+ vb = new QVBoxLayout( page, 6, 6 );
+ gb = new QGroupBox( "", page );
+ grid = new QGridLayout( gb, 1, 1, 20, 6 );
+ gridLine = 0;
+
+ lab = new QLabel( i18n("<qt><b>Name:</b></qt>"), gb );
+ grid->addWidget( lab, gridLine, 0 );
+ ident = new QLabel( dvbConfig->devList.at(i)->name, gb );
+ grid->addMultiCellWidget( ident, gridLine, gridLine, 1, 3 );
+ ++gridLine;
+
+ lab = new QLabel( i18n("<qt><b>Type:</b></qt>"), gb );
+ grid->addWidget( lab, gridLine, 0 );
+ dvbType = new QLabel( gb );
+ switch ( dvbConfig->devList.at(i)->type ) {
+ case FE_QAM : dvbType->setText( i18n("Cable") ); break;
+ case FE_OFDM : dvbType->setText( i18n("Terrestrial") ); break;
+ case FE_QPSK : dvbType->setText( i18n("Satellite") ); break;
+ case FE_ATSC : dvbType->setText( i18n("Atsc") ); break;
+ default : dvbType->setText( i18n("Unknown") );
+ }
+ grid->addMultiCellWidget( dvbType, gridLine, gridLine, 1, 3 );
+ ++gridLine;
+
+ lab = new QLabel( i18n("Tuner timeout :"), gb );
+ grid->addWidget( lab, gridLine, 0 );
+ spin = new QSpinBox( 500, 5000, 100, gb );
+ spin->setValue( dvbConfig->devList.at(i)->tuningTimeout );
+ timeoutSpin.append( spin );
+ grid->addWidget( spin, gridLine, 1 );
+ lab = new QLabel( i18n("(ms)"), gb );
+ grid->addWidget( lab, gridLine, 2 );
+ ++gridLine;
+
+ if ( dvbConfig->devList.at(i)->type==FE_QPSK ) {
+ lab = new QLabel( i18n("Number of LNBs:"), gb );
+ grid->addWidget( lab, gridLine, 0 );
+ satNumber[i] = new MSpinBox( gb, i );
+ connect( satNumber[i], SIGNAL(signalValueChanged(int,int)), this, SLOT(satNumberChanged(int,int)));
+ grid->addWidget( satNumber[i], gridLine, 1 );
+ usals = new KPushButton( gb );
+ usals->setGuiItem( KGuiItem(i18n("Set rotor coordinates..."), icon->loadIconSet("move", KIcon::Small) ) );
+ connect( usals, SIGNAL(clicked()), this, SLOT(setUsals()));
+ grid->addWidget( usals, gridLine, 2 );
+
+ ++gridLine;
+
+ lnb0[i] = new MPushButton( gb, i, 0 );
+ lnb0[i]->setGuiItem( KGuiItem(i18n("LNB 1 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
+ lnb0[i]->setEnabled(true);
+ grid->addWidget( lnb0[i], gridLine, 0 );
+ connect( lnb0[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));
+ rotor0[i] = new MComboBox( gb, i, 0 );
+ rotor0[i]->insertStringList( rotorList );
+ rotor0[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[0].rotorType );
+ grid->addWidget( rotor0[i], gridLine, 1 );
+ connect( rotor0[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int)));
+ swidg = new QWidget( gb );
+ sgrid = new QGridLayout( swidg, 1, 1, 0, 0 );
+ sat0[i] = new QComboBox( swidg );
+ sat0[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) );
+ sgrid->addWidget( sat0[i], 0, 0 );
+ src0[i] = new MPushButton( swidg, i, 0 );
+ src0[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) );
+ connect( src0[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) );
+ sgrid->addWidget( src0[i], 1, 0 );
+ if ( dvbConfig->devList.at(i)->lnb[0].rotorType==0 ) {
+ setSource( sat0[i], dvbConfig->devList.at(i)->lnb[0].source[0] );
+ src0[i]->hide();
+ }
+ else {
+ sat0[i]->hide();
+ }
+ grid->addWidget( swidg, gridLine, 2 );
+ ++gridLine;
+
+ lnb1[i] = new MPushButton( gb, i, 1 );
+ lnb1[i]->setGuiItem( KGuiItem(i18n("LNB 2 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
+ lnb1[i]->setEnabled(false);
+ grid->addWidget( lnb1[i], gridLine, 0 );
+ connect( lnb1[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));
+ rotor1[i] = new MComboBox( gb, i, 1 );
+ rotor1[i]->setEnabled( false );
+ rotor1[i]->insertStringList( rotorList );
+ rotor1[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[1].rotorType );
+ grid->addWidget( rotor1[i], gridLine, 1 );
+ connect( rotor1[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int)));
+ swidg = new QWidget( gb );
+ sgrid = new QGridLayout( swidg, 1, 1, 0, 0 );
+ sat1[i] = new QComboBox( swidg );
+ sat1[i]->setEnabled(false);
+ sat1[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) );
+ sgrid->addWidget( sat1[i], 0, 0 );
+ src1[i] = new MPushButton( swidg, i, 1 );
+ src1[i]->setEnabled(false);
+ src1[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) );
+ connect( src1[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) );
+ sgrid->addWidget( src1[i], 1, 0 );
+ if ( dvbConfig->devList.at(i)->lnb[1].rotorType==0 ) {
+ setSource( sat1[i], dvbConfig->devList.at(i)->lnb[1].source[0] );
+ src1[i]->hide();
+ }
+ else {
+ sat1[i]->hide();
+ }
+ grid->addWidget( swidg, gridLine, 2 );
+ ++gridLine;
+
+ lnb2[i] = new MPushButton( gb, i, 2 );
+ lnb2[i]->setGuiItem( KGuiItem(i18n("LNB 3 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
+ lnb2[i]->setEnabled(false);
+ grid->addWidget( lnb2[i], gridLine, 0 );
+ connect( lnb2[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));
+ rotor2[i] = new MComboBox( gb, i, 2 );
+ rotor2[i]->setEnabled(false);
+ rotor2[i]->insertStringList( rotorList );
+ rotor2[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[2].rotorType );
+ grid->addWidget( rotor2[i], gridLine, 1 );
+ connect( rotor2[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int)));
+ swidg = new QWidget( gb );
+ sgrid = new QGridLayout( swidg, 1, 1, 0, 0 );
+ sat2[i] = new QComboBox( swidg );
+ sat2[i]->setEnabled(false);
+ sat2[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) );
+ sgrid->addWidget( sat2[i], 0, 0 );
+ src2[i] = new MPushButton( swidg, i, 2 );
+ src2[i]->setEnabled(false);
+ src2[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) );
+ connect( src2[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) );
+ sgrid->addWidget( src2[i], 1, 0 );
+ if ( dvbConfig->devList.at(i)->lnb[2].rotorType==0 ) {
+ setSource( sat2[i], dvbConfig->devList.at(i)->lnb[2].source[0] );
+ src2[i]->hide();
+ }
+ else {
+ sat2[i]->hide();
+ }
+ grid->addWidget( swidg, gridLine, 2 );
+ ++gridLine;
+
+ lnb3[i] = new MPushButton( gb, i, 3 );
+ lnb3[i]->setGuiItem( KGuiItem(i18n("LNB 4 settings..."), icon->loadIconSet("hwinfo", KIcon::Small) ) );
+ lnb3[i]->setEnabled(false);
+ grid->addWidget( lnb3[i], gridLine, 0 );
+ connect( lnb3[i], SIGNAL(clicked(int,int)), this, SLOT(setLnb(int,int)));
+ rotor3[i] = new MComboBox( gb, i, 3 );
+ rotor3[i]->setEnabled(false);
+ rotor3[i]->insertStringList( rotorList );
+ rotor3[i]->setCurrentItem( dvbConfig->devList.at(i)->lnb[3].rotorType );
+ grid->addWidget( rotor3[i], gridLine, 1 );
+ connect( rotor3[i], SIGNAL(activated(int,int,int)), this, SLOT(setRotor(int,int,int)));
+ swidg = new QWidget( gb );
+ sgrid = new QGridLayout( swidg, 1, 1, 0, 0 );
+ sat3[i] = new QComboBox( swidg );
+ sat3[i]->setEnabled(false);
+ sat3[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) );
+ sgrid->addWidget( sat3[i], 0, 0 );
+ src3[i] = new MPushButton( swidg, i, 3 );
+ src3[i]->setEnabled(false);
+ src3[i]->setGuiItem( KGuiItem(i18n("Sources list...") ) );
+ connect( src3[i], SIGNAL(clicked(int,int)), this, SLOT(setRotorSources(int,int)) );
+ sgrid->addWidget( src3[i], 1, 0 );
+ if ( dvbConfig->devList.at(i)->lnb[3].rotorType==0 ) {
+ setSource( sat3[i], dvbConfig->devList.at(i)->lnb[3].source[0] );
+ src3[i]->hide();
+ }
+ else {
+ sat3[i]->hide();
+ }
+ grid->addWidget( swidg, gridLine, 2 );
+ ++gridLine;
+
+ satNumber[i]->setValue( dvbConfig->devList.at(i)->numLnb );
+ }
+ else {
+ lab = new QLabel( i18n("Source:"), gb );
+ grid->addWidget( lab, gridLine, 0 );
+ sat0[i] = new QComboBox( gb );
+ if ( dvbConfig->devList.at(i)->canAutoscan )
+ sat0[i]->insertItem( "AUTO" );
+ sat0[i]->insertStringList( dvbConfig->getSourcesList(dvbConfig->devList.at(i)->type) );
+ setSource( sat0[i], dvbConfig->devList.at(i)->source );
+ grid->addWidget( sat0[i], gridLine, 1 );
+ ++gridLine;
+
+ if ( dvbConfig->devList.at(i)->canAutoscan ) {
+ lab = new QLabel( i18n("<qt>This device seems to support the <b><i>autoscan</i></b> feature. "
+ "You can choose <b>AUTO</b> in Source list to let Kaffeine "
+ "search for a range of frequencies.<br>"
+ "If <b><i>autoscan</i></b> fails to find your channels, choose a real Source in list.</qt>"), gb );
+ grid->addMultiCellWidget( lab, gridLine, gridLine, 0, 3 );
+ ++gridLine;
+ }
+ }
+ lab = new QLabel( i18n("<qt><i>If you can't find your network/location in the list, you'll have to create one. "
+ "Look in $HOME/.kde/share/apps/kaffeine/dvb-x/ and take an existing file as start point. "
+ "Fill in with the values for your network/location and give it a sensible name "
+ "(follow the naming convention). If you think your new file could be usefull for others, send it to "
+ "kaffeine-user(AT)lists.sf.net.</i></qt>"), gb );
+ grid->addMultiCellWidget( lab, gridLine, gridLine, 0, 3 );
+
+ vb->addWidget( gb );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+ }
+
+ page = addPage(i18n("Recording"),i18n("DVB Recording Options"),
+ KGlobal::instance()->iconLoader()->loadIcon( "hdd_unmount", KIcon::NoGroup, KIcon::SizeMedium ) );
+ vb = new QVBoxLayout( page, 6, 6 );
+ gb = new QGroupBox( "", page );
+ grid = new QGridLayout( gb, 1, 1, 20, 6 );
+
+ lab = new QLabel( i18n("Records directory:"), gb );
+ grid->addWidget( lab, 0, 0 );
+ recordDirLe = new QLineEdit( gb );
+ recordDirLe->setReadOnly( true );
+ grid->addWidget( recordDirLe, 0, 1 );
+ recordDirBtn = new QToolButton( gb );
+ recordDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) );
+ grid->addWidget( recordDirBtn, 0, 2 );
+
+ lab = new QLabel( i18n("Time shifting directory:"), gb );
+ grid->addWidget( lab, 1, 0 );
+ shiftDirLe = new QLineEdit( gb );
+ shiftDirLe->setReadOnly( true );
+ grid->addWidget( shiftDirLe, 1, 1 );
+ shiftDirBtn = new QToolButton( gb );
+ shiftDirBtn->setIconSet( icon->loadIconSet("fileopen", KIcon::Small) );
+ grid->addWidget( shiftDirBtn, 1, 2 );
+
+ lab = new QLabel( i18n("Begin margin:"), gb );
+ grid->addWidget( lab, 2, 0 );
+ beginSpin = new QSpinBox( gb );
+ h1 = new QHBoxLayout();
+ h1->addWidget( beginSpin );
+ lab = new QLabel( i18n("(minutes)"), gb );
+ h1->addWidget( lab );
+ grid->addLayout( h1, 2, 1 );
+
+ lab = new QLabel( i18n("End margin:"), gb );
+ grid->addWidget( lab, 3, 0 );
+ endSpin = new QSpinBox( gb );
+ h1 = new QHBoxLayout();
+ h1->addWidget( endSpin );
+ lab = new QLabel( i18n("(minutes)"), gb );
+ h1->addWidget( lab );
+ grid->addLayout( h1, 3, 1 );
+
+ lab = new QLabel( i18n("Instant record duration:"), gb );
+ grid->addWidget( lab, 4, 0 );
+ instantDurationSpin = new QSpinBox( 1, 1440, 1, gb );
+ h1 = new QHBoxLayout();
+ h1->addWidget( instantDurationSpin );
+ lab = new QLabel( i18n("(minutes)"), gb );
+ h1->addWidget( lab );
+ grid->addLayout( h1, 4, 1 );
+
+ lab = new QLabel( i18n("Max file size (0=Unlimited):"), gb );
+ grid->addWidget( lab, 5, 0 );
+ sizeFileSpin = new QSpinBox( 1, 9999, 1, gb );
+ sizeFileSpin->setMinValue(0);
+ h1 = new QHBoxLayout();
+ h1->addWidget( sizeFileSpin );
+ lab = new QLabel( i18n("(MB)"), gb );
+ h1->addWidget( lab );
+ grid->addLayout( h1, 5, 1 );
+
+ lab = new QLabel( i18n("Filename Format:"), gb );
+ grid->addWidget( lab, 7, 0 );
+ filenameFormatLe = new QLineEdit( gb );
+ grid->addWidget( filenameFormatLe, 7, 1 );
+ helpNameBtn = new QToolButton( gb );
+ helpNameBtn->setIconSet( icon->loadIconSet("help", KIcon::Small) );
+ grid->addWidget( helpNameBtn, 7, 2 );
+
+ vb->addWidget( gb );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+
+ recordDirLe->setText( dvbConfig->recordDir );
+ shiftDirLe->setText( dvbConfig->shiftDir );
+ beginSpin->setValue( dvbConfig->beginMargin );
+ endSpin->setValue( dvbConfig->endMargin );
+ instantDurationSpin->setValue( dvbConfig->instantDuration );
+ sizeFileSpin->setValue( dvbConfig->sizeFile );
+ filenameFormatLe->setText( dvbConfig->filenameFormat );
+
+ page = addPage(i18n("Broadcasting"),i18n("DVB Broadcasting"),
+ KGlobal::instance()->iconLoader()->loadIcon( "network_local", KIcon::NoGroup, KIcon::SizeMedium ) );
+ vb = new QVBoxLayout( page, 6, 6 );
+ gb = new QGroupBox( "", page );
+ grid = new QGridLayout( gb, 1, 1, 20, 6 );
+
+ lab = new QLabel( i18n("Broadcast address:"), gb );
+ grid->addWidget( lab, 0, 0 );
+ broadcastLe = new QLineEdit( gb );
+ grid->addWidget( broadcastLe, 0, 1 );
+ lab = new QLabel( i18n("Broadcast port:"), gb );
+ grid->addWidget( lab, 1, 0 );
+ bportSpin = new QSpinBox( 1, 65535, 1, gb );
+ grid->addWidget( bportSpin, 1, 1 );
+ lab = new QLabel( i18n("Info port:"), gb );
+ grid->addWidget( lab, 2, 0 );
+ sportSpin = new QSpinBox( 1, 65535, 1, gb );
+ grid->addWidget( sportSpin, 2, 1 );
+
+ vb->addWidget( gb );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+
+ broadcastLe->setText( dvbConfig->broadcastAddress );
+ bportSpin->setValue( dvbConfig->broadcastPort );
+ sportSpin->setValue( dvbConfig->senderPort );
+
+ page = addPage(i18n("Misc"),i18n("Misc"),
+ KGlobal::instance()->iconLoader()->loadIcon( "misc", KIcon::NoGroup, KIcon::SizeMedium ) );
+ vb = new QVBoxLayout( page, 6, 6 );
+ gb = new QGroupBox( "", page );
+ grid = new QGridLayout( gb, 1, 1, 20, 6 );
+
+ lab = new QLabel( i18n("Default charset (restart needed):"), gb );
+ grid->addWidget( lab, 0, 0 );
+ charsetComb = new QComboBox( gb );
+ charsetComb->insertItem( "ISO8859-1" );
+ charsetComb->insertItem( "ISO6937" );
+ if ( dvbConfig->defaultCharset=="ISO8859-1" )
+ charsetComb->setCurrentItem( 0 );
+ else if ( dvbConfig->defaultCharset=="ISO6937" )
+ charsetComb->setCurrentItem( 1 );
+ grid->addWidget( charsetComb, 0, 1 );
+
+ lab = new QLabel( i18n("Update scan data:"), gb );
+ grid->addWidget( lab, 1, 0 );
+ updateBtn = new KPushButton( gb );
+ updateBtn->setGuiItem( KGuiItem(i18n("Download"), icon->loadIconSet("khtml_kget", KIcon::Small) ) );
+ grid->addWidget( updateBtn, 1, 1 );
+
+ lab = new QLabel( i18n("Dump epg's events to \n~/kaffeine_dvb_events.tx:"), gb );
+ grid->addWidget( lab, 2, 0 );
+ dumpBtn = new KPushButton( gb );
+ dumpBtn->setGuiItem( KGuiItem(i18n("Dump"), icon->loadIconSet("filesave", KIcon::Small) ) );
+ grid->addWidget( dumpBtn, 2, 1 );
+
+ vb->addWidget( gb );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+
+ if ( p ) {
+ page = addPage(i18n("DVB plugins"),i18n("DVB plugins"),
+ KGlobal::instance()->iconLoader()->loadIcon( "misc", KIcon::NoGroup, KIcon::SizeMedium ) );
+ vb = new QVBoxLayout( page, 6, 6 );
+ gb = new QGroupBox( "", page );
+ grid = new QGridLayout( gb, 1, 1, 20, 6 );
+
+ KPushButton *btn = new KPushButton( p->pluginName(), gb );
+ grid->addWidget( btn, 0, 0 );
+ connect( btn, SIGNAL(clicked()), p, SLOT(configDialog()) );
+ vb->addWidget( gb );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+ }
+
+ connect( recordDirBtn, SIGNAL(clicked()), this, SLOT(setRecordDir()) );
+ connect( shiftDirBtn, SIGNAL(clicked()), this, SLOT(setShiftDir()) );
+ connect( updateBtn, SIGNAL(clicked()), this, SLOT(downloadData()) );
+ connect( helpNameBtn, SIGNAL(clicked()), this, SLOT(fileTemplateHelp()) );
+ delete icon;
+}
+
+
+
+void DvbConfigDialog::setUsals()
+{
+ KDialogBase *dlg = new KDialogBase( this, "usalsConfigDialog", true, i18n("Rotors settings"), Ok|Cancel, Ok, true );
+ QGridLayout *grid;
+ QWidget *page = new QWidget( dlg );
+ dlg->setMainWidget( page );
+
+ QVBoxLayout *vb = new QVBoxLayout( page, 6, 6 );
+ QLabel *lab = new QLabel( i18n("Set your position coordinates for rotors:"), page );
+ vb->addWidget( lab );
+ lab = new QLabel( "(Sydney: -33.8916, 151.2417 - New York: 40.7139, -74.0063)", page );
+ vb->addWidget( lab );
+ grid = new QGridLayout( 0, 1, 1 );
+ lab = new QLabel( i18n("Latitude:"), page );
+ grid->addWidget( lab, 0, 0 );
+ QLineEdit *latitude = new QLineEdit( page );
+ latitude->setText( QString().setNum( dvbConfig->usalsLatitude ) );
+ grid->addWidget( latitude, 0, 1 );
+ lab = new QLabel( i18n("Longitude:"), page );
+ grid->addWidget( lab, 1, 0 );
+ QLineEdit *longitude = new QLineEdit( page );
+ longitude->setText( QString().setNum( dvbConfig->usalsLongitude ) );
+ grid->addWidget( longitude, 1, 1 );
+ vb->addLayout( grid );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+
+ if ( dlg->exec()==QDialog::Accepted ) {
+ dvbConfig->usalsLatitude = latitude->text().toDouble();
+ dvbConfig->usalsLongitude = longitude->text().toDouble();
+ for ( int i=0; i<(int)dvbConfig->devList.count(); i++ ) {
+ dvbConfig->devList.at(i)->usalsLatitude = dvbConfig->usalsLatitude;
+ dvbConfig->devList.at(i)->usalsLongitude = dvbConfig->usalsLongitude;
+ }
+ }
+}
+
+
+
+void DvbConfigDialog::setRotorSources( int devNum, int lnbNum )
+{
+ RotorConfig rotor( dvbConfig->devList.at(devNum), dvbConfig, lnbNum, this );
+ rotor.exec();
+}
+
+
+
+void DvbConfigDialog::setRotor( int index, int devNum, int lnbNum )
+{
+ QComboBox *comb;
+ QPushButton *btn;
+
+ switch ( lnbNum ) {
+ case 0 : comb=sat0[devNum]; btn=src0[devNum]; break;
+ case 1 : comb=sat1[devNum]; btn=src1[devNum]; break;
+ case 2 : comb=sat2[devNum]; btn=src2[devNum]; break;
+ case 3 : comb=sat3[devNum]; btn=src3[devNum]; break;
+ default : return;
+ }
+
+ dvbConfig->devList.at(devNum)->lnb[lnbNum].rotorType=index;
+
+ if ( index==0 ) {
+ btn->hide();
+ comb->show();
+ }
+ else {
+ comb->hide();
+ btn->show();
+ }
+}
+
+
+
+void DvbConfigDialog::setLnb( int devNum, int lnbNum )
+{
+ LnbConfig lnb( &dvbConfig->devList.at(devNum)->lnb[lnbNum], this );
+ lnb.exec();
+}
+
+
+
+void DvbConfigDialog::downloadData()
+{
+ int ret;
+
+loop:
+ if ( !dvbConfig->loadDvbData(0) ) {
+ ret = KMessageBox::questionYesNo( this, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\
+ Check your internet connection, and say Yes to try again.<br>\
+ Or say No to cancel.<br> Should I try again?</qt>") );
+ if ( ret==KMessageBox::Yes )
+ goto loop;
+ return;
+ }
+}
+
+
+
+void DvbConfigDialog::setSource( QComboBox *box, QString s )
+{
+ int pos, i;
+
+ pos = s.find("|");
+ if ( pos>=0 )
+ s = s.right( s.length()-pos-1 );
+ for ( i=0; i<(int)box->count(); i++ ) {
+ if ( box->text(i)==s ) {
+ box->setCurrentItem(i);
+ break;
+ }
+ }
+}
+
+
+
+void DvbConfigDialog::satNumberChanged( int value, int devNum )
+{
+ sat0[devNum]->setEnabled( value > 0 );
+ sat1[devNum]->setEnabled( value > 1 );
+ sat2[devNum]->setEnabled( value > 2 );
+ sat3[devNum]->setEnabled( value > 3 );
+
+ src0[devNum]->setEnabled( value > 0 );
+ src1[devNum]->setEnabled( value > 1 );
+ src2[devNum]->setEnabled( value > 2 );
+ src3[devNum]->setEnabled( value > 3 );
+
+ lnb0[devNum]->setEnabled( value > 0 );
+ lnb1[devNum]->setEnabled( value > 1 );
+ lnb2[devNum]->setEnabled( value > 2 );
+ lnb3[devNum]->setEnabled( value > 3 );
+
+ rotor0[devNum]->setEnabled( value > 0 );
+ rotor1[devNum]->setEnabled( value > 1 );
+ rotor2[devNum]->setEnabled( value > 2 );
+ rotor3[devNum]->setEnabled( value > 3 );
+}
+
+
+
+void DvbConfigDialog::fileTemplateHelp()
+{
+ KMessageBox::information( this, i18n("Special strings are:\n- %chan (channel's name)\n- %date (the starting date, YYMMdd-hhmmss)\n- %name (the name given in timer editor or the program name from EPG)\nSo, if you set template to '%chan-%date-%name', the resulting filename will be, for example, BBC-20070919-210000-News.m2t") );
+}
+
+
+
+void DvbConfigDialog::setRecordDir()
+{
+ QString s = KFileDialog::getExistingDirectory( recordDirLe->text().stripWhiteSpace() );
+ if ( !s.isEmpty() )
+ recordDirLe->setText( s );
+}
+
+
+
+void DvbConfigDialog::setShiftDir()
+{
+ QString s = KFileDialog::getExistingDirectory( shiftDirLe->text().stripWhiteSpace() );
+ if ( !s.isEmpty() )
+ shiftDirLe->setText( s );
+}
+
+
+
+void DvbConfigDialog::accept()
+{
+ QString s;
+ int i;
+
+ if ( recordDirLe->text().stripWhiteSpace().isEmpty() ) {
+ KMessageBox::sorry( this, i18n("Invalid records directory.") );
+ recordDirLe->setFocus();
+ return;
+ }
+ if ( shiftDirLe->text().stripWhiteSpace().isEmpty() ) {
+ KMessageBox::sorry( this, i18n("Invalid time shifting directory.") );
+ shiftDirLe->setFocus();
+ return;
+ }
+ if ( bportSpin->value()==sportSpin->value() ) {
+ KMessageBox::sorry( this, i18n("Broadcast and Info ports must be different.") );
+ sportSpin->setFocus();
+ return;
+ }
+ if ( !QRegExp("(\\d{1,3}\\.){3}\\d{1,3}").exactMatch( broadcastLe->text().stripWhiteSpace() ) ) {
+ KMessageBox::sorry( this, i18n("Invalid broadcast address.") );
+ broadcastLe->setFocus();
+ return;
+ }
+ if ( !filenameFormatLe->text().contains("%chan") && !filenameFormatLe->text().contains("%date") && !filenameFormatLe->text().contains("%name") ) {
+ KMessageBox::sorry( this, i18n("Invalid filename format.") );
+ filenameFormatLe->setFocus();
+ return;
+ }
+
+ for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) {
+ switch (dvbConfig->devList.at(i)->type) {
+ case FE_QPSK: {
+ dvbConfig->devList.at(i)->numLnb = satNumber[i]->value();
+ if ( dvbConfig->devList.at(i)->lnb[3].rotorType==0 ) {
+ dvbConfig->devList.at(i)->lnb[3].source.clear();
+ dvbConfig->devList.at(i)->lnb[3].source.append(sat3[i]->currentText());
+ }
+ if ( dvbConfig->devList.at(i)->lnb[2].rotorType==0 ) {
+ dvbConfig->devList.at(i)->lnb[2].source.clear();
+ dvbConfig->devList.at(i)->lnb[2].source.append(sat2[i]->currentText());
+ }
+ if ( dvbConfig->devList.at(i)->lnb[1].rotorType==0 ) {
+ dvbConfig->devList.at(i)->lnb[1].source.clear();
+ dvbConfig->devList.at(i)->lnb[1].source.append(sat1[i]->currentText());
+ }
+ if ( dvbConfig->devList.at(i)->lnb[0].rotorType==0 ) {
+ dvbConfig->devList.at(i)->lnb[0].source.clear();
+ dvbConfig->devList.at(i)->lnb[0].source.append(sat0[i]->currentText());
+ }
+ s = "S";
+ break;
+ }
+ case FE_QAM: {
+ s = "C";
+ s+="|"+sat0[i]->currentText();
+ break;
+ }
+ case FE_OFDM: {
+ s = "T";
+ s+="|"+sat0[i]->currentText();
+ break;
+ }
+ case FE_ATSC: {
+ s = "A";
+ s+="|"+sat0[i]->currentText();
+ break;
+ }
+ }
+ dvbConfig->devList.at(i)->source = s;
+ dvbConfig->devList.at(i)->tuningTimeout = timeoutSpin.at(i)->value();
+ }
+
+ dvbConfig->recordDir = recordDirLe->text();
+ if ( !dvbConfig->recordDir.endsWith("/") )
+ dvbConfig->recordDir+= "/";
+ dvbConfig->shiftDir = shiftDirLe->text();
+ if ( !dvbConfig->shiftDir.endsWith("/") )
+ dvbConfig->shiftDir+= "/";
+ dvbConfig->beginMargin = beginSpin->value();
+ dvbConfig->endMargin = endSpin->value();
+ dvbConfig->instantDuration = instantDurationSpin->value();
+ dvbConfig->sizeFile = sizeFileSpin->value();
+ dvbConfig->filenameFormat = filenameFormatLe->text();
+ dvbConfig->defaultCharset = charsetComb->currentText();
+ dvbConfig->broadcastAddress = broadcastLe->text().stripWhiteSpace();
+ dvbConfig->broadcastPort = bportSpin->value();
+ dvbConfig->senderPort = sportSpin->value();
+ dvbConfig->saveConfig();
+ done( Accepted );
+}
+
+
+
+DvbConfigDialog::~DvbConfigDialog()
+{
+}
+
+
+
+LnbConfig::LnbConfig( LNB *b, QWidget *parent ) :
+ KDialogBase ( parent, "lnbConfigDialog", true, i18n("LNB Settings"), Ok|Cancel, Ok, true )
+{
+ QGridLayout *grid;
+
+ QWidget *page = new QWidget( this );
+ setMainWidget( page );
+
+ lnb = b;
+
+ QVBoxLayout *vb = new QVBoxLayout( page, 6, 6 );
+ univ = new QPushButton( i18n("Universal LNB"), page );
+ connect( univ, SIGNAL(clicked()), this, SLOT(setUniversal()) );
+ vb->addWidget( univ );
+ cmono = new QPushButton( i18n("C-Band LNB"), page );
+ connect( cmono, SIGNAL(clicked()), this, SLOT(setCBandMono()) );
+ vb->addWidget( cmono );
+ cmulti = new QPushButton( i18n("C-Band Multipoint LNB"), page );
+ connect( cmulti, SIGNAL(clicked()), this, SLOT(setCBandMulti()) );
+ vb->addWidget( cmulti );
+
+ grid = new QGridLayout( 0, 1, 1 );
+ nLO = new QButtonGroup( 3, Qt::Horizontal, page );
+ connect( nLO, SIGNAL(clicked(int)), this, SLOT(setDual(int)) );
+ new QRadioButton( i18n("Dual LO"), nLO );
+ new QRadioButton( i18n("Single LO"), nLO );
+ new QRadioButton( i18n("H/V LO"), nLO );
+ grid->addMultiCellWidget( nLO, 0, 0, 0, 1 );
+ slofLab = new QLabel( i18n("Dual LO switch frequency:")+i18n(" (MHz)"), page );
+ grid->addWidget( slofLab, 1, 0 );
+ slof = new QSpinBox( 0, 13000, 1, page );
+ grid->addWidget( slof, 1, 1 );
+ loLab = new QLabel( i18n("Lo-band frequency:")+i18n(" (MHz)"), page );
+ grid->addWidget( loLab, 2, 0 );
+ lo = new QSpinBox( 0, 13000, 1, page );
+ grid->addWidget( lo, 2, 1 );
+ hiLab = new QLabel( i18n("Hi-band frequency:")+i18n(" (MHz)"), page );
+ grid->addWidget( hiLab, 3, 0 );
+ hi = new QSpinBox( 0, 13000, 1, page );
+ grid->addWidget( hi, 3, 1 );
+ singleLab = new QLabel( i18n("Single LO frequency:")+i18n(" (MHz)"), page );
+ grid->addWidget( singleLab, 4, 0 );
+ single = new QSpinBox( 0, 13000, 1, page );
+ grid->addWidget( single, 4, 1 );
+ verticalLab = new QLabel( i18n("Vertical pol. LO frequency:")+i18n(" (MHz)"), page );
+ grid->addWidget( verticalLab, 5, 0 );
+ vertical = new QSpinBox( 0, 13000, 1, page );
+ grid->addWidget( vertical, 5, 1 );
+ horizontalLab = new QLabel( i18n("Horizontal pol. LO frequency:")+i18n(" (MHz)"), page );
+ grid->addWidget( horizontalLab, 6, 0 );
+ horizontal = new QSpinBox( 0, 13000, 1, page );
+ grid->addWidget( horizontal, 6, 1 );
+
+ vb->addLayout( grid );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+
+
+ slof->setValue( lnb->switchFreq );
+ lo->setValue( lnb->loFreq );
+ hi->setValue( lnb->hiFreq );
+ single->setValue( lnb->loFreq );
+ vertical->setValue( lnb->loFreq );
+ horizontal->setValue( lnb->hiFreq );
+
+ if ( lnb->switchFreq ) {
+ nLO->setButton( 0 );
+ setDual( 0 );
+ }
+ else {
+ if ( lnb->hiFreq ) {
+ nLO->setButton( 2 );
+ setDual( 2 );
+ }
+ else {
+ nLO->setButton( 1 );
+ setDual( 1 );
+ }
+ }
+}
+
+
+
+void LnbConfig::setDual( int id )
+{
+ switch ( id ) {
+ case 0: {
+ singleLab->hide();
+ single->hide();
+ verticalLab->hide();
+ vertical->hide();
+ horizontalLab->hide();
+ horizontal->hide();
+ slofLab->show();
+ slof->show();
+ loLab->show();
+ lo->show();
+ hiLab->show();
+ hi->show();
+ break;
+ }
+ case 1: {
+ slofLab->hide();
+ slof->hide();
+ loLab->hide();
+ lo->hide();
+ hiLab->hide();
+ hi->hide();
+ verticalLab->hide();
+ vertical->hide();
+ horizontalLab->hide();
+ horizontal->hide();
+ singleLab->show();
+ single->show();
+ break;
+ }
+ case 2: {
+ slofLab->hide();
+ slof->hide();
+ loLab->hide();
+ lo->hide();
+ hiLab->hide();
+ hi->hide();
+ singleLab->hide();
+ single->hide();
+ verticalLab->show();
+ vertical->show();
+ horizontalLab->show();
+ horizontal->show();
+ break;
+ }
+ }
+}
+
+
+
+void LnbConfig::setUniversal()
+{
+ nLO->setButton( 0 );
+ setDual( 0 );
+ slof->setValue( 11700 );
+ lo->setValue( 9750 );
+ hi->setValue( 10600 );
+}
+
+
+
+void LnbConfig::setCBandMono()
+{
+ nLO->setButton( 1 );
+ setDual( 1 );
+ single->setValue( 5150 );
+}
+
+
+
+void LnbConfig::setCBandMulti()
+{
+ nLO->setButton( 2 );
+ setDual( 2 );
+ vertical->setValue( 5150 );
+ horizontal->setValue( 5750 );
+}
+
+
+
+void LnbConfig::accept()
+{
+ switch ( nLO->selectedId() ) {
+ case 0: {
+ lnb->switchFreq = slof->value();
+ lnb->loFreq = lo->value();
+ lnb->hiFreq = hi->value();
+ break;
+ }
+ case 1: {
+ lnb->switchFreq = 0;
+ lnb->hiFreq = 0;
+ lnb->loFreq = single->value();
+ break;
+ }
+ case 2: {
+ lnb->switchFreq = 0;
+ lnb->loFreq = vertical->value();
+ lnb->hiFreq = horizontal->value();
+ break;
+ }
+ }
+ done( Accepted );
+}
+
+
+
+RotorConfig::RotorConfig( Device *d, DVBconfig *c, int lnb, QWidget *parent ) :
+ KDialogBase ( parent, "rotorConfigDialog", true, i18n("Rotor Settings"), Ok|Cancel, Ok, true )
+{
+ int i;
+
+ QWidget *page = new QWidget( this );
+ setMainWidget( page );
+
+ dev = d;
+ config = c;
+ lnbNum = lnb;
+
+ QVBoxLayout *vb = new QVBoxLayout( page, 6, 6 );
+ QGridLayout *grid = new QGridLayout( 0, 1, 1 );
+ QLabel *lab = new QLabel( i18n("Sattelite:"), page );
+ grid->addWidget( lab, 0, 0 );
+ if ( dev->lnb[lnbNum].rotorType==2 ) {
+ lab = new QLabel( i18n("Position:"), page );
+ grid->addWidget( lab, 0, 1 );
+ }
+ srcComb = new QComboBox( page );
+ srcComb->insertStringList( config->getSourcesList( dev->type ) );
+ grid->addWidget( srcComb, 1, 0 );
+ position = new QSpinBox( 0, 500, 1, page );
+ grid->addWidget( position, 1, 1 );
+ vb->addLayout( grid );
+ vb->addItem( new QSpacerItem( 20, 10, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+
+ addBtn = new QPushButton( i18n("Add to list"), page );
+ connect( addBtn, SIGNAL(clicked()), this, SLOT(add()) );
+ vb->addWidget( addBtn );
+ vb->addItem( new QSpacerItem( 20, 10, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+
+ listView = new QListView( page );
+ listView->addColumn( i18n("Sattelite:") );
+ vb->addWidget( listView );
+
+ resetBtn = new QPushButton( i18n("Clear list"), page );
+ connect( resetBtn, SIGNAL(clicked()), this, SLOT(reset()) );
+ vb->addWidget( resetBtn );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+
+ grid = new QGridLayout( 0, 1, 1 );
+ lab = new QLabel( i18n("13V rotor speed:"), page );
+ grid->addWidget( lab, 0, 0 );
+ speed13 = new QLineEdit( page );
+ speed13->setText( QString().setNum( dev->lnb[lnbNum].speed13v ) );
+ grid->addWidget( speed13, 0, 1 );
+ lab = new QLabel( i18n("sec./ °"), page );
+ grid->addWidget( lab, 0, 2 );
+ lab = new QLabel( i18n("18V rotor speed:"), page );
+ grid->addWidget( lab, 1, 0 );
+ speed18 = new QLineEdit( page );
+ speed18->setText( QString().setNum( dev->lnb[lnbNum].speed18v ) );
+ grid->addWidget( speed18, 1, 1 );
+ lab = new QLabel( i18n("sec./ °"), page );
+ grid->addWidget( lab, 1, 2 );
+ vb->addLayout( grid );
+
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
+
+ if ( dev->lnb[lnbNum].rotorType==2 ) {
+ listView->addColumn( i18n("Position:") );
+ for ( i=0; i<(int)dev->lnb[lnbNum].source.count(); i++ )
+ new QListViewItem( listView, dev->lnb[lnbNum].source[i], QString().setNum(dev->lnb[lnbNum].position[i]) );
+ }
+ else {
+ position->hide();
+ for ( i=0; i<(int)dev->lnb[lnbNum].source.count(); i++ )
+ new QListViewItem( listView, dev->lnb[lnbNum].source[i] );
+ }
+
+}
+
+
+
+void RotorConfig::reset()
+{
+ listView->clear();
+ position->setValue( 1 );
+}
+
+
+
+void RotorConfig::add()
+{
+ if ( position->isHidden() ) {
+ new QListViewItem( listView, srcComb->currentText() );
+ }
+ else {
+ new QListViewItem( listView, srcComb->currentText(), QString().setNum(position->value()) );
+ }
+
+}
+
+
+
+void RotorConfig::accept()
+{
+ QListViewItem *it;
+
+ dev->lnb[lnbNum].speed18v = speed18->text().toDouble();
+ dev->lnb[lnbNum].speed13v = speed13->text().toDouble();
+ dev->lnb[lnbNum].source.clear();
+ dev->lnb[lnbNum].position.clear();
+ for ( it=listView->firstChild(); it; it=it->nextSibling() ) {
+ dev->lnb[lnbNum].source.append( it->text(0) );
+ if ( dev->lnb[lnbNum].rotorType==2 )
+ dev->lnb[lnbNum].position.append( it->text(1).toInt() );
+ }
+ done( Accepted );
+}
+
+
+#include "dvbconfig.moc"
diff --git a/kaffeine/src/input/dvb/dvbconfig.h b/kaffeine/src/input/dvb/dvbconfig.h
new file mode 100644
index 0000000..f52b9cc
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbconfig.h
@@ -0,0 +1,301 @@
+/*
+ * dvbconfig.h
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBCONFIG_H
+#define DVBCONFIG_H
+
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qtoolbutton.h>
+#include <qbuttongroup.h>
+#include <qlistview.h>
+
+#include <kdialogbase.h>
+#include <kpushbutton.h>
+#include <kconfig.h>
+#include <kio/job.h>
+#include <kprogress.h>
+
+#include <linux/dvb/frontend.h>
+
+using namespace KIO;
+
+class MSpinBox : public QSpinBox
+{
+ Q_OBJECT
+public:
+ MSpinBox( QWidget *parent, int devNum );
+public slots:
+ void slotValueChanged( int value );
+signals:
+ void signalValueChanged( int value, int devNum );
+private:
+ int deviceNumber;
+};
+
+
+
+class MPushButton : public KPushButton
+{
+ Q_OBJECT
+public:
+ MPushButton( QWidget *parent, int devNum, int lnbNum );
+private slots:
+ void isClicked();
+signals:
+ void clicked( int devnum, int lnbnum );
+private:
+ int deviceNumber;
+ int lnbNumber;
+};
+
+
+
+class MComboBox : public QComboBox
+{
+ Q_OBJECT
+public:
+ MComboBox( QWidget *parent, int devNum, int lnbNum );
+private slots:
+ void isActivated( int index );
+signals:
+ void activated( int index, int devnum, int lnbnum );
+private:
+ int deviceNumber;
+ int lnbNumber;
+};
+
+
+
+class LNB
+{
+public:
+ LNB();
+
+ unsigned int switchFreq;
+ unsigned int loFreq;
+ unsigned int hiFreq;
+ int rotorType;
+ double speed13v, speed18v;
+ QStringList source;
+ QValueList<int> position;
+ QString currentSource;
+};
+
+
+
+class Device
+{
+public:
+ Device( int anum, int tnum, fe_type_t t, const QString &n, bool as );
+ int adapter, tuner;
+ fe_type_t type;
+ QString name;
+ QString source;
+ int numLnb;
+ LNB lnb[4];
+ bool canAutoscan;
+ int tuningTimeout;
+ double usalsLatitude, usalsLongitude;
+};
+
+
+
+class Category
+{
+public:
+ Category( const QString &tname, const QString &ticon );
+ QString name;
+ QString icon;
+};
+
+
+
+class DVBconfig : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ DVBconfig( const QString &dvbConf );
+ ~DVBconfig();
+ void readConfig();
+ void saveConfig();
+ int readDvbChanOrder();
+ void saveDvbChanOrder( int s, int col );
+ void startup();
+ static bool haveDvbDevice();
+ bool loadDvbData( QWidget *parent );
+ bool localData();
+ QStringList getSourcesList( fe_type_t type );
+ bool haveData();
+ bool firstRun();
+ void addCategory( const QString &name, const QString &icon );
+ void removeCategory( const QString &name );
+ void changeIconCategory( const QString &name, const QString &icon );
+
+ KConfig *config;
+ QString recordDir, shiftDir, filenameFormat;
+ int beginMargin, endMargin, instantDuration, sizeFile;
+ QSize epgSize, scanSize, timerSize;
+ QPtrList<Device> devList;
+ QPtrList<Category> categories;
+ QString allIcon, tvIcon, radioIcon;
+ QString dvbConfigDir;
+ QString dvbConfigIconsDir;
+ QString broadcastAddress;
+ int broadcastPort, senderPort;
+ int lastChannel;
+ QValueList<int> splitSizes;
+ QString defaultCharset;
+ double usalsLatitude, usalsLongitude;
+
+private:
+
+ KProgressDialog *downProgress;
+ bool downloadFinished;
+
+private slots:
+
+ void setDownloadResult( KIO::Job *job );
+ void setDownloadPercent( KIO::Job *job, unsigned long percent );
+};
+
+
+
+class KaffeineDvbPlugin;
+
+class DvbConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p );
+ ~DvbConfigDialog();
+ void setSource( QComboBox *box, QString s );
+
+ QLineEdit *recordDirLe, *shiftDirLe, *broadcastLe, *filenameFormatLe;
+ QSpinBox *beginSpin, *endSpin, *instantDurationSpin, *bportSpin, *sportSpin, *sizeFileSpin;
+ MSpinBox *satNumber[8];
+ QComboBox *sat0[8];
+ QComboBox *sat1[8];
+ QComboBox *sat2[8];
+ QComboBox *sat3[8];
+ MPushButton *src0[8];
+ MPushButton *src1[8];
+ MPushButton *src2[8];
+ MPushButton *src3[8];
+ MComboBox *rotor0[8];
+ MComboBox *rotor1[8];
+ MComboBox *rotor2[8];
+ MComboBox *rotor3[8];
+ MPushButton *lnb0[8];
+ MPushButton *lnb1[8];
+ MPushButton *lnb2[8];
+ MPushButton *lnb3[8];
+ KPushButton *updateBtn, *dumpBtn;
+ QToolButton *recordDirBtn, *shiftDirBtn, *helpNameBtn;
+ DVBconfig *dvbConfig;
+ QComboBox *charsetComb;
+ QPtrList<QSpinBox> timeoutSpin;
+
+private slots:
+
+ void fileTemplateHelp();
+ void setRecordDir();
+ void setShiftDir();
+ void satNumberChanged( int value, int devNum );
+ void downloadData();
+ void setLnb( int devNum, int lnbNum );
+ void setRotor( int index, int devNum, int lnbNum );
+ void setRotorSources( int devNum, int lnbNum );
+ void setUsals();
+
+protected slots:
+
+ virtual void accept();
+};
+
+
+
+class LnbConfig : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ LnbConfig( LNB *b, QWidget *parent );
+
+protected slots:
+
+ virtual void accept();
+ void setDual( int id );
+ void setUniversal();
+ void setCBandMono();
+ void setCBandMulti();
+
+private:
+
+ QSpinBox *slof;
+ QSpinBox *lo, *hi, *single, *vertical, *horizontal;
+ QLabel *slofLab, *loLab, *hiLab, *singleLab, *verticalLab, *horizontalLab;
+ QButtonGroup *nLO;
+ QPushButton *univ, *cmono, *cmulti;
+
+ LNB *lnb;
+};
+
+
+
+class RotorConfig : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ RotorConfig( Device *d, DVBconfig *c, int lnb, QWidget *parent );
+
+protected slots:
+
+ virtual void accept();
+
+private slots:
+
+ void reset();
+ void add();
+
+private:
+
+ QSpinBox *position;
+ QComboBox *srcComb;
+ QListView *listView;
+ QPushButton *addBtn, *resetBtn;
+ QLineEdit *speed13, *speed18;
+
+ Device *dev;
+ int lnbNum;
+ DVBconfig *config;
+};
+
+
+#endif /* DVBCONFIG_H */
diff --git a/kaffeine/src/input/dvb/dvbevents.cpp b/kaffeine/src/input/dvb/dvbevents.cpp
new file mode 100644
index 0000000..13e1265
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbevents.cpp
@@ -0,0 +1,424 @@
+/*
+ * dvbevents.cpp
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <qdatetime.h>
+#include <qfile.h>
+
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+
+#include "dvbevents.h"
+
+
+
+DVBevents::DVBevents( QString devType, int anum, int tnum, const QString &charset, EventTable *table )
+ : KaffeineDVBsection( anum, tnum, charset )
+{
+ events = table;
+ KaffeineEpgPlugin *plug;
+ QString plugName;
+ int error;
+
+ KTrader::OfferList offers = KTrader::self()->query("KaffeineEpgPlugin");
+ KTrader::OfferList::Iterator end( offers.end() );
+ for ( KTrader::OfferList::Iterator it=offers.begin(); it!=end; ++it ) {
+ error = 0;
+ KService::Ptr ptr = (*it);
+ if ( !ptr->name().contains(devType) )
+ continue;
+ plug = KParts::ComponentFactory::createPartInstanceFromService<KaffeineEpgPlugin>(ptr, 0, ptr->name().ascii(), 0, 0, 0, &error );
+ plugName = ptr->desktopEntryName();
+ if (error > 0) {
+ fprintf( stderr, "Loading of EPG plugin %s failed: %s\n", plugName.ascii(), KLibLoader::self()->lastErrorMessage().ascii() );
+ plug = NULL;
+ }
+ else {
+ plugs.append( plug );
+ plug->setTable( table );
+ plug->initSection( anum, tnum, charset );
+ plugNames.append( plugName );
+ }
+ }
+ fprintf( stderr, "%d EPG plugins loaded for device %d:%d.\n", plugs.count(), anum, tnum );
+}
+
+
+
+DVBevents::~DVBevents()
+{
+ int i;
+
+ isRunning = false;
+ if ( !wait(2000) ) {
+ terminate();
+ wait();
+ }
+ for ( i=0; i<(int)plugs.count(); ++i ) {
+ plugs.at(i)->stop();
+ KService::Ptr service = KService::serviceByDesktopName( plugNames[i] );
+ KLibLoader::self()->unloadLibrary( service->library().ascii() );
+ }
+}
+
+
+
+bool DVBevents::shortEventDesc( unsigned char *buf, EventDesc *desc )
+{
+ QString name, text;
+ int len, len2;
+ ShortEvent *ev;
+
+ if ( !safeLen( buf+6 ) )
+ return false;
+ len = getBits(buf,40,8);
+ if ( !safeLen( buf+6+len ) )
+ return false;
+ name = getText( buf+6, len );
+ if ( !safeLen( buf+6+len+1 ) )
+ return false;
+ len2 = getBits(buf+6+len,0,8);
+ if ( !safeLen( buf+7+len+len2 ) )
+ return false;
+ text = getText( buf+7+len, len2);
+ if ( desc->title.isEmpty() ) {
+ desc->title=name;
+ desc->subtitle=text;
+ return true;
+ }
+ desc->shortEvents.append( new ShortEvent() );
+ ev = desc->shortEvents.getLast();
+ ev->name = name;
+ ev->text = text;
+ return true;
+}
+
+
+
+bool DVBevents::extEventDesc( unsigned char *buf, EventDesc *desc )
+{
+ int loop, len1, len2;
+ unsigned char *b = buf;
+ QString s;
+
+ if ( !safeLen( b+7 ) )
+ return false;
+ loop = getBits(b+6,0,8);
+ b +=7;
+
+ while ( loop>0 ) {
+ if ( !safeLen( b+1 ) )
+ return false;
+ len1 = getBits(b,0,8);
+ if ( !safeLen( b+1+len1 ) )
+ return false;
+ s = getText(b+1,len1);
+ if ( !safeLen( b+1+len1+1 ) )
+ return false;
+ len2 = getBits(b+1+len1,0,8);
+ if ( !safeLen( buf+2+len1+len2 ) )
+ return false;
+ if ( !s.isEmpty() )
+ s = s+" : ";
+ s = s+getText(b+2+len1,len2);
+ desc->extEvents.append( new QString( s ) );
+ b +=(2+len1+len2);
+ loop -=(2+len1+len2);
+ }
+ if ( !safeLen( b+1 ) )
+ return false;
+ len1 = getBits(b,0,8);
+ if ( !safeLen( b+1+len1 ) )
+ return false;
+ s = getText(b+1,len1);
+ desc->extEvents.append( new QString( s ) );
+ return true;
+}
+
+
+
+bool DVBevents::tableEIT( unsigned char* buffer )
+{
+ unsigned char* buf = buffer;
+ unsigned int length, loop, sid, tid, eid, tsid, sn, lsn, nid;
+ int i, sec;
+ EventDesc *desc=0, *itdesc=0;
+ EventSid *slist;
+ QPtrList<EventDesc> *currentEvents;
+ bool nodesc, parse;
+ QDateTime start, cur, dt;
+ unsigned int cdt = QDateTime::currentDateTime().toTime_t();
+
+ tid = getBits(buf,0,8);
+ length = getBits(buf,12,12);
+ sid = getBits(buf,24,16);
+ sn = getBits(buf,48,8);
+ lsn = getBits(buf,56,8);
+ tsid = getBits(buf,64,16);
+ nid = getBits(buf,80,16);
+ length -=11;
+ buf +=14;
+
+ slist = currentSrc->getEventSid( nid, tsid, sid );
+ if ( !slist )
+ return false;
+ slist->lock();
+ currentEvents = slist->getEvents();
+ QPtrListIterator<EventDesc> it( *currentEvents );
+
+ while ( length>4 ) {
+ nodesc=parse=false;
+ if ( !safeLen( buf+2 ) )
+ goto stop;
+ eid = getBits(buf,0,16);
+ if ( !safeLen( buf+2+5 ) )
+ goto stop;
+ start = getDateTime( buf+2 );
+ nodesc=parse=true;
+
+ it.toFirst();
+ while ( (desc=it.current())!=0 ) {
+ if ( desc->sid==sid ) {
+ if ( desc->startDateTime==start || desc->eid==eid ) {
+ if ( desc->tid==0x4e && tid!=0x4e ) {
+ parse = false;
+ nodesc = false;
+ break;
+ }
+ else {
+ nodesc = false;
+ if ( (cdt-desc->loop)<300 ) { // only reparse events every 300 seconds
+ parse = false;
+ }
+ else {
+ desc->extEvents.clear();
+ desc->shortEvents.clear();
+ desc->title=desc->subtitle="";
+ }
+ break;
+ }
+ }
+ }
+ ++it;
+ }
+
+ if ( nodesc )
+ desc = new EventDesc();
+ if ( parse ) {
+ if ( !safeLen( buf+10 ) )
+ goto stop;
+ desc->duration = getTime( buf+7 );
+ if ( !safeLen( buf+11 ) )
+ goto stop;
+ desc->running = getBits(buf,80,3);
+ desc->sid = sid;
+ desc->tid = tid;
+ desc->tsid = tsid;
+ desc->nid = nid;
+ desc->lsn = lsn;
+ desc->sn = sn;
+ desc->eid = eid;
+ desc->loop = cdt;
+ }
+
+ if ( desc->sn != sn ) {
+ slist->unlock();
+ return false;
+ }
+ if ( !safeLen( buf+12 ) )
+ goto stop;
+ loop = getBits(buf,84,12);
+ buf +=12;
+ length -=(12+loop);
+ while ( loop>0 ) {
+ if ( parse ) {
+ if ( !safeLen( buf+1 ) )
+ goto stop;
+ switch ( getBits(buf,0,8) ) {
+ case 0x4D :
+ if ( !shortEventDesc( buf, desc ) )
+ goto stop;
+ break;
+ case 0x4E :
+ if ( !extEventDesc( buf, desc ) )
+ goto stop;
+ break;
+ default :
+ break;
+ }
+ }
+ if ( !safeLen( buf+2 ) )
+ goto stop;
+ loop -=( getBits(buf,8,8)+2 );
+ buf +=( getBits(buf,8,8)+2 );
+ }
+//out:
+ if ( parse ) {
+ if ( !nodesc ) {
+ if ( start==desc->startDateTime )
+ goto ifend;
+ currentEvents->take( currentEvents->find( desc ) );
+ }
+ desc->startDateTime = start;
+ for ( i=0; i<(int)currentEvents->count(); i++ ) {
+ itdesc = currentEvents->at(i);
+ if ( desc->startDateTime<itdesc->startDateTime ) {
+ currentEvents->insert( i, desc );
+ break;
+ }
+ itdesc = 0;
+ }
+ if ( !itdesc )
+ currentEvents->append( desc );
+ }
+ifend:
+ if ( parse )
+ ++(desc->sn);
+ if ( nodesc ) {
+ cur = QDateTime::currentDateTime();
+ dt = desc->startDateTime;
+ sec = desc->duration.hour()*3600+desc->duration.minute()*60+desc->duration.second();
+ if ( dt.addSecs( sec )<cur || desc->title.length()<3 ) {
+ currentEvents->remove( desc );
+ }
+ else
+ desc->source = currentSrc->getSource();
+ }
+
+ }
+ slist->unlock();
+ return true;
+stop:
+ slist->unlock();
+ fprintf( stderr, "Stop parsing EIT (%d:%d)\n", adapter, tuner );
+ if ( nodesc )
+ delete desc;
+ return false;
+}
+
+
+
+
+bool DVBevents::safeLen( unsigned char* buf )
+{
+ if ( buf<(secbuf+readSize) )
+ return true;
+ fprintf( stderr, "EIT (%d:%d) : buffer overflow! Rejected\n", adapter, tuner );
+ return false;
+}
+
+
+
+bool DVBevents::go( QString src, int freqKHz, bool all )
+{
+ int tid, i;
+
+ if ( isRunning )
+ return true;
+
+ if ( all )
+ tid = 0;
+ else
+ tid = 0x4e;
+
+ currentSrc = events->getEventSource( src );
+
+ if ( !setFilter( 0x12, tid, 1000 ) )
+ return false;
+ isRunning = true;
+ start();
+ fprintf(stderr,"dvbEvents %d:%d started\n", adapter, tuner);
+
+ for ( i=0; i<(int)plugs.count(); ++i ) {
+ plugs.at(i)->go( src, freqKHz );
+ }
+
+ return true;
+}
+
+
+
+void DVBevents::stop()
+{
+ int i;
+
+ if ( !isRunning )
+ return;
+
+ isRunning = false;
+ if ( !wait(2000) ) {
+ terminate();
+ wait();
+ fprintf(stderr,"dvbEvents %d:%d terminated\n", adapter, tuner);
+ }
+ else
+ fprintf(stderr,"dvbEvents %d:%d ended\n", adapter, tuner);
+ stopFilter();
+
+ for ( i=0; i<(int)plugs.count(); ++i ) {
+ plugs.at(i)->stop();
+ }
+}
+
+
+
+void DVBevents::run()
+{
+ int n=0, tid;
+ int skip=0;
+
+ setpriority(PRIO_PROCESS, 0, 19); // eit parsing is cpu eater on some astra multiplex.
+ while ( isRunning ) {
+ if ( !isRunning )
+ break;
+
+ if ( poll(pf,1,1000)>0 ){
+ if ( pf[0].revents & POLLIN ){
+ n = read( fdDemux, secbuf, 4096 );
+ skip = 0;
+ }
+ else
+ skip++;
+ }
+ else
+ skip++;
+
+ if (skip)
+ continue;
+ if ( n<16 )
+ continue;
+ else
+ readSize = n;
+
+ if ( !isRunning )
+ break;
+
+ tid = getBits(secbuf,0,8);
+ if ( tid>0x4D && tid<0x70 ) {
+ tableEIT( secbuf );
+ }
+ }
+}
diff --git a/kaffeine/src/input/dvb/dvbevents.h b/kaffeine/src/input/dvb/dvbevents.h
new file mode 100644
index 0000000..e5d693d
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbevents.h
@@ -0,0 +1,59 @@
+/*
+ * dvbevents.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBEVENTS_H
+#define DVBEVENTS_H
+
+#include <qptrlist.h>
+
+#include "kaffeinedvbsection.h"
+#include "kaffeinedvbevents.h"
+
+
+
+class DVBevents : public KaffeineDVBsection
+{
+
+public:
+
+ DVBevents( QString devType, int anum, int tnum, const QString &charset, EventTable *table );
+ ~DVBevents();
+ bool go( QString src, int freqKHz, bool all=false );
+ void stop();
+
+private:
+
+ virtual void run();
+ bool tableEIT( unsigned char* buffer );
+ bool shortEventDesc( unsigned char *buf, EventDesc *desc );
+ bool extEventDesc( unsigned char *buf, EventDesc *desc );
+ bool safeLen( unsigned char* buf );
+
+ unsigned char secbuf[4096];
+ int readSize;
+
+ EventTable *events;
+ EventSource *currentSrc;
+
+ QPtrList<KaffeineEpgPlugin> plugs;
+ QStringList plugNames;
+};
+
+#endif /* DVBEVENTS_H */
diff --git a/kaffeine/src/input/dvb/dvbout.cpp b/kaffeine/src/input/dvb/dvbout.cpp
new file mode 100644
index 0000000..0ede057
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbout.cpp
@@ -0,0 +1,568 @@
+/*
+ * dvbout.cpp
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <fcntl.h>
+
+#include <kstandarddirs.h>
+
+#include "dvbout.h"
+#include "kaffeinedvbplugin.h"
+
+#define NTS 64
+
+DVBout::DVBout( ChannelDesc chan, int anum, int tnum, KaffeineDvbPlugin *p )
+{
+ bool bok;
+ bok = true;
+ unsigned int i, j=0, k;
+
+ for( i = 0 ; i < 256 ; i++ ) {
+ k = 0;
+ for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) {
+ k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
+ }
+ CRC32[i] = k;
+ }
+
+ plug = 0;
+ if ( p ) {
+ plug = p;
+ plugHandle = plug->init( chan.sid, anum, tnum, chan.fta );
+ }
+
+ fdPipe=0;
+ channel = chan;
+ thWrite = 0;
+ rtp = 0;
+ if ( channel.vpid )
+ pids.append( channel.vpid );
+ for ( i=0; i<channel.napid && i<MAX_AUDIO; i++ )
+ pids.append( channel.apid[i].pid );
+ for ( i=0; i<channel.nsubpid && i<MAX_DVBSUB; i++ )
+ pids.append( channel.subpid[i].pid );
+ wBuf = NULL;
+ timeShifting = beginLive = false;
+ haveRec = haveLive = instantRec = haveBroadcast = false;
+ patpmt = wpatpmt = false;
+ connect( &stopRecTimer, SIGNAL(timeout()), this, SLOT(stopRec()) );
+ connect( &timerPatPmt, SIGNAL(timeout()), this, SLOT(setPatPmt()) );
+ if ( !pids.contains(8192) )
+ timerPatPmt.start(500);
+}
+
+
+
+void DVBout::calculateCRC( unsigned char *p_begin, unsigned char *p_end )
+{
+ unsigned int i_crc = 0xffffffff;
+
+ // Calculate the CRC
+ while( p_begin < p_end ) {
+ i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((unsigned int)*p_begin) ];
+ p_begin++;
+ }
+
+ // Store it after the data
+ p_end[0] = (i_crc >> 24) & 0xff;
+ p_end[1] = (i_crc >> 16) & 0xff;
+ p_end[2] = (i_crc >> 8) & 0xff;
+ p_end[3] = (i_crc >> 0) & 0xff;
+}
+
+
+
+void DVBout::writePat()
+{
+ int i;
+
+ tspat[0x00] = 0x47; // sync_byte
+ tspat[0x01] = 0x40;
+ tspat[0x02] = 0x00; // PID = 0x0000
+ tspat[0x03] = 0x10; // | (ps->pat_counter & 0x0f);
+ tspat[0x04] = 0x00; // pointer_field. CRC calculation begins here
+ tspat[0x05] = 0x00; // 0x00: Program association section
+ tspat[0x06] = 0xb0;
+ tspat[0x07] = 0x11; // section_length = 0x011
+ tspat[0x08] = 0x00;
+ tspat[0x09] = 0xbb; // TS id = 0x00b0 (what the vlc calls "Stream ID")
+ tspat[0x0a] = 0xc1;
+ // section # and last section #
+ tspat[0x0b] = tspat[0x0c] = 0x00;
+ // Network PID (useless)
+ tspat[0x0d] = tspat[0x0e] = 0x00; tspat[0x0f] = 0xe0; tspat[0x10] = 0x10;
+ // Program Map PID
+ pmtpid = 0xff;
+ while ( pids.contains( pmtpid ) ) pmtpid--;
+ tspat[0x11] = 0x03; tspat[0x12] = 0xe8; tspat[0x13] = 0xe0; tspat[0x14] = pmtpid;
+ // Put CRC in ts[0x15...0x18]
+ calculateCRC( tspat + 0x05, tspat + 0x15 );
+ // needed stuffing bytes
+ for (i=0x19 ; i < 188 ; i++) tspat[i]=0xff;
+}
+
+
+
+void DVBout::writePmt()
+{
+ int i, off=0;
+
+ tspmt[0x00] = 0x47; //sync_byte
+ tspmt[0x01] = 0x40;
+ tspmt[0x02] = pmtpid;
+ tspmt[0x03] = 0x10;
+ tspmt[0x04] = 0x00; // pointer_field. CRC calculation begins here
+ tspmt[0x05] = 0x02; // 0x02: Program map section
+ tspmt[0x06] = 0xb0;
+ tspmt[0x07] = 0x20; // section_length
+ tspmt[0x08] = 0x03;
+ tspmt[0x09] = 0xe8; // prog number
+ tspmt[0x0a] = 0xc1;
+ // section # and last section #
+ tspmt[0x0b] = tspmt[0x0c] = 0x00;
+ // PCR PID
+ tspmt[0x0d] = channel.vpid>>8; tspmt[0x0e] = channel.vpid&0xff;
+ // program_info_length == 0
+ tspmt[0x0f] = 0xf0; tspmt[0x10] = 0x00;
+ // Program Map / Video PID
+ tspmt[0x11] = channel.vType; // video stream type
+ tspmt[0x12] = channel.vpid>>8; tspmt[0x13] = channel.vpid&0xff;
+ tspmt[0x14] = 0xf0; tspmt[0x15] = 0x09; // es info length
+ // useless info
+ tspmt[0x16] = 0x07; tspmt[0x17] = 0x04; tspmt[0x18] = 0x08; tspmt[0x19] = 0x80;
+ tspmt[0x1a] = 0x24; tspmt[0x1b] = 0x02; tspmt[0x1c] = 0x11; tspmt[0x1d] = 0x01;
+ tspmt[0x1e] = 0xfe;
+ off = 0x1e;
+ // audio pids
+ i = 0;
+ for ( i=0; i<channel.napid && i<MAX_AUDIO; i++ ) {
+ if ( channel.apid[i].ac3 ) {
+ tspmt[++off] = 0x81; // stream type = xine see this as ac3
+ tspmt[++off] = channel.apid[i].pid>>8; tspmt[++off] = channel.apid[i].pid&0xff;
+ tspmt[++off] = 0x00; tspmt[++off] = 0x0c; // es info length
+ tspmt[++off] = 0x05; tspmt[++off] = 0x04; tspmt[++off] = 0x41;
+ tspmt[++off] = 0x43; tspmt[++off] = 0x2d; tspmt[++off] = 0x33;
+ }
+ else {
+ tspmt[++off] = 0x04; // stream type = audio
+ tspmt[++off] = channel.apid[i].pid>>8; tspmt[++off] = channel.apid[i].pid&0xff;
+ tspmt[++off] = 0xf0; tspmt[++off] = 0x06; // es info length
+ }
+ tspmt[++off] = 0x0a; // iso639 descriptor tag
+ tspmt[++off] = 0x04; // descriptor length
+ if ( !channel.apid[i].lang.isEmpty() ) {
+ tspmt[++off] = channel.apid[i].lang.constref(0);
+ tspmt[++off] = channel.apid[i].lang.constref(1);
+ if ( channel.apid[i].ac3 )
+ tspmt[++off] = '_';
+ else
+ tspmt[++off] = channel.apid[i].lang.constref(2);
+ }
+ else if ( channel.apid[i].ac3 ) {
+ tspmt[++off] = 'd';
+ tspmt[++off] = 'd';
+ tspmt[++off] = 49+i;
+ }
+ else {
+ tspmt[++off] = 'c';
+ tspmt[++off] = 'h';
+ tspmt[++off] = 49+i;
+ }
+ tspmt[++off] = 0x00; // audio type
+ }
+ // Subtitles
+ for ( i=0; i<channel.nsubpid && i<MAX_DVBSUB; i++ ) {
+ tspmt[++off] = 0x06; // stream type = ISO_13818_PES_PRIVATE
+ tspmt[++off] = channel.subpid[i].pid>>8; tspmt[++off] = channel.subpid[i].pid&0xff;
+ tspmt[++off] = 0xf0; tspmt[++off] = 0x0a; // es info length
+ tspmt[++off] = 0x59; //DVB sub tag
+ tspmt[++off] = 0x08; // descriptor length
+ if ( !channel.subpid[i].lang.isEmpty() ) {
+ tspmt[++off] = channel.subpid[i].lang.constref(0);
+ tspmt[++off] = channel.subpid[i].lang.constref(1);
+ tspmt[++off] = channel.subpid[i].lang.constref(2);
+ }
+ else {
+ tspmt[++off] = 'c';
+ tspmt[++off] = 'h';
+ tspmt[++off] = 49+i;
+ }
+ tspmt[++off] = channel.subpid[i].type; //sub type
+ tspmt[++off] = channel.subpid[i].page>>8; tspmt[++off] = channel.subpid[i].page&0xff; // comp_page_id
+ tspmt[++off] = channel.subpid[i].id>>8; tspmt[++off] = channel.subpid[i].id&0xff; // anc_page_id
+ }
+ tspmt[0x07] = off-3; // update section_length
+ // Put CRC in ts[0x29...0x2c]
+ calculateCRC( tspmt+0x05, tspmt+off+1 );
+ // needed stuffing bytes
+ for (i=off+5 ; i < 188 ; i++) tspmt[i]=0xff;
+}
+
+
+
+bool DVBout::hasInstantRec() const
+{
+ return instantRec;
+}
+
+
+
+bool DVBout::hasRec() const
+{
+ return haveRec;
+}
+
+
+
+bool DVBout::hasLive() const
+{
+ if ( haveLive || fdPipe || timeShifting )
+ return true;
+ return false;
+}
+
+
+
+bool DVBout::hasBroadcast() const
+{
+ return haveBroadcast;
+}
+
+
+
+bool DVBout::doPause( const QString &name ) // called from dvbstream::run()
+{
+ if ( !haveLive )
+ return false;
+
+ if ( !timeShifting ) {
+ liveFile.setName( name );
+ liveFile.open( IO_WriteOnly|IO_Truncate );
+ liveFile.writeBlock( (char*)tspat, TS_SIZE );
+ liveFile.writeBlock( (char*)tspmt, TS_SIZE );
+ mutex.lock();
+ haveLive = false;
+ mutex.unlock();
+ if ( !wait(100) ) {
+ terminate();
+ wait();
+ }
+ mutex.lock();
+ haveLive = true;
+ if ( close( fdPipe )<0 )
+ perror("close out pipe: ");
+ else
+ fprintf(stderr,"out pipe closed\n");
+ fdPipe = 0;
+ mutex.unlock();
+ timeShifting = true;
+ //emit shifting( timeShifting );
+ }
+ return true;
+}
+
+
+
+void DVBout::setPatPmt()
+{
+ patpmt = true;
+}
+
+
+
+bool DVBout::goLive( const QString &name )
+{
+ if ( fdPipe ) return false;
+
+ haveLive = true;
+ pipeName = name;
+ beginLive = true;
+ //activeApid = napid;
+
+ writePat();
+ writePmt();
+ if ( !pids.contains(8192) )
+ patpmt = wpatpmt = true;
+ wBuf = new unsigned char[TS_SIZE*NTS*100];
+ if ( !wBuf ) fprintf( stderr, "\nNO WBUF !!!\n\n" );
+ wRead = wWrite = wDist = 0;
+ start();
+ return true;
+}
+
+
+
+void DVBout::preStopLive()
+{
+ mutex.lock();
+ haveLive = false;
+ mutex.unlock();
+}
+
+
+
+void DVBout::stopLive()
+{
+ mutex.lock();
+ if ( timeShifting ) {
+ liveFile.close();
+ timeShifting = false;
+ emit shifting( timeShifting );
+ }
+ mutex.unlock();
+ if ( !wait(500) ) {
+ terminate();
+ wait();
+ }
+ if ( fdPipe ) {
+ close( fdPipe );
+ fprintf( stderr, "pipe closed\n" );
+ fdPipe = 0;
+ }
+ delete [] wBuf;
+ wBuf = NULL;
+}
+
+
+
+bool DVBout::goBroadcast( Ts2Rtp *r )
+{
+ if ( haveBroadcast ) return false;
+ fprintf(stderr,"Start Broadcast: %s\n", channel.name.ascii() );
+ rtp = r;
+ haveBroadcast = true;
+ return true;
+}
+
+
+
+void DVBout::stopBroadcast()
+{
+ if ( !haveBroadcast ) return;
+ fprintf(stderr,"Stop Broadcast: %s\n", channel.name.ascii() );
+ mutex.lock();
+ rtp->removeChannels();
+ haveBroadcast = false;
+ mutex.unlock();
+}
+
+
+
+bool DVBout::goRec( const QString &name, int maxsize, RecTimer *t )
+{
+ QString fname=name;
+
+ if ( haveRec )
+ return false;
+
+ recTimer = t;
+ fileName=name;
+ fileNumber=0;
+
+ if (maxsize>0) {
+ fileMaxSize = (long long int)1048576*(long long int)maxsize;
+ fname=fileName+"_"+QString().setNum(fileNumber);
+ }
+ else {
+ fileMaxSize = 0;
+ fname=fileName;
+ }
+ if ( QFile(fname+".m2t").exists() )
+ renameFile( fname, ".m2t" );
+ writePat();
+ writePmt();
+ if ( channel.apid[0].pid!=8192 )
+ patpmt = true;
+ outFile.setName( fname+".m2t" );
+ if ( !outFile.open( IO_WriteOnly | IO_Truncate ) )
+ return false;
+ outFile.writeBlock( (char*)tspat, TS_SIZE );
+ outFile.writeBlock( (char*)tspmt, TS_SIZE );
+ recTimer->fullPath = fname+".m2t";
+
+ haveRec = true;
+ if ( recTimer ) {
+ QTime t = recTimer->duration.addSecs( QDateTime::currentDateTime().secsTo(recTimer->begin) );
+ stopRecTimer.start( QTime().msecsTo( t ), true );
+ }
+ else
+ instantRec = true;
+ fprintf( stderr, "Recording started: %s\n", channel.name.latin1() );
+ return true;
+}
+
+
+
+void DVBout::renameFile( QString &name, const QString &ext )
+{
+ int index=1;
+
+ while ( QFile(name+"-"+QString().setNum(index)+ext).exists() )
+ index++;
+
+ name = name+"-"+QString().setNum(index);
+}
+
+
+
+void DVBout::changeTimer( int ms )
+{
+ if ( stopRecTimer.isActive() )
+ stopRecTimer.changeInterval( ms );
+}
+
+
+
+void DVBout::stopRec()
+{
+ if ( !haveRec )
+ return;
+
+ if ( stopRecTimer.isActive() )
+ stopRecTimer.stop();
+ mutex.lock();
+ outFile.close();
+ mutex.unlock();
+ haveRec = instantRec = false;
+ fprintf( stderr, "Recording stopped: %s\n", channel.name.latin1() );
+ if ( !haveLive && !haveBroadcast )
+ emit endRecord( this, recTimer, true );
+ else
+ emit endRecord( this, recTimer, false );
+}
+
+
+
+void DVBout::process( unsigned char *buf, int size )
+{
+ int i, pid;
+ unsigned char *buffer=buf;
+ QString fname;
+
+ for ( i=0; i<size; i+=TS_SIZE ) {
+ pid = (((buffer[1] & 0x1f) << 8) | buffer[2]);
+ if ( pids.contains( pid ) || pids.contains( 8192) ) {
+ memcpy( thBuf+thWrite, buffer, TS_SIZE );
+ thWrite+=TS_SIZE;
+ if ( thWrite==(TS_SIZE*NTS ) ) {
+ if ( plug && plugHandle )
+ plug->process( plugHandle, thBuf, TS_SIZE*NTS );
+ mutex.lock();
+ if ( haveLive && fdPipe ) {
+ if ( beginLive ) {
+ beginLive = !beginLive;
+ start();
+ }
+ if ( wDist<95 ) {
+ memcpy( wBuf+(wWrite*TS_SIZE*NTS), thBuf, TS_SIZE*NTS );
+ wpatpmt = patpmt;
+ ++wDist;
+ ++wWrite;
+ if ( wWrite>99 )
+ wWrite = 0;
+ //fprintf(stderr,"WDIST = %d\n",wDist);
+ }
+ }
+ else if ( timeShifting ) {
+ if ( patpmt ) {
+ liveFile.writeBlock( (char*)tspat, TS_SIZE );
+ liveFile.writeBlock( (char*)tspmt, TS_SIZE );
+ }
+ liveFile.writeBlock( (char*)thBuf, TS_SIZE*NTS );
+ }
+ if ( haveRec && fileNumber>=0 ) {
+ if ((fileMaxSize>0)&&(outFile.size()>=fileMaxSize)) {
+ outFile.close();
+ fileNumber++;
+ fname=fileName+"_"+QString().setNum(fileNumber);
+ if (QFile(fname+"_"+QString().setNum(fileNumber)+".m2t").exists() )
+ renameFile( fname, ".m2t" );
+
+ outFile.setName( fname+".m2t" );
+ if ( !outFile.open( IO_WriteOnly | IO_Truncate ) )
+ fileNumber=-1;
+ else
+ {
+ outFile.writeBlock( (char*)tspat, TS_SIZE );
+ outFile.writeBlock( (char*)tspmt, TS_SIZE );
+ recTimer->fullPath = fname+".m2t";
+ }
+ }
+ if (fileNumber>=0)
+ {
+ if ( patpmt ) {
+ outFile.writeBlock( (char*)tspat, TS_SIZE );
+ outFile.writeBlock( (char*)tspmt, TS_SIZE );
+ }
+ outFile.writeBlock( (char*)thBuf, TS_SIZE*NTS );
+ }
+
+ }
+ if ( haveBroadcast )
+ rtp->process( thBuf, TS_SIZE*NTS );
+ patpmt = false;
+ mutex.unlock();
+ thWrite = 0;
+ }
+ }
+ buffer+=TS_SIZE;
+ }
+}
+
+
+
+void DVBout::run()
+{
+ if ( haveLive && fdPipe ) {
+ while ( haveLive && fdPipe ) {
+ if ( wDist>0 ) {
+ if ( wpatpmt ) {
+ write( fdPipe, tspat, TS_SIZE );
+ write( fdPipe, tspmt, TS_SIZE );
+ wpatpmt = false;
+ }
+ write( fdPipe, wBuf+(wRead*TS_SIZE*NTS), TS_SIZE*NTS );
+ --wDist;
+ ++wRead;
+ if ( wRead>99 )
+ wRead = 0;
+ }
+ else
+ usleep( 100 );
+ }
+ return;
+ }
+
+ if ( (fdPipe=open( pipeName.ascii(), O_WRONLY))<0 ) {
+ perror("PIPE FILE: ");
+ return;
+ }
+ fprintf(stderr,"pipe opened\n");
+ emit playDvb();
+}
+
+
+
+DVBout::~DVBout()
+{
+ if ( plug )
+ plug->close( plugHandle );
+}
+
+#include "dvbout.moc"
diff --git a/kaffeine/src/input/dvb/dvbout.h b/kaffeine/src/input/dvb/dvbout.h
new file mode 100644
index 0000000..bc97b47
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbout.h
@@ -0,0 +1,118 @@
+/*
+ * dvbout.h
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBOUT_H
+#define DVBOUT_H
+
+#include <qobject.h>
+#include <qthread.h>
+#include <qmutex.h>
+#include <qstring.h>
+#include <qfile.h>
+#include <qtimer.h>
+#include <qvaluelist.h>
+
+#include "channeldesc.h"
+#include "ts2rtp.h"
+#include "gdvb.h"
+
+class KaffeineDvbPlugin;
+
+class DVBout : public QObject, public QThread
+{
+ Q_OBJECT
+
+public:
+
+ DVBout( ChannelDesc chan, int anum, int tnum, KaffeineDvbPlugin *p );
+ ~DVBout();
+ void process( unsigned char *buf, int size );
+ bool goLive( const QString &name );
+ void preStopLive();
+ void stopLive();
+ bool goBroadcast( Ts2Rtp *r );
+ void stopBroadcast();
+ bool goRec( const QString &name, int maxsize, RecTimer *t );
+ bool hasRec() const;
+ bool hasLive() const;
+ bool hasBroadcast() const;
+ bool hasInstantRec() const;
+ bool timeShiftMode() const;
+ bool doPause( const QString &name );
+ void changeTimer( int ms );
+ QValueList<int> pidsList() { return pids; }
+
+ ChannelDesc channel;
+ QValueList<int> dmx, pids;
+ RecTimer *recTimer;
+
+public slots:
+
+ void stopRec();
+
+private slots:
+
+ void setPatPmt();
+
+private:
+
+ void writePmt();
+ void writePat();
+ void calculateCRC( unsigned char *p_begin, unsigned char *p_end );
+ void renameFile( QString &name, const QString &ext );
+
+ int pmtpid;
+ bool patpmt, wpatpmt;
+ bool timeShifting;
+ QString pipeName;
+ QFile outFile, liveFile;
+ int fdPipe;
+ Ts2Rtp *rtp;
+ unsigned char thBuf[188*100];
+ unsigned char *wBuf;
+ int wRead, wWrite, wDist;
+ unsigned char tspat[188];
+ unsigned char tspmt[188];
+ unsigned int CRC32[256];
+ int thWrite;
+ bool beginLive;
+ bool haveRec, haveLive, instantRec, haveBroadcast;
+ QTimer stopRecTimer, timerPatPmt;
+ QMutex mutex;
+ KaffeineDvbPlugin *plug;
+ void *plugHandle;
+
+ int fileNumber;
+ QString fileName;
+ long long int fileMaxSize;
+
+signals:
+
+ void playDvb();
+ void endRecord(DVBout*, RecTimer*, bool);
+ void shifting(bool);
+
+protected:
+
+ virtual void run();
+
+};
+
+#endif /* DVBOUT_H */
diff --git a/kaffeine/src/input/dvb/dvbpanel.cpp b/kaffeine/src/input/dvb/dvbpanel.cpp
new file mode 100644
index 0000000..4d70760
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbpanel.cpp
@@ -0,0 +1,2673 @@
+/*
+ * dvbpanel.cpp
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <sys/statvfs.h>
+
+#include <qlayout.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qstringlist.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <qapplication.h>
+#include <qpopupmenu.h>
+#include <qmap.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kinputdialog.h>
+#include <kicondialog.h>
+#include <kaction.h>
+#include <kprocess.h>
+#include <kfiledialog.h>
+#include <ktrader.h>
+#include <kxmlguifactory.h>
+#include <kparts/componentfactory.h>
+
+#include "kaffeineinput.h"
+#include "kaffeinedvbplugin.h"
+#include "dvbpanel.h"
+#include "channeldesc.h"
+#include "dvbstream.h"
+#include "kevents.h"
+#include "broadcasteditor.h"
+#include "channeleditor.h"
+
+#define CHANICONSIZE 28
+
+
+
+DIconViewItem::DIconViewItem( DvbPanel *pan, QIconView *parent, const QString &text, const QPixmap &icon )
+ : KIconViewItem( parent, text, icon )
+{
+ panel = pan;
+}
+
+
+
+void DIconViewItem::dropped( QDropEvent *e, const QValueList<QIconDragItem> & )
+{
+ QString s;
+
+ if ( !dropEnabled() )
+ return;
+ if ( QTextDrag::decode( e, s ) )
+ panel->moveChannel( text(), s );
+}
+
+
+
+DListView::DListView( QWidget *parent ) : KListView( parent )
+{
+ visibleItems = 0;
+}
+
+
+
+QDragObject* DListView::dragObject()
+{
+ if ( currentItem() )
+ return new QTextDrag( currentItem()->text(1), this );
+ else
+ return 0;
+}
+
+
+
+DvbPanel::DvbPanel( QWidget *parent, QObject *objParent, const char *name ) : KaffeineInput(objParent,name)
+{
+ browseDvbStream = -1;
+ plug = NULL;
+
+ isTuning = false;
+ timeShiftFileName = "";
+ timersDialog = 0;
+ currentCategory = "All";
+ channels.setAutoDelete( true );
+ timers.setAutoDelete( true );
+ dvb.setAutoDelete( true );
+
+ mainWidget = new QVBox( parent );
+ mainWidget->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred) );
+ split = new QSplitter( mainWidget );
+ split->setOpaqueResize( true );
+ pbox = new QVBox( split );
+ iconView = new KIconView( pbox );
+ iconView->setVScrollBarMode( QScrollView::AlwaysOff );
+ iconView->setHScrollBarMode( QScrollView::AlwaysOff );
+ iconView->horizontalScrollBar()->setFixedHeight( 0 );
+ connect( iconView, SIGNAL(rightButtonPressed(QIconViewItem*,const QPoint&)), this, SLOT(catContextMenu(QIconViewItem*,const QPoint&)) );
+ connect( iconView, SIGNAL(clicked(QIconViewItem*)), this, SLOT(catSelected(QIconViewItem*)) );
+ iconView->setArrangement(QIconView::TopToBottom);
+ iconView->setMargin(0);
+ iconView->setSpacing(0);
+ iconView->setItemsMovable(false);
+ iconView->setResizeMode(QIconView::Adjust);
+ iconView->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Minimum ) );
+ playerBox = new QVBox( pbox );
+ playerBox->setMinimumWidth( 200 );
+ panel = new QFrame( split );
+ panel->setLineWidth(1);
+ panel->setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ split->moveToFirst( panel );
+ split->setResizeMode( panel, QSplitter::KeepSize );
+
+ QVBoxLayout *vb = new QVBoxLayout( panel, 3, 3 );
+ channelsBtn = new QToolButton( panel );
+ channelsBtn->setAutoRaise( true );
+ QToolTip::add( channelsBtn, i18n("Channels"));
+ dateBtn = new QToolButton( panel );
+ dateBtn->setAutoRaise( true );
+ QToolTip::add( dateBtn, i18n("Timers"));
+ infoBtn = new QToolButton( panel );
+ infoBtn->setAutoRaise( true );
+ QToolTip::add( infoBtn, i18n("Electronic Program Guide"));
+ osdBtn = new QToolButton( panel );
+ osdBtn->setAutoRaise( true );
+ QToolTip::add( osdBtn, i18n("OSD"));
+ configBtn = new QToolButton( panel );
+ configBtn->setAutoRaise( true );
+ QToolTip::add( configBtn, i18n("DVB settings"));
+ recallBtn = new QToolButton( panel );
+ recallBtn->setAutoRaise( true );
+ QToolTip::add( recallBtn, i18n("Recall"));
+ QHBoxLayout *h1 = new QHBoxLayout();
+ h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) );
+ h1->addWidget( channelsBtn );
+ h1->addWidget( dateBtn );
+ h1->addWidget( infoBtn );
+ h1->addWidget( osdBtn );
+ h1->addWidget( configBtn );
+ h1->addWidget( recallBtn );
+ h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) );
+ vb->addLayout( h1 );
+
+ h1 = new QHBoxLayout();
+ searchBtn = new QToolButton( panel );
+ searchBtn->setAutoRaise( true );
+ QToolTip::add( searchBtn, i18n("Search channel(s)"));
+ QLabel* filterLabel = new QLabel( i18n("Filter") + ":", panel );
+ searchLE = new KLineEdit( panel );
+ searchLE->setFocusPolicy( QWidget::ClickFocus );
+ h1->addWidget( searchBtn );
+ h1->addWidget( filterLabel );
+ h1->addWidget( searchLE );
+ vb->addLayout( h1 );
+
+ channelsCb = new DListView( panel );
+ channelsCb->setHScrollBarMode( QListView::AlwaysOff );
+ //channelsCb->setPaletteBackgroundColor( QColor(255,255,200) );
+ connect( channelsCb, SIGNAL(itemRenamed(QListViewItem*)), this, SLOT(channelNumberChanged(QListViewItem*)) );
+ connect( channelsCb, SIGNAL(doubleClicked(QListViewItem*)), this, SLOT(channelSelected(QListViewItem*)) );
+ connect( channelsCb, SIGNAL(clicked(QListViewItem*)), this, SLOT(channelClicked(QListViewItem*)) );
+ connect( channelsCb, SIGNAL(contextMenuRequested(QListViewItem*,const QPoint&,int)), this, SLOT(channelPopup(QListViewItem*,const QPoint&,int)) );
+ channelsCb->setItemsRenameable( true );
+ channelsCb->addColumn( i18n("Number") );
+ channelsCb->addColumn( i18n("Name") );
+ channelsCb->addColumn( i18n("Source") );
+ channelsCb->setAllColumnsShowFocus( true );
+ channelsCb->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::MinimumExpanding) );
+ //channelsCb->setEnabled( false );
+ vb->addWidget( channelsCb );
+
+ h1 = new QHBoxLayout();
+ recordBtn = new QToolButton( panel );
+ QToolTip::add( recordBtn, i18n("Instant Record") );
+ recordBtn->setToggleButton( true );
+ h1->addWidget( recordBtn );
+ broadcastBtn = new QToolButton( panel );
+ QToolTip::add( broadcastBtn, i18n("Broadcast") );
+ h1->addWidget( broadcastBtn );
+ vb->addLayout( h1 );
+
+ h1 = new QHBoxLayout();
+ h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) );
+ shiftLed = new KLed( panel );
+ shiftLed->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ shiftLed->setDarkFactor( 500 );
+ shiftLed->off();
+ QToolTip::add( shiftLed, i18n("Time shifting") );
+ h1->addWidget( shiftLed );
+ h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) );
+ recordLed = new KLed( panel );
+ recordLed->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ recordLed->setColor( QColor( 255,0,0 ) );
+ recordLed->setDarkFactor( 500 );
+ recordLed->off();
+ QToolTip::add( recordLed, i18n("Recording") );
+ h1->addWidget( recordLed );
+ h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) );
+ broadcastLed = new KLed( panel );
+ broadcastLed->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ broadcastLed->setColor( QColor( 255,128,0 ) );
+ broadcastLed->setDarkFactor( 500 );
+ broadcastLed->off();
+ QToolTip::add( broadcastLed, i18n("Broadcasting") );
+ h1->addWidget( broadcastLed );
+ h1->addItem( new QSpacerItem( 1, 1, QSizePolicy::Preferred, QSizePolicy::Minimum ) );
+ vb->addLayout( h1 );
+
+ KIconLoader *icon = new KIconLoader();
+ tvPix = icon->loadIcon( "kdvbtv", KIcon::Small );
+ tvcPix = icon->loadIcon( "kdvbtvc", KIcon::Small );
+ raPix = icon->loadIcon( "kdvbra", KIcon::Small );
+ racPix = icon->loadIcon( "kdvbrac", KIcon::Small );
+ QIconSet iconset;
+ iconset.setPixmap( icon->loadIcon( "filesave", KIcon::Small ), QIconSet::Small );
+ iconset.setPixmap( icon->loadIcon( "player_record", KIcon::Small), QIconSet::Small, QIconSet::Normal, QIconSet::On );
+ recordBtn->setIconSet( iconset );
+ broadcastBtn->setIconSet( icon->loadIconSet("network_local", KIcon::Small) );
+ dateBtn->setIconSet( icon->loadIconSet("date", KIcon::Small) );
+ infoBtn->setIconSet( icon->loadIconSet("view_text", KIcon::Small) );
+ osdBtn->setIconSet( icon->loadIconSet("info", KIcon::Small) );
+ channelsBtn->setIconSet( icon->loadIconSet("kdvbtv", KIcon::Small) );
+ configBtn->setIconSet( icon->loadIconSet("configure", KIcon::Small) );
+ recallBtn->setIconSet( icon->loadIconSet("reload", KIcon::Small) );
+ searchBtn->setIconSet( icon->loadIconSet("locationbar_erase", KIcon::Small) );
+
+ setXMLFile("kaffeinedvb.rc");
+ setupActions();
+
+ connect( this, SIGNAL(zap(ChannelDesc*)), SLOT(dvbZap(ChannelDesc*)) );
+ connect( configBtn, SIGNAL(clicked()), this, SLOT(showConfigDialog()));
+ connect( recallBtn, SIGNAL(clicked()), this, SLOT(recallZap()));
+
+ connect( recordBtn, SIGNAL(clicked()), this, SLOT(setRecord()) );
+ connect( broadcastBtn, SIGNAL(clicked()), this, SLOT(setBroadcast()) );
+ connect( infoBtn, SIGNAL(clicked()), this, SLOT(showEvents()) );
+ connect( channelsBtn, SIGNAL(clicked()), this, SLOT(scanner()) );
+ connect( dateBtn, SIGNAL(clicked()), this, SLOT(showTimers()) );
+ connect( osdBtn, SIGNAL(clicked()), this, SLOT(dvbOSD()));
+ connect( searchBtn, SIGNAL(clicked()), this, SLOT(resetSearch()) );
+ connect(searchLE, SIGNAL(textChanged(const QString&)), this, SLOT(searchChannel(const QString&)));
+
+ connect( &timersTimer, SIGNAL(timeout()), this, SLOT(checkTimers()) );
+ connect( &osdTimer, SIGNAL(timeout()), this, SLOT(resetOSD()) );
+ connect( &showOsdTimer, SIGNAL(timeout()), this, SLOT(dvbOSD()) );
+ connect( &tuningTimer, SIGNAL(timeout()), this, SLOT(setTuning()) );
+ connect( &stopTuningTimer, SIGNAL(timeout()), this, SLOT(setTuning()) );
+ connect( &diskTimer, SIGNAL(timeout()), this, SLOT(diskStatus()) );
+
+ setConfig();
+
+ updown = 1;
+ autocount = 0;
+ delete icon;
+
+ events.loadEpg();
+}
+
+
+
+void DvbPanel::togglePanel()
+{
+ if ( panel->isHidden() )
+ panel->show();
+ else
+ panel->hide();
+}
+
+
+
+void DvbPanel::diskStatus()
+{
+ double freemb;
+ struct statvfs buf;
+
+ if ( statvfs( dvbConfig->shiftDir.local8Bit(), &buf ) ) {
+ fprintf(stderr,"Couldn't get file system statistics\n");
+ return;
+ }
+
+ freemb = (double)(((double)(buf.f_bavail)*(double)(buf.f_bsize))/(1024.0*1024.0));
+ if ( freemb<300 )
+ emit showOSD( i18n("Warning: low disc space")+QString(" (%1").arg((int)freemb)+i18n("MB")+")", 5000, 3 );
+}
+
+
+
+void DvbPanel::channelPopup( QListViewItem *it, const QPoint &pos, int col )
+{
+ QPoint p=pos;
+
+ if ( !it )
+ return;
+
+ int i=col, j;
+ QImage img;
+ QPixmap pix;
+ QString name = it->text(1);
+ QString s;
+
+ QPopupMenu *pop = new QPopupMenu();
+ pop->insertItem( i18n("Select icon..."), 1 );
+ pop->insertItem( i18n("Edit..."), 2 );
+ i = 0;
+ i = pop->exec( QCursor::pos() );
+ switch ( i ) {
+ case 0 :
+ break;
+ case 1 :
+ s = KFileDialog::getOpenFileName( QString::null, "image/png image/jpeg image/gif image/x-bmp image/x-xpm", 0, i18n("Choose channel icon"));
+ if ( s.isEmpty() )
+ break;
+ img = QImage( s );
+ if ( img.isNull() )
+ break;
+ if ( img.width()>img.height() )
+ img = img.smoothScale( CHANICONSIZE, img.height()*CHANICONSIZE/img.width() );
+ else
+ img = img.smoothScale( img.width()*CHANICONSIZE/img.height(), CHANICONSIZE );
+ pix.convertFromImage( img );
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ if ( channels.at(j)->name==name ) {
+ channels.at(j)->pix = pix;
+ break;
+ }
+ }
+ pix.save( dvbConfig->dvbConfigIconsDir+name, "PNG" );
+ fillChannelList();
+ break;
+ case 2:
+ editChannel( name );
+ break;
+
+ }
+ delete pop;
+}
+
+bool DvbPanel::editChannel( QString &name )
+{
+ int j;
+ ChannelDesc *chan=0;
+ QStringList list;
+ QPixmap pix;
+
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ chan = channels.at(j);
+ if ( chan->name==name ) {
+ j = -1;
+ list.append( chan->tp.source );
+ break;
+ }
+ }
+ if ( j==-1 ) {
+ ChannelEditor dlg( list, false, chan, &channels, mainWidget );
+ int ret = dlg.exec();
+ if ( ret==ChannelEditor::Accepted ) {
+ pix.load( dvbConfig->dvbConfigIconsDir+chan->name );
+ if ( !pix.isNull() )
+ chan->pix = pix;
+ else {
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ pix = tvcPix;
+ else
+ pix = tvPix;
+ }
+ else {
+ if ( chan->fta )
+ pix = racPix;
+ else
+ pix = raPix;
+ }
+ }
+ fillChannelList( chan );
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+void DvbPanel::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames )
+{
+ uiNames.append( i18n("Digital TV") );
+ iconNames.append( "tv" );
+ targetNames.append( "DVB" );
+}
+
+
+
+bool DvbPanel::execTarget( const QString &target )
+{
+ if ( target=="DVB" ) {
+ if ( !channelsCb->isEnabled() ) {
+ KMessageBox::information( mainWidget, i18n("Live digital TV only works with the xine engine.") );
+ return true;
+ }
+ emit showMe( this );
+ QTimer::singleShot( 100, this, SLOT(playLastChannel()) );
+ return true;
+ }
+ return false;
+}
+
+
+
+void DvbPanel::setupActions()
+{
+ new KAction(i18n("OSD Next Channel"), "next", CTRL+SHIFT+Key_W, this, SLOT(dvbOSDNext()), actionCollection(), "dvb_browse_next");
+ new KAction(i18n("OSD Previous Channel"), "previous", CTRL+SHIFT+Key_Q, this, SLOT(dvbOSDPrev()), actionCollection(),"dvb_browse_prev");
+ new KAction(i18n("OSD Zap"), "ok", CTRL+SHIFT+Key_E, this, SLOT(dvbOSDZap()), actionCollection(), "dvb_browse_zap");
+ new KAction(i18n("OSD Next Event"), "down", CTRL+SHIFT+Key_S, this, SLOT(dvbOSDAdvance()), actionCollection(), "dvb_browse_advance");
+ new KAction(i18n("OSD Previous Event"), "up", CTRL+SHIFT+Key_A, this, SLOT(dvbOSDRetreat()), actionCollection(), "dvb_browse_retreat");
+ new KAction(i18n("Instant Record"), "filesave", 0, this, SLOT(setRecord()), actionCollection(), "dvb_instant_record");
+ new KAction(i18n("Recall"), "reload", CTRL+SHIFT+Key_Z, this, SLOT(recallZap()), actionCollection(), "dvb_recall");
+ new KAction(i18n("Show OSD"), "info", Key_O, this, SLOT(dvbOSD()), actionCollection(), "dvb_show_osd");
+ new KAction(i18n("EPG..."), "view_text", Key_G, this, SLOT(showEvents()), actionCollection(), "dvb_show_epg");
+ new KAction(i18n("Timers..."), "date", Key_T, this, SLOT(showTimers()), actionCollection(), "dvb_show_timers");
+ new KAction(i18n("Broadcasting..."), "network_local", Key_B, this, SLOT(setBroadcast()), actionCollection(), "dvb_show_broadcast");
+ new KAction(i18n("Channels..."), "kdvbtv", Key_C, this, SLOT(scanner()), actionCollection(), "dvb_channels");
+ new KAction(i18n("Configure DVB..."), "configure", CTRL|Key_C, this, SLOT(showConfigDialog()), actionCollection(), "dvb_config");
+}
+
+
+
+QWidget *DvbPanel::wantPlayerWindow()
+{
+ return playerBox;
+}
+
+
+
+QWidget *DvbPanel::inputMainWidget()
+{
+ return mainWidget;
+}
+
+
+
+void DvbPanel::searchChannel( const QString &text )
+{
+ int i, c=-1;
+ QListViewItemIterator it( channelsCb );
+ if ( !it.current() )
+ return;
+ for ( i=0; i<channelsCb->columns(); i++ ) {
+ if ( channelsCb->columnText(i)==i18n("Name") ) {
+ c = i;
+ break;
+ }
+ }
+ if ( c==-1 )
+ return;
+
+ channelsCb->visibleItems = 0;
+
+ while ( it.current() ) {
+ if ( text.isEmpty() || it.current()->text( c ).contains( text, false ) ) {
+ it.current()->setVisible(true);
+ ++channelsCb->visibleItems;
+ }
+ else {
+ it.current()->setVisible(false);
+ }
+ ++it;
+ }
+}
+
+
+
+void DvbPanel::resetSearch()
+{
+ searchLE->clear();
+ searchChannel( "" );
+}
+
+
+
+void DvbPanel::channelNumberChanged( QListViewItem *it )
+{
+ int i, j;
+ bool ok;
+ unsigned int oldNum=0;
+ unsigned int num = it->text(0).toUInt( &ok, 10 );
+
+ for ( i=0; i<(int)channels.count(); i++ ) {
+ if ( channels.at(i)->name==it->text(1) ) {
+ oldNum = channels.at(i)->num;
+ break;
+ }
+ }
+
+ if ( num && oldNum ) {
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ if ( channels.at(j)->num==num ) {
+ channels.at(j)->num = oldNum;
+ channels.at(i)->num = num;
+ break;
+ }
+ }
+ }
+
+ if ((int)num > maxChannelNumber)
+ maxChannelNumber = num;
+ if ((int)num < minChannelNumber)
+ minChannelNumber = num;
+
+ fillChannelList();
+}
+
+
+
+void DvbPanel::catSelected( QIconViewItem *it )
+{
+ if ( !it ) return;
+
+ if ( it->text()==i18n("All") )
+ currentCategory = "All";
+ else if ( it->text()==i18n("TV") )
+ currentCategory = "TV";
+ else if ( it->text()==i18n("Radio") )
+ currentCategory = "Radio";
+ else
+ currentCategory = it->text();
+ fillChannelList();
+}
+
+
+
+void DvbPanel::catContextMenu( QIconViewItem *it, const QPoint &p )
+{
+ bool ok;
+ QString name, icon;
+ int i=0, ret;
+
+ QPopupMenu *pop = new QPopupMenu();
+ if ( !it ) {
+ pop->insertItem( i18n("New Category..."), 0 );
+ }
+ else {
+ pop->insertItem( i18n("Change Icon..."), 1 );
+ if ( it->text()!=i18n("All") && it->text()!=i18n("Radio") && it->text()!=i18n("TV") )
+ pop->insertItem( i18n("Delete Category..."), 2 );
+ }
+ i = pop->exec( p );
+ switch ( i ) {
+ case 0 :
+ name = KInputDialog::getText( i18n("New Category"), i18n("Enter a name for this category:"), QString::null, &ok);
+ for ( QIconViewItem *qitem = iconView->firstItem(); qitem; qitem = qitem->nextItem() ) {
+ if ( qitem->text()==name )
+ ok = false;
+ }
+ if ( ok ) {
+ KIconViewItem* item = new DIconViewItem(this, iconView, name, KGlobal::iconLoader()->loadIcon("kaffeine", KIcon::NoGroup, KIcon::SizeSmallMedium));
+ item->setDropEnabled( true );
+ dvbConfig->addCategory( name, "kaffeine" );
+ }
+ break;
+ case 1 :
+ icon = KIconDialog::getIcon();
+ if ( !icon.isEmpty() ) {
+ it->setPixmap( KGlobal::iconLoader()->loadIcon(icon, KIcon::NoGroup, KIcon::SizeSmallMedium) );
+ dvbConfig->changeIconCategory( it->text(), icon );
+ }
+ break;
+ case 2 :
+ ret = KMessageBox::questionYesNo( mainWidget, i18n("Do you really want to delete this category?") );
+ if ( ret==KMessageBox::Yes ) {
+ dvbConfig->removeCategory( it->text() );
+ delete it;
+ currentCategory = "All";
+ fillChannelList();
+ }
+ break;
+ }
+ delete pop;
+}
+
+
+
+void DvbPanel::moveChannel( const QString &cat, const QString &name )
+{
+ int i;
+ ChannelDesc *chan;
+ QListViewItem *it;
+
+ for ( i=0; i<(int)channels.count(); i++ ) {
+ chan = channels.at(i);
+ if ( chan->name==name ) {
+ if ( cat==i18n("All") )
+ chan->category = "";
+ else
+ chan->category = cat;
+ it = channelsCb->currentItem();
+ if ( it && currentCategory!="All" && currentCategory!="TV" && currentCategory!="Radio" )
+ delete it;
+ break;
+ }
+ }
+}
+
+
+
+void DvbPanel::dumpEvents()
+{
+ EventSource *esrc;
+ EventTsid *et;
+ EventSid *es;
+ QPtrList<EventDesc> *esEvents;
+ EventDesc *desc;
+ int i, k, j, m, n;
+ QString s;
+
+ QFile f( QDir::homeDirPath()+"/kaffeine_dvb_events.txt" );
+ if ( f.open(IO_WriteOnly|IO_Truncate) ) {
+ fprintf( stderr, "Creating events file.\n");
+ QTextStream tt( &f );
+ tt << "Saved: "+QDateTime::currentDateTime().toString( "dd-MM-yyyy hh:mm:ss" )+"\n";
+ k= 0;
+ for( i=0; i<events.getNSource(); i++ ) {
+ if ( !(esrc=events.getNEventSource( i )) )
+ continue;
+ tt << esrc->getSource()+QString(" : %1 TS with events.\n").arg( esrc->getNTsid() );
+ for ( m=0; m<esrc->getNTsid(); m++ ) {
+ if ( !(et=esrc->getNEventTsid( m )) )
+ continue;
+ tt << QString("TSID %1 : %2 services with events\n").arg( et->getTsid() ).arg( et->getNSid() );
+ for ( n=0; n<et->getNSid(); n++ ) {
+ if ( !(es=et->getNEventSid( n )) )
+ continue;
+ tt << QString(" SID %1 : %2 events\n").arg( es->getSid() ).arg( es->getNDesc() );
+ k+= es->getNDesc();
+ }
+ }
+ }
+ tt << "Number of events : "+s.setNum( k )+"\n";
+ fprintf( stderr, "Number of events : %d\n", k );
+ tt << "-------------------------\n";
+ tt << "\n";
+ for( i=0; i<events.getNSource(); i++ ) {
+ if ( !(esrc=events.getNEventSource( i )) )
+ continue;
+ for ( m=0; m<esrc->getNTsid(); m++ ) {
+ if ( !(et=esrc->getNEventTsid( m )) )
+ continue;
+ for ( n=0; n<et->getNSid(); n++ ) {
+ if ( !(es=et->getNEventSid( n )) )
+ continue;
+ esEvents = es->getEvents();
+ es->lock();
+ for ( j=0; j<(int)esEvents->count(); j++ ) {
+ if ( !(desc=esEvents->at( j )) )
+ continue;
+ tt << "Source: "+desc->source+"\n";
+ tt << QString("Network ID: %1\n").arg(desc->nid);
+ tt << QString("Transport Stream ID: %1\n").arg(desc->tsid);
+ tt << QString("Service ID: %1\n").arg(desc->sid);
+ tt << QString("Event ID: %1\n").arg(desc->eid);
+ tt << "Title: "+desc->title+"\n";
+ tt << "Subtitle: "+desc->subtitle+"\n";
+ tt << desc->startDateTime.toString( "dd-MM-yyyy hh:mm:ss" )+"\n";
+ tt << desc->duration.toString( "hh:mm:ss" )+"\n";
+ s = "";
+ for ( k=0; k<(int)desc->shortEvents.count(); k++ ) {
+ s = s + desc->shortEvents.at(k)->name;
+ if (!desc->shortEvents.at(k)->name.isEmpty() && !desc->shortEvents.at(k)->text.isEmpty()) {
+ s = s + " : ";
+ s = s + desc->shortEvents.at(k)->text;
+ s = s+". ";
+ }
+ }
+ for ( k=0; k<(int)desc->extEvents.count(); k++ )
+ s = s+ *desc->extEvents.at(k);
+ tt << s+"\n";
+ tt << "\n";
+ }
+ es->unlock();
+ }
+ }
+ }
+ f.close();
+ }
+ else fprintf( stderr, "Can't create events file!\n");
+}
+
+
+
+void DvbPanel::channelClicked( QListViewItem *it )
+{
+ QPtrListIterator<ChannelDesc> iter( channels );
+ ChannelDesc *itdesc, *desc=0;
+ DvbStream *d = 0;
+
+ if ( !it )
+ return;
+
+ iter.toFirst();
+ while ( (itdesc=iter.current())!=0 ) {
+ if ( itdesc->name==it->text(1) ) {
+ desc = itdesc;
+ break;
+ }
+ ++iter;
+ }
+
+ if ( !desc )
+ return;
+
+ for (int j = 0; j < (int)dvb.count(); j ++) {
+ if (dvb.at(j)->canSource(desc)) {
+ d = dvb.at(j);
+ break;
+ }
+ }
+
+ osdMode = 0;
+ dvbOSD( *desc, d );
+}
+
+
+
+void DvbPanel::resetOSD()
+{
+ osdMode = 0;
+}
+
+
+
+void DvbPanel::dvbOSD()
+{
+ DvbStream *d = 0;
+
+ if (browseDvbStream != -1 && osdMode != 0) {
+ dvbOSDSkip(0);
+ return;
+ }
+
+ for (int i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasLive() ) {
+ d = dvb.at(i);
+ break;
+ }
+ }
+
+ if ( d )
+ dvbOSD( d->getLiveChannel(), d );
+}
+
+
+
+void DvbPanel::dvbOSDZap()
+{
+ ChannelDesc *chan = 0;
+
+ if (browseDvbStream == -1)
+ return;
+
+ osdMode = 0;
+
+ for (int i=0; i<(int)channels.count(); i++) {
+ if ((int) channels.at(i)->num == browseDvbStream) {
+ chan = channels.at(i);
+ break;
+ }
+ }
+
+ if (!chan)
+ return;
+
+ dvbZap(chan);
+}
+
+
+
+void DvbPanel::dvbOSDNext()
+{
+ browseDvbTimeShift = -1;
+ osdMode = 0;
+
+ dvbOSDSkip(1);
+}
+
+
+
+void DvbPanel::dvbOSDSkip(int skip, int timeShift /* = 0 */)
+{
+ DvbStream *d = 0;
+ ChannelDesc *chan = 0;
+
+ int mychan = -1;
+
+ if (browseDvbStream == -1)
+ mychan = dvbConfig->lastChannel;
+ else
+ mychan = browseDvbStream + skip;
+
+ if (mychan < minChannelNumber)
+ mychan = maxChannelNumber;
+ else if (mychan > maxChannelNumber)
+ mychan = minChannelNumber;
+
+ for (int i = 0; i < (int)channels.count(); i ++) {
+ if ((int) channels.at(i)->num == mychan) {
+ chan = channels.at(i);
+ break;
+ }
+ }
+
+ if (!chan)
+ return;
+
+ for (int j = 0; j < (int)dvb.count(); j ++) {
+ if (dvb.at(j)->canSource(chan)) {
+ d = dvb.at(j);
+ break;
+ }
+ }
+
+ if (!d)
+ return;
+
+ browseDvbStream = chan->num;
+
+ dvbOSD(*chan, d, timeShift);
+}
+
+
+
+void DvbPanel::dvbOSDPrev()
+{
+ browseDvbTimeShift = -1;
+ osdMode = 0;
+
+ dvbOSDSkip(-1);
+}
+
+
+
+void DvbPanel::dvbOSDHide()
+{
+ browseDvbStream = -1;
+ browseDvbTimeShift = -1;
+}
+
+
+
+void DvbPanel::dvbOSDAdvance()
+{
+ osdMode = 0;
+
+ dvbOSDSkip(0, 1);
+}
+
+
+
+void DvbPanel::dvbOSDRetreat()
+{
+ osdMode = 0;
+
+ dvbOSDSkip(0, -1);
+}
+
+
+
+void DvbPanel::dvbOSD(ChannelDesc liveChannel, DvbStream *d, int timeShift /* = 0 */)
+{
+ QStringList list;
+ EventSource *esrc;
+ EventSid *es;
+ QPtrList<EventDesc> *esEvents;
+ EventDesc *desc;
+ QString s;
+ int i, j, k;
+ int first=0;
+
+ if ( !d || liveChannel.name.isEmpty() )
+ return;
+
+ if ( osdMode==2 ) {
+ osdTimer.stop();
+ osdMode = 0;
+ list.append( "STOP" );
+ emit showDvbOSD( s.setNum( liveChannel.num )+" - "+liveChannel.name, list );
+ return;
+ }
+
+ if ( osdMode==1 )
+ osdTimer.stop();
+
+ if ( osdMode==0 ) {
+ if ( d->liveIsRecording() )
+ list.append( "R" );
+ if ( d->timeShiftMode() )
+ list.append( "T" );
+ }
+ else
+ list.append( "E" );
+
+ int myshift = 0;
+
+ if (browseDvbTimeShift == -1)
+ myshift = 0;
+ else
+ myshift = browseDvbTimeShift + timeShift;
+
+ if (myshift < 0)
+ myshift = 0;
+
+ browseDvbTimeShift = myshift;
+
+ k = 0;
+
+ esrc = events.getEventSource( liveChannel.tp.source );
+ es = esrc->getEventSid( liveChannel.tp.nid, liveChannel.tp.tsid, liveChannel.sid );
+ if ( !es )
+ goto end;
+ es->lock();
+ esEvents = es->getEvents();
+
+ for ( j=myshift; j<(myshift+2); j++ ) {
+ desc = esEvents->at( j );
+ if ( !desc )
+ continue;
+
+ if ( !desc->title.isEmpty() ) {
+ s = desc->startDateTime.toString( "hh:mm" );
+ s = s+" - ";
+ s = s+desc->title;
+ if ( !osdMode && !first && !myshift ) {
+ QDateTime dt = QDateTime::currentDateTime();
+ int secs = desc->startDateTime.secsTo( dt );
+ i = QTime().secsTo( desc->duration );
+ if ( i!=0 )
+ i = secs*100/i;
+ if ( i>100 )
+ i = 100;
+ list.append( QString("BAR")+QString().setNum( i ) );
+ ++first;
+ }
+ list.append( s );
+ k++;
+ }
+ else if ( osdMode )
+ list.append( "" );
+ if ( osdMode==0 ) {
+ if ( k>1 )
+ break;
+ else
+ continue;
+ }
+ list.append( desc->subtitle );
+ s = "";
+ for ( i=0; i<(int)desc->shortEvents.count(); i++ ) {
+ s = s + desc->shortEvents.at(i)->name;
+ if (!desc->shortEvents.at(i)->name.isEmpty() && !desc->shortEvents.at(i)->text.isEmpty()) {
+ s+= " : ";
+ s+= desc->shortEvents.at(i)->text;
+ s+= ". ";
+ }
+ }
+ for ( i=0; i<(int)desc->extEvents.count(); i++ )
+ s+= *desc->extEvents.at(i);
+ list.append( s );
+ break;
+ }
+ es->unlock();
+
+end:
+ if ( osdMode==0 )
+ osdTimer.start( 5000, true );
+ osdMode++;
+ emit showDvbOSD( s.setNum( liveChannel.num )+" - "+liveChannel.name, list );
+}
+
+
+
+void DvbPanel::enableLiveDvb( bool on )
+{
+ channelsCb->setEnabled( on );
+}
+
+
+
+void DvbPanel::checkFirstRun()
+{
+ if ( dvbConfig->firstRun() )
+ showConfigDialog();
+}
+
+
+
+void DvbPanel::setConfig()
+{
+ int i;
+ int error = 0;
+ KIconViewItem* item = NULL;
+ DvbStream *d;
+
+ QString s = locateLocal("appdata", "");
+ dvbConfig = new DVBconfig( s );
+ item = new DIconViewItem(this, iconView, i18n("All"), KGlobal::iconLoader()->loadIcon(dvbConfig->allIcon, KIcon::NoGroup, KIcon::SizeSmallMedium));
+ iconView->setFixedHeight( item->height()+iconView->horizontalScrollBar()->height() );
+ item->setDropEnabled( true );
+ item = new DIconViewItem(this, iconView, i18n("Radio"), KGlobal::iconLoader()->loadIcon(dvbConfig->radioIcon, KIcon::NoGroup, KIcon::SizeSmallMedium));
+ item->setDropEnabled( false );
+ item = new DIconViewItem(this, iconView, i18n("TV"), KGlobal::iconLoader()->loadIcon(dvbConfig->tvIcon, KIcon::NoGroup, KIcon::SizeSmallMedium));
+ item->setDropEnabled( false );
+
+ KTrader::OfferList offers = KTrader::self()->query("KaffeineDvbPlugin");
+ KTrader::OfferList::Iterator it = offers.begin();
+ if ( it!=offers.end() ) {
+ KService::Ptr ptr = (*it);
+ plugName = ptr->desktopEntryName();
+ plug = KParts::ComponentFactory::createPartInstanceFromService<KaffeineDvbPlugin>(ptr, 0, ptr->name().ascii(), 0, 0, 0, &error);
+ if (error > 0) {
+ fprintf( stderr, "Loading of DVB plugin failed: %s\n", KLibLoader::self()->lastErrorMessage().ascii() );
+ plug = NULL;
+ }
+ else {
+ fprintf( stderr, "DVB plugin loaded\n.");
+ }
+ }
+
+ for ( i=0; i<(int)dvbConfig->categories.count(); i++ ) {
+ item = new DIconViewItem(this, iconView, dvbConfig->categories.at(i)->name, KGlobal::iconLoader()->loadIcon(dvbConfig->categories.at(i)->icon, KIcon::NoGroup, KIcon::SizeSmallMedium));
+ item->setDropEnabled( true );
+ }
+
+ for ( i=0; i<(int)dvbConfig->devList.count(); i++ ) {
+ d = new DvbStream( dvbConfig->devList.at(i), dvbConfig->defaultCharset, &events );
+ d->setPlug( plug );
+ dvb.append( d );
+ connect( d, SIGNAL(shifting(bool)), this, SLOT(setShiftLed(bool)) );
+ connect( d, SIGNAL(isBroadcasting(bool)), this, SLOT(setBroadcastLed(bool)) );
+ connect( d, SIGNAL(timerEnded(RecTimer*)), this, SLOT(killTimer(RecTimer*)) );
+ connect( d, SIGNAL(isRecording(bool)), this, SLOT(setRecordLed(bool)) );
+ connect( d, SIGNAL(playDvb()), this, SLOT(pipeOpened()) );
+ }
+ fifoName = QDir::homeDirPath()+"/.kaxtv.ts";
+ QFile f( fifoName );
+ if ( f.exists() )
+ f.remove();
+ if ( (mkfifo( fifoName.ascii(), 0644 ))<0 ) {
+ perror( fifoName.latin1() );
+ fifoName = "";
+ }
+ fifoName1 = QDir::homeDirPath()+"/.kaxtv1.ts";
+ QFile f1( fifoName1 );
+ if ( f1.exists() )
+ f1.remove();
+ if ( (mkfifo( fifoName1.ascii(), 0644 ))<0 ) {
+ perror( fifoName1.latin1() );
+ fifoName1 = "";
+ }
+ currentFifo = fifoName;
+ getTimerList();
+ timersTimer.start( 5000 );
+ getChannelList();
+ rtp = new Ts2Rtp();
+ rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort );
+ cleaner = new Cleaner( dvbConfig->shiftDir, dvbConfig->recordDir );
+ split->setSizes( dvbConfig->splitSizes );
+ recallChannel = dvbConfig->lastChannel;
+}
+
+
+
+void DvbPanel::showConfigDialog()
+{
+ int ret;
+
+loop:
+ if ( !dvbConfig->haveData() ) {
+ ret = KMessageBox::questionYesNo( mainWidget, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\
+ Check your internet connection, and say Yes to try again.<br>\
+ Or say No to cancel.<br>\
+ If you already have this archive, copy it to ~/.kde/share/apps/kaffeine/dvbdata.tar.gz and say Yes.<br><br>Should I try again?</qt>") );
+ if ( ret==KMessageBox::Yes )
+ goto loop;
+ return;
+ }
+
+ DvbConfigDialog dlg( dvbConfig, mainWidget, plug );
+ connect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) );
+ ret = dlg.exec();
+ disconnect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) );
+ if ( ret==DvbConfigDialog::Rejected )
+ return;
+ rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort );
+ cleaner->setPaths( dvbConfig->shiftDir, dvbConfig->recordDir );
+}
+
+
+
+QPtrList<Transponder> DvbPanel::getSourcesStatus()
+{
+ int i, j;
+ QStringList list;
+ QPtrList<Transponder> ss;
+ Transponder t;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ list = dvb.at(i)->getSources();
+ for ( j=0; j<(int)list.count(); j++ ) {
+ if ( dvb.at(i)->hasRec() || dvb.at(i)->hasBroadcast() )
+ t = dvb.at(i)->getCurrentTransponder();
+ else {
+ t = Transponder();
+ t.source = list[j];
+ }
+ ss.append( new Transponder( t ) );
+ }
+ }
+ return ss;
+}
+
+
+
+void DvbPanel::fillChannelList( ChannelDesc *ch )
+{
+ int i, j;
+ ChannelDesc *chan;
+ KListViewItem *it, *visible=0;
+ bool cont=false;
+ QPtrList<Transponder> trans = getSourcesStatus();
+ trans.setAutoDelete( true );
+
+ searchLE->clear();
+ channelsCb->clear();
+ for ( i=0; i<(int)channels.count(); i++ ) {
+ chan = channels.at(i);
+ for ( j=0; j<(int)trans.count(); j++ ) {
+ cont = false;
+ if ( trans.at(j)->source==chan->tp.source ) {
+ if ( trans.at(j)->freq ) {
+ if ( chan->tp==*trans.at(j) ) break;
+ }
+ else
+ break;
+ }
+ cont = true;
+ }
+ if ( cont )
+ continue;
+ if ( currentCategory=="TV" ) {
+ if ( chan->type!=1 )
+ continue;
+ }
+ else if ( currentCategory=="Radio" ) {
+ if ( chan->type!=2 )
+ continue;
+ }
+ else if ( currentCategory!="All" && chan->category!=currentCategory )
+ continue;
+ it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source );
+ if ( ch && ch==chan )
+ visible = it;
+ it->setDragEnabled( true );
+ chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name );
+ if ( !chan->pix.isNull() )
+ it->setPixmap( 1, chan->pix );
+ else {
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ it->setPixmap( 1, tvcPix );
+ else
+ it->setPixmap( 1, tvPix );
+ }
+ else {
+ if ( chan->fta )
+ it->setPixmap( 1, racPix );
+ else
+ it->setPixmap( 1, raPix );
+ }
+ }
+ }
+ channelsCb->visibleItems = channelsCb->childCount();
+ trans.clear();
+ if ( visible ) {
+ channelsCb->ensureItemVisible( visible );
+ channelsCb->setSelected( visible, true );
+ }
+}
+
+
+
+DvbStream* DvbPanel::getWorkingDvb( int mode, ChannelDesc *chan )
+{
+ int i, ret;
+ QValueList<int> working; // notTuned=0, hasLive=1, hasBroadcast=2, hasRec=3, can'tDoChannel=4
+
+ for ( i=0; i<(int)dvb.count(); i++ )
+ working.append( 0 );
+
+ // fill in working status
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( !dvb.at(i)->canSource( chan ) ) {
+ working[i] = 4;
+ continue;
+ }
+ if ( dvb.at(i)->isTuned() ) {
+ if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) {
+ return dvb.at(i); // use that one since it's already tuned on the good mplex
+ }
+ else if ( dvb.at(i)->hasRec() )
+ working[i] = 3;
+ else if ( dvb.at(i)->hasBroadcast() )
+ working[i] = 2;
+ else
+ working[i] = 1;
+ }
+ else
+ working[i] = 0;
+ }
+ ret = 0;
+ // search for least working card
+ for ( i=1; i<(int)working.count(); i++ ) {
+ if ( working[i]<working[0] ) {
+ working[0] = working[i];
+ ret = i;
+ }
+ }
+ if ( working[0]<mode )
+ return dvb.at(ret);
+ else
+ return 0;
+}
+
+
+
+void DvbPanel::setBroadcast()
+{
+ int ret, i;
+ QPtrList<ChannelDesc> list;
+ bool live=false;
+ DvbStream *d;
+
+ BroadcastEditor dlg( mainWidget, &channels, &list );
+ ret = dlg.exec();
+ if ( ret==BroadcastEditor::Rejected )
+ return;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasBroadcast() )
+ dvb.at(i)->stopBroadcast();
+ }
+ if ( ! list.count() ) {
+ return;
+ }
+
+ d = getWorkingDvb( 2, list.at(0) );
+
+ if ( d )
+ ret = d->canStartBroadcast( live, list.at(0) );
+ else
+ ret = -1;
+ if ( ret==0 ) {
+ if ( live ) {
+ stopLive();
+ emit dvbStop();
+ }
+ if ( !d->startBroadcast( &list, rtp ) ) {
+ KMessageBox::information( mainWidget, i18n("Broadcasting failed.") );
+ }
+ }
+ else
+ KMessageBox::information( mainWidget, i18n("Can't start broadcasting.") );
+}
+
+
+
+void DvbPanel::checkTimers()
+{
+ int i, j, ret;
+ bool live=false;
+ RecTimer *t;
+ ChannelDesc *chan;
+ QDateTime cur=QDateTime::currentDateTime();
+ DvbStream *d;
+
+ for ( i=0; i<(int)timers.count(); i++ ) {
+ t = timers.at(i);
+ if ( t->running )
+ continue;
+ if ( t->begin<=cur && cur<t->begin.addSecs(QTime().secsTo(t->duration)) ) {
+ chan = 0;
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ if ( channels.at(j)->name==t->channel ) {
+ chan = channels.at(j);
+ break;
+ }
+ }
+ if ( !chan )
+ continue;
+ d = getWorkingDvb( 3, chan );
+ live = false;
+ if ( d )
+ ret = d->canStartTimer( live, chan );
+ else
+ ret = -1;
+ if ( ret==0 ) {
+ if ( live ) {
+ stopLive();
+ emit dvbStop();
+ }
+ if ( d->startTimer( chan, dvbConfig->recordDir, dvbConfig->sizeFile, t, dvbConfig->filenameFormat ) ) {
+ KProcess proc;
+ proc << QDir::homeDirPath()+"/bin/kaffeine_recording";
+ proc << "On";
+ proc.start( KProcess::DontCare );
+ t->running = 1;
+ if ( timersDialog )
+ emit timersChanged();
+ saveTimerList();
+ i--;
+ }
+ else
+ fprintf( stderr, "start timer failed!!!\n" );
+ }
+ else
+ fprintf( stderr, "Cant start timer !!!\n" );
+ }
+ else if ( t->mode ) {
+ if (t->begin.addSecs(t->duration.hour()*3600+t->duration.minute()*60+60)<cur) {
+ updateModeTimer( t );
+ if ( timersDialog )
+ emit timersChanged();
+ }
+ }
+ }
+}
+
+
+
+void DvbPanel::setRecord()
+{
+ ChannelDesc curchan;
+ QString s="";
+ int ret, i, r=0;
+ bool live=false;
+ RecTimer *t, *rt;
+ EventDesc *desc;
+ DvbStream *d=0;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasLive() ) {
+ d = dvb.at(i);
+ curchan = d->getLiveChannel();
+ break;
+ }
+ }
+ if ( !d ) {
+ recordBtn->setOn( false );
+ showTimers();
+ return;
+ }
+
+ desc = events.getEventDesc( curchan.tp.source, curchan.tp.nid, curchan.tp.tsid, curchan.sid, 0 );
+
+ if ( desc )
+ s = desc->title;
+
+ if ( s.isEmpty() ) {
+ if ( !dvbConfig->filenameFormat.contains("%chan") )
+ s = curchan.name;
+ if ( !dvbConfig->filenameFormat.contains("%date") )
+ s+="_"+QDateTime::currentDateTime().toString( "yyyyMMdd-hhmmss" );
+ }
+
+ rt = new RecTimer();
+ rt->name = s;
+ rt->channel = curchan.name;
+ rt->begin = QDateTime::currentDateTime();
+ rt->duration = QTime( 0,0,0).addSecs( dvbConfig->instantDuration*60 ) ;
+ rt->running = 1;
+ rt->mode = 0;
+
+ ret = d->canStartTimer( live, &curchan );
+ if ( ret==0 ) {
+ if ( d->startTimer( &curchan, dvbConfig->recordDir, dvbConfig->sizeFile, rt, dvbConfig->filenameFormat ) ) {
+ KProcess proc;
+ proc << QDir::homeDirPath()+"/bin/kaffeine_recording";
+ proc << "On";
+ proc.start( KProcess::DontCare );
+
+ for ( i=0; i<(int)timers.count(); i++ ) {
+ t = timers.at(i);
+ if ( rt->begin>t->begin )
+ r=i+1;
+ }
+ timers.insert( r, rt );
+ if ( timersDialog )
+ emit timersChanged();
+ saveTimerList();
+ emit showOSD( i18n("Instant Record successfully started"), 5000, 3 );
+ }
+ else {
+ KMessageBox::information( mainWidget, i18n("Instant Recording failed to start.") );
+ fprintf( stderr, "DvbPanel::setRecord:start timer failed!\n" );
+ delete rt;
+ }
+ }
+ else {
+ delete rt;
+ for ( i=0; i<(int)timers.count(); i++ ) {
+ t = timers.at(i);
+ if ( d->liveIsRecording() && t->running && curchan.name == t->channel ) {
+ d->updateTimer( t, 0 );
+ emit showOSD( i18n("Recording successfully stopped"), 5000, 3 );
+ return;
+ }
+ }
+ showTimers();
+ }
+}
+
+
+
+void DvbPanel::setRecordLed( bool on )
+{
+ int i;
+ bool rec=false;
+
+ if ( on ) {
+ recordLed->on();
+ fillChannelList();
+ }
+ else {
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasRec() ) {
+ rec = true;
+ break;
+ }
+ }
+ if ( !rec )
+ recordLed->off();
+ else
+ recordLed->on();
+ fillChannelList();
+ }
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->liveIsRecording() ) {
+ recordBtn->setOn( true );
+ return;
+ }
+ }
+ recordBtn->setOn( false );
+}
+
+
+void DvbPanel::setBroadcastLed( bool on )
+{
+ int i;
+ bool broad=false;
+
+ if ( on ) {
+ broadcastLed->on();
+ fillChannelList();
+ }
+ else {
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasBroadcast() ) {
+ broad = true;
+ break;
+ }
+ }
+ if ( !broad )
+ broadcastLed->off();
+ else
+ broadcastLed->on();
+ fillChannelList();
+ }
+}
+
+
+
+void DvbPanel::killTimer( RecTimer *t )
+{
+ int i;
+
+ for ( i=0; i<(int)timers.count(); i++ ) {
+ if ( timers.at(i)==t ) {
+ KProcess proc;
+ proc << QDir::homeDirPath()+"/bin/kaffeine_recording";
+ if ( recordLed->state()==KLed::On )
+ proc << "On";
+ else
+ proc << "Off";
+ proc << KProcess::quote( t->fullPath );
+ proc.start( KProcess::DontCare );
+
+ if ( t->mode )
+ updateModeTimer( t );
+ else
+ timers.remove( t );
+ if ( timersDialog )
+ emit timersChanged();
+ return;
+ }
+ }
+}
+
+
+
+void DvbPanel::updateModeTimer( RecTimer *t )
+{
+ int stop=0, r=0, i;
+
+ if ( t->mode==CronTimer::Daily )
+ t->begin = t->begin.addDays(1);
+ else if ( t->mode==CronTimer::Weekly )
+ t->begin = t->begin.addDays(7);
+ else if ( t->mode==CronTimer::Monthly )
+ t->begin = t->begin.addMonths(1);
+ else while ( !stop ) {
+ t->begin = t->begin.addDays(1);
+ if ( (t->begin.date().dayOfWeek()==1) && (t->mode&CronTimer::Monday) ) stop++;
+ else if ( (t->begin.date().dayOfWeek()==2) && (t->mode&CronTimer::Tuesday) ) stop++;
+ else if ( (t->begin.date().dayOfWeek()==3) && (t->mode&CronTimer::Wednesday) ) stop++;
+ else if ( (t->begin.date().dayOfWeek()==4) && (t->mode&CronTimer::Thursday) ) stop++;
+ else if ( (t->begin.date().dayOfWeek()==5) && (t->mode&CronTimer::Friday) ) stop++;
+ else if ( (t->begin.date().dayOfWeek()==6) && (t->mode&CronTimer::Saturday) ) stop++;
+ else if ( (t->begin.date().dayOfWeek()==7) && (t->mode&CronTimer::Sunday) ) stop++;
+ }
+
+ RecTimer *nt = new RecTimer();
+ nt->name = t->name;
+ nt->channel = t->channel;
+ nt->begin = t->begin;
+ nt->duration = t->duration;
+ nt->running = 0;
+ nt->mode = t->mode;
+ timers.remove( t );
+ for ( i=0; i<(int)timers.count(); i++ ) {
+ t = timers.at(i);
+ if ( nt->begin>t->begin )
+ r=i+1;
+ }
+ timers.insert( r, nt );
+}
+
+
+
+void DvbPanel::showTimers()
+{
+ int i;
+ QStringList list;
+ QMap<QString,QString> map;
+
+ if ( channels.count()==0 ) {
+ KMessageBox::sorry( 0, i18n("You may want to define some channel first!") );
+ return;
+ }
+ for ( QPtrListIterator<ChannelDesc> it(channels); it.current(); ++it )
+ map[it.current()->name] = it.current()->name;
+ QMap<QString,QString>::Iterator it;
+ QMap<QString,QString>::Iterator end(map.end());
+ for ( it = map.begin(); it != end; ++it )
+ list.append( it.data() );
+
+ timersDialog = new KRecord( list, &timers, mainWidget, dvbConfig->timerSize );
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ connect( timersDialog, SIGNAL(updateTimer(RecTimer*,int)), dvb.at(i), SLOT(updateTimer(RecTimer*,int)) );
+ }
+ connect( this, SIGNAL(timersChanged()), timersDialog, SLOT(refresh()) );
+ timersDialog->exec();
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ disconnect( timersDialog, SIGNAL(updateTimer(RecTimer*,int)), dvb.at(i), SLOT(updateTimer(RecTimer*,int)) );
+ }
+ disconnect( this, SIGNAL(timersChanged()), timersDialog, SLOT(refresh()) );
+ dvbConfig->timerSize = timersDialog->size();
+ delete timersDialog;
+ timersDialog = 0;
+ saveTimerList();
+}
+
+
+
+int DvbPanel::getSNR( int device )
+{
+ if ( device<0 || device>=(int)dvb.count() )
+ return -1;
+ return dvb.at(device)->getSNR();
+}
+
+
+void DvbPanel::dvbNewTimer( QString name, QString channel, QString datetime, QString duration )
+{
+ newTimer( channel, name, QDateTime::fromString( datetime, Qt::ISODate ), QTime::fromString( duration ), false );
+}
+
+
+
+void DvbPanel::newTimer( QString channel, QString name, QDateTime begin, QTime duration, bool warn )
+{
+ int i, r=0;
+ RecTimer *t;
+ RecTimer *rt = new RecTimer();
+
+ rt->name = name.replace("/","_").replace(">","_").replace("<","_").replace(":","_").replace('"',"_").replace("\\","_").replace("|","_");
+ rt->channel = channel;
+ rt->begin = begin.addSecs( -(dvbConfig->beginMargin*60) );
+ rt->duration = duration.addSecs( (dvbConfig->beginMargin+dvbConfig->endMargin)*60 ) ;
+ rt->running = 0;
+ rt->mode = 0;
+
+ for ( i=0; i<(int)timers.count(); i++ ) {
+ t = timers.at(i);
+ if ( rt->begin>t->begin )
+ r=i+1;
+ }
+ timers.insert( r, rt );
+ if ( warn )
+ KMessageBox::information( 0, i18n("Timer successfully created.") );
+}
+
+
+
+void DvbPanel::scanner()
+{
+ int ret;
+
+loop:
+ if ( !dvbConfig->haveData() ) {
+ ret = KMessageBox::questionYesNo( mainWidget, i18n("<qt>Can't get DVB data from http://hftom.free.fr/kaxtv/dvbdata.tar.gz!<br>\
+ Check your internet connection, and say Yes to try again.<br>\
+ Or say No to cancel.<br>\
+ If you already have this archive, copy it to ~/.kde/share/apps/kaffeine/dvbdata.tar.gz and say Yes.<br><br>Should I try again?</qt>") );
+ if ( ret==KMessageBox::Yes )
+ goto loop;
+ return;
+ }
+
+ if ( !dvbConfig->haveData() )
+ return;
+ ScanDialog dlg( &dvb, &channels, dvbConfig->scanSize, dvbConfig->dvbConfigDir, dvbConfig->defaultCharset );
+ dlg.exec();
+ dvbConfig->scanSize = dlg.size();
+ fillChannelList();
+ saveChannelList();
+}
+
+
+
+void DvbPanel::showEvents()
+{
+ events.doClean( false );
+ KEvents dlg( &channels, &dvb, &events, mainWidget, dvbConfig->epgSize );
+ connect( &dlg, SIGNAL(addTimer(QString,QString,QDateTime,QTime)), this, SLOT(newTimer(QString,QString,QDateTime,QTime)) );
+ connect( &dlg, SIGNAL(zapTo(const QString &)), this, SLOT(channelSelected(const QString &)) );
+ dlg.exec();
+ dvbConfig->epgSize = dlg.size();
+ disconnect( &dlg, SIGNAL(addTimer(QString,QString,QDateTime,QTime)), this, SLOT(newTimer(QString,QString,QDateTime,QTime)) );
+ disconnect( &dlg, SIGNAL(zapTo(const QString &)), this, SLOT(channelSelected(const QString &)) );
+ events.doClean( true );
+}
+
+
+
+void DvbPanel::setShiftLed( bool on )
+{
+ if ( on ) {
+ shiftLed->on();
+ diskTimer.start( 300000 );
+ }
+ else {
+ shiftLed->off();
+ diskTimer.stop();
+ }
+}
+
+
+
+void DvbPanel::channelSelected( const QString &name )
+{
+ QPtrListIterator<ChannelDesc> iter( channels );
+ ChannelDesc *itdesc;
+
+ iter.toFirst();
+ while ( (itdesc=iter.current())!=0 ) {
+ if ( itdesc->name==name ) {
+ dvbZap( itdesc );
+ break;
+ }
+ ++iter;
+ }
+}
+
+
+
+void DvbPanel::channelSelected( QListViewItem *it )
+{
+ QPtrListIterator<ChannelDesc> iter( channels );
+ ChannelDesc *itdesc;
+
+ if ( !it )
+ return;
+
+ iter.toFirst();
+ while ( (itdesc=iter.current())!=0 ) {
+ if ( itdesc->name==it->text(1) ) {
+ dvbZap( itdesc );
+ break;
+ }
+ ++iter;
+ }
+}
+
+
+
+bool DvbPanel::nextTrack( MRL& )
+{
+ next();
+ return false;
+}
+
+
+
+bool DvbPanel::previousTrack( MRL& )
+{
+ previous();
+ return false;
+}
+
+
+
+bool DvbPanel::currentTrack( MRL& )
+{
+ playLastChannel();
+ return false;
+}
+
+
+
+bool DvbPanel::trackNumber( int num, MRL& )
+{
+ playNumChannel( num );
+ return false;
+}
+
+
+
+void DvbPanel::recallZap()
+{
+ emit showMe( this );
+ playNumChannel( recallChannel );
+}
+
+
+
+void DvbPanel::playNumChannel( int num )
+{
+ int j;
+ bool ok=false;
+
+ if ( !channelsCb->isEnabled() )
+ return;
+
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ if ( (int)channels.at(j)->num==num ) {
+ ok = true;
+ break;
+ }
+ }
+
+ if ( ok )
+ dvbZap( channels.at( j ) );
+}
+
+
+
+bool DvbPanel::playbackFinished( MRL& )
+{
+ return false;
+}
+
+
+
+void DvbPanel::playLastChannel()
+{
+ /*int ret, i, j;
+ QPtrList<ChannelDesc> list;
+ bool live=false, ok=false;
+ DvbStream *d;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasBroadcast() )
+ dvb.at(i)->stopBroadcast();
+ }
+ ++dvbConfig->lastChannel;
+ if ( dvbConfig->lastChannel>channels.count() )
+ dvbConfig->lastChannel = 1;
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ if ( (int)channels.at(j)->num==dvbConfig->lastChannel ) {
+ ok = true;
+ list.append( channels.at(j) );
+ break;
+ }
+ }
+ if ( ! list.count() ) {
+ QTimer::singleShot( 2000, this, SLOT(playLastChannel()) );
+ return;
+ }
+ d = getWorkingDvb( 2, list.at(0) );
+ if ( d )
+ ret = d->canStartBroadcast( live, list.at(0) );
+ else
+ ret = -1;
+ if ( ret==0 ) {
+ if ( live ) {
+ stopLive();
+ emit dvbStop();
+ }
+ if ( !d->startBroadcast( &list, rtp ) ) {
+ fprintf( stderr, "Broadcasting failed.\n" );
+ }
+ else {
+ fprintf( stderr, "Tuning to: %s / autocount: %lu\n", channels.at(j)->name.ascii(), autocount );
+ ++autocount;
+ }
+ }
+ else
+ fprintf( stderr, "Can't start broadcasting.\n");
+
+ QTimer::singleShot( 2000, this, SLOT(playLastChannel()) );
+ return;*/
+
+
+
+
+ int j;
+ bool ok=false;
+
+ if ( !channelsCb->isEnabled() )
+ return;
+
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ if ( (int)channels.at(j)->num==dvbConfig->lastChannel ) {
+ ok = true;
+ break;
+ }
+ }
+ if ( !ok )
+ return;
+
+ dvbZap( channels.at(j) );
+}
+
+
+
+void DvbPanel::next()
+{
+ if ( !channelsCb->isEnabled() )
+ return;
+
+ QListViewItem* nextItem;
+
+ QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 );
+
+ if ( !playingItem == 0 ) // yes, it's in the current category
+ {
+ if ( playingItem == channelsCb->lastItem() )
+ nextItem = channelsCb->firstChild(); // wrap around
+ else
+ nextItem = playingItem->itemBelow();
+ }
+ else // not in current category, user has switched category, use first in current cat
+ nextItem = channelsCb->firstChild();
+
+ channelsCb->setSelected( nextItem, true );
+ channelSelected( nextItem );
+
+}
+
+
+
+void DvbPanel::previous()
+{
+ if ( !channelsCb->isEnabled() )
+ return;
+
+ QListViewItem* prevItem;
+
+ QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 );
+
+ if ( !playingItem == 0 ) // yes, it's in the current category
+ {
+ if ( playingItem == channelsCb->firstChild() )
+ prevItem = channelsCb->lastItem(); // wrap around
+ else
+ prevItem = playingItem->itemAbove();
+ }
+ else // not in current category, user has switched category, use first in current cat
+ prevItem = channelsCb->firstChild();
+
+ channelsCb->setSelected( prevItem, true );
+ channelSelected( prevItem );
+}
+
+
+
+void DvbPanel::dvbZap( ChannelDesc *chan )
+{
+ int i;
+ DvbStream *d=0;
+
+ if ( currentFifo.isEmpty() || isTuning )
+ return;
+
+ isTuning = true;
+ emit setTimeShiftFilename( "" );
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) {
+ d = dvb.at(i);
+ break;
+ }
+ }
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasLive() ) {
+ dvb.at(i)->preStopLive();
+ emit dvbPause( false );
+ dvb.at(i)->stopLive( chan );
+ break;
+ }
+ }
+ finalZap( d, chan );
+}
+
+
+
+void DvbPanel::pipeOpened()
+{
+ tuningTimer.start( 1000, true );
+}
+
+
+
+void DvbPanel::setTuning()
+{
+ tuningTimer.stop();
+ stopTuningTimer.stop();
+ isTuning = false;
+}
+
+
+
+void DvbPanel::finalZap( DvbStream *d, ChannelDesc *chan )
+{
+ QString s, t;
+ int i;
+ DvbStream *d1=d, *d2=0;
+
+ emit setCurrentPlugin( this );
+
+ fprintf( stderr, "Tuning to: %s / autocount: %lu\n", chan->name.latin1(), autocount );
+ QTime tm;
+ tm.start();
+ if ( !d1 ) {
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( !dvb.at(i)->canSource( chan ) )
+ continue;
+ if ( dvb.at(i)->isTuned() ) {
+ if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) {
+ d1 = dvb.at(i);
+ break;
+ }
+ else d2 = dvb.at(i);
+ }
+ else {
+ d1 = dvb.at(i);
+ break;
+ }
+ }
+ if ( !d1 && d2 )
+ d1 = d2;
+ }
+
+ if ( !d1 ) {
+ emit dvbStop();
+ isTuning = false;
+ return;
+ }
+
+ int ret = d1->goLive( chan, currentFifo );
+
+ switch ( ret ) {
+ case DvbStream::ErrIsRecording :
+ emit showOSD( i18n("Still recording."), 5000, 3 );
+ break;
+ case DvbStream::ErrIsBroadcasting :
+ emit showOSD( i18n("Still broadcasting."), 5000, 3 );
+ break;
+ case DvbStream::ErrCantTune :
+ emit showOSD( i18n("Can't tune dvb!"), 5000, 3 );
+ break;
+ case DvbStream::ErrCantSetPids :
+ emit showOSD( i18n("Can't set pid(s)"), 5000, 3 );
+ break;
+ case DvbStream::ErrCamUsed :
+ emit showOSD( i18n("No CAM free"), 5000, 3 );
+ break;
+ }
+
+ fprintf( stderr, "Tuning delay: %d ms\n", tm.elapsed() );
+ osdMode = 0;
+ if ( ret<1 ) {
+ emit dvbOpen( currentFifo, s.setNum( chan->num)+" - "+chan->name, chan->vpid );
+ showOsdTimer.start( 2000, true );
+ ++autocount;
+ stopTuningTimer.start( 5000, true );
+ if ( currentFifo==fifoName ) {
+ if ( !fifoName1.isEmpty() )
+ currentFifo = fifoName1;
+ }
+ else {
+ if ( !fifoName.isEmpty() )
+ currentFifo = fifoName;
+ }
+ if ( channelsCb->visibleItems<5 ) {
+ resetSearch();
+ }
+
+ if ( d1->liveIsRecording() )
+ recordBtn->setOn( true );
+ else
+ recordBtn->setOn( false );
+ }
+ else {
+ recordBtn->setOn( false );
+ isTuning = false;
+ emit dvbStop();
+ }
+ if ( dvbConfig->lastChannel!=(int)chan->num ) {
+ recallChannel = dvbConfig->lastChannel;
+ dvbConfig->lastChannel = chan->num;
+ }
+ //QTimer::singleShot( 3000, this, SLOT(playLastChannel()) );
+}
+
+
+
+void DvbPanel::pauseLiveTV()
+{
+ int i;
+ DvbStream *d=0;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasLive() ) {
+ d = dvb.at(i);
+ break;
+ }
+ }
+ if ( !d )
+ return;
+
+ timeShiftFileName = dvbConfig->shiftDir+"DVBLive-"+QDateTime::currentDateTime().toString("yyyyMMddThhmmss")+".m2t";
+ if ( d->doPause( timeShiftFileName ) )
+ emit setTimeShiftFilename( timeShiftFileName );
+}
+
+
+
+bool DvbPanel::timeShiftMode()
+{
+ int i;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasLive() ) {
+ return dvb.at(i)->timeShiftMode();
+ break;
+ }
+ }
+ return false;
+}
+
+
+
+void DvbPanel::stopLive()
+{
+ int i;
+ ChannelDesc chan;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasLive() ) {
+ recallChannel = dvb.at(i)->getLiveChannel().num;
+ dvb.at(i)->preStopLive();
+ dvb.at(i)->stopLive( &chan );
+ break;
+ }
+ }
+ recordBtn->setOn( false );
+ emit setTimeShiftFilename( "" );
+}
+
+
+// TV | vpid(stream_type) | apid1(lang)(ac3),apid2, | ttpid | sid | tsid | type(S,C,T)source | freq | sr | pol | fecH | inv | mod | fecL | bw | trans | guard | hier | number / subpid1(type)(pageid)(ancid)(lang),subpid2..., | category | nid |
+bool DvbPanel::getChannelList()
+{
+ bool ret=false;
+ QString s, c, t, u, type;
+ int pos, tpos;
+ ChannelDesc *chan;
+ QString src="";
+ int ns;
+ KListViewItem *it;
+ QPixmap pix;
+
+ maxChannelNumber = 0;
+ minChannelNumber = -1;
+
+ int sort = dvbConfig->readDvbChanOrder();
+ if ( sort ) {
+ int column = sort&1;
+ int order = sort>>1;
+ switch (order){
+ case 1:
+ channelsCb->setSorting ( column, FALSE );
+ break;
+ case 0:
+ channelsCb->setSorting ( column, TRUE );
+ break;
+ }
+ }
+
+ QFile f( locateLocal("appdata", "channels.dvb" ) );
+ if ( f.open(IO_ReadOnly) ) {
+ QTextStream tt( &f );
+ while ( !tt.eof() ) {
+ s = tt.readLine();
+ if ( s.startsWith("#") ) {
+ if ( s.contains("KaxTV") )
+ break;
+ continue;
+ }
+ chan = new ChannelDesc();
+ pos = s.find("|");
+ c = s.left( pos );
+ if ( c=="TV" || c=="TVC" )
+ chan->type=1;
+ else
+ chan->type=2;
+ if ( c=="TVC" || c=="RAC" )
+ chan->fta=1;
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ chan->name = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ c = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ tpos = c.find("(");
+ if ( tpos>0 )
+ chan->vpid = c.left(tpos).toUShort();
+ else
+ chan->vpid = c.toUShort();
+ if( tpos>0 ) {
+ t = c.right( c.length()-tpos-1);
+ t.remove(")");
+ chan->vType = t.toUShort();
+ }
+ else
+ chan->vType = 2;
+ if ( !chan->vpid )
+ chan->vType = 0;
+ pos = s.find("|");
+ c = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ while ( (pos=c.find(","))!=-1 ) {
+ t = c.left(pos);
+ chan->napid++;
+ if ( t.contains("(ac3)") ) {
+ chan->apid[chan->napid-1].ac3=1;
+ t.remove("(ac3)");
+ }
+ if( (tpos=t.find("("))!=-1 ) {
+ t.remove(")");
+ chan->apid[chan->napid-1].lang=t.right( t.length()-tpos-1 );
+ t = t.left( tpos );
+ }
+ chan->apid[chan->napid-1].pid=t.toUShort();
+ c = c.right( c.length()-pos-1 );
+ }
+ pos = s.find("|");
+ chan->ttpid = s.left(pos).toUShort();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ chan->sid = s.left(pos).toUShort();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ chan->tp.tsid = s.left(pos).toUShort();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ c = s.left(pos);
+ if ( c.startsWith("T") ) {
+ chan->tp.type=FE_OFDM;
+ chan->tp.source = "Terrestrial";
+ }
+ else if ( c.startsWith("C") ) {
+ chan->tp.type=FE_QAM;
+ chan->tp.source = "Cable";
+ }
+ else if ( c.startsWith("S") ) {
+ chan->tp.type=FE_QPSK;
+ c.remove( 0, 1 );
+ chan->tp.source = c;
+ }
+ else {
+ chan->tp.type=FE_ATSC;
+ chan->tp.source = "Atsc";
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ chan->tp.freq = s.left(pos).toULong();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ chan->tp.sr = s.left(pos).toULong();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ c = s.left( pos );
+ chan->tp.pol = c[0].latin1();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 0 : chan->tp.coderateH = FEC_NONE; break;
+ case 12 : chan->tp.coderateH = FEC_1_2; break;
+ case 23 : chan->tp.coderateH = FEC_2_3; break;
+ case 34 : chan->tp.coderateH = FEC_3_4; break;
+ case 45 : chan->tp.coderateH = FEC_4_5; break;
+ case 56 : chan->tp.coderateH = FEC_5_6; break;
+ case 67 : chan->tp.coderateH = FEC_6_7; break;
+ case 78 : chan->tp.coderateH = FEC_7_8; break;
+ case 89 : chan->tp.coderateH = FEC_8_9; break;
+ case -1 : chan->tp.coderateH = FEC_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 0 : chan->tp.inversion = INVERSION_OFF; break;
+ case 1 : chan->tp.inversion = INVERSION_ON; break;
+ case -1 : chan->tp.inversion = INVERSION_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 8 : chan->tp.modulation = QPSK; break;
+ case 16 : chan->tp.modulation = QAM_16; break;
+ case 32 : chan->tp.modulation = QAM_32; break;
+ case 64 : chan->tp.modulation = QAM_64; break;
+ case 128 : chan->tp.modulation = QAM_128; break;
+ case 256 : chan->tp.modulation = QAM_256; break;
+ case 108 : chan->tp.modulation = VSB_8; break;
+ case 116 : chan->tp.modulation = VSB_16; break;
+ case -1 : chan->tp.modulation = QAM_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 0 : chan->tp.coderateL = FEC_NONE; break;
+ case 12 : chan->tp.coderateL = FEC_1_2; break;
+ case 23 : chan->tp.coderateL = FEC_2_3; break;
+ case 34 : chan->tp.coderateL = FEC_3_4; break;
+ case 45 : chan->tp.coderateL = FEC_4_5; break;
+ case 56 : chan->tp.coderateL = FEC_5_6; break;
+ case 67 : chan->tp.coderateL = FEC_6_7; break;
+ case 78 : chan->tp.coderateL = FEC_7_8; break;
+ case 89 : chan->tp.coderateL = FEC_8_9; break;
+ case -1 : chan->tp.coderateL = FEC_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 8 : chan->tp.bandwidth = BANDWIDTH_8_MHZ; break;
+ case 7 : chan->tp.bandwidth = BANDWIDTH_7_MHZ; break;
+ case 6 : chan->tp.bandwidth = BANDWIDTH_6_MHZ; break;
+ case -1 : chan->tp.bandwidth = BANDWIDTH_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 2 : chan->tp.transmission = TRANSMISSION_MODE_2K; break;
+ case 8 : chan->tp.transmission = TRANSMISSION_MODE_8K; break;
+ case -1 : chan->tp.transmission = TRANSMISSION_MODE_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 32 : chan->tp.guard = GUARD_INTERVAL_1_32; break;
+ case 16 : chan->tp.guard = GUARD_INTERVAL_1_16; break;
+ case 8 : chan->tp.guard = GUARD_INTERVAL_1_8; break;
+ case 4 : chan->tp.guard = GUARD_INTERVAL_1_4; break;
+ case -1 : chan->tp.guard = GUARD_INTERVAL_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ switch ( s.left(pos).toInt() ) {
+ case 0 : chan->tp.hierarchy = HIERARCHY_NONE; break;
+ case 1 : chan->tp.hierarchy = HIERARCHY_1; break;
+ case 2 : chan->tp.hierarchy = HIERARCHY_2; break;
+ case 4 : chan->tp.hierarchy = HIERARCHY_4; break;
+ case -1 : chan->tp.hierarchy = HIERARCHY_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ chan->num = s.left(pos).toUInt();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ c = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ while ( (pos=c.find(","))!=-1 ) {
+ t = c.left(pos);
+ tpos=t.find("(");
+ ns = (int)chan->nsubpid;
+ chan->subpid[ns].pid = t.left(tpos).toUShort();
+ t = t.right( t.length()-tpos-1 );
+ tpos=t.find(")");
+ chan->subpid[ns].type = t.left(tpos).toUShort();
+ t = t.right( t.length()-tpos-2 );
+ tpos=t.find(")");
+ chan->subpid[ns].page = t.left(tpos).toUShort();
+ t = t.right( t.length()-tpos-2 );
+ tpos=t.find(")");
+ chan->subpid[ns].id = t.left(tpos).toUShort();
+ t = t.right( t.length()-tpos-2 );
+ tpos=t.find(")");
+ chan->subpid[ns].lang = t.left(tpos);
+ c = c.right( c.length()-pos-1 );
+ chan->nsubpid++;
+ }
+ pos = s.find("|");
+ chan->category = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ chan->tp.nid = s.left(pos).toUShort();
+
+ if ( chan->tp.source.isEmpty() ) {
+ delete chan;
+ continue;
+ }
+
+ chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name );
+ it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source );
+ it->setDragEnabled( true );
+ if ( !chan->pix.isNull() )
+ it->setPixmap( 1, chan->pix );
+ else {
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ it->setPixmap( 1, tvcPix );
+ else
+ it->setPixmap( 1, tvPix );
+ }
+ else {
+ if ( chan->fta )
+ it->setPixmap( 1, racPix );
+ else
+ it->setPixmap( 1, raPix );
+ }
+ }
+ channels.append( chan );
+ if ( chan->num<=0 )
+ chan->num = channels.count();
+
+ if ( (int)chan->num > maxChannelNumber )
+ maxChannelNumber = chan->num;
+ if ( minChannelNumber == -1 || (int)chan->num < minChannelNumber )
+ minChannelNumber = chan->num;
+
+ }
+ ret = true;
+ f.close();
+ }
+ return ret;
+}
+
+
+
+bool DvbPanel::saveChannelList()
+{
+ bool ret=false;
+ int i, k;
+ QString s;
+ ChannelDesc *chan=0;
+
+ QFile f( locateLocal("appdata", "channels.dvb" ) );
+ if ( f.open(IO_WriteOnly|IO_Truncate) ) {
+ QTextStream tt( &f );
+ tt<<"#Generated by Kaffeine 0.5\n";
+ for( i=0; i<(int)channels.count(); i++ ) {
+ chan = channels.at(i);
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ tt<<"TVC|";
+ else
+ tt<<"TV|";
+ }
+ else {
+ if ( chan->fta )
+ tt<<"RAC|";
+ else
+ tt<<"RA|";
+ }
+ tt<< chan->name+"|";
+ tt<< s.setNum(chan->vpid);
+ if ( chan->vType ) {
+ tt<< "(";
+ tt<< s.setNum(chan->vType);
+ tt<< ")";
+ }
+ tt<< "|";
+ for ( k=0; k<chan->napid; k++ ) {
+ tt<< s.setNum(chan->apid[k].pid);
+ if ( !chan->apid[k].lang.isEmpty() )
+ tt<< "("+chan->apid[k].lang+")";
+ if ( chan->apid[k].ac3 )
+ tt<< "(ac3)";
+ tt<< ",";
+ }
+ tt<< "|";
+ tt<< s.setNum(chan->ttpid)+"|";
+ tt<< s.setNum(chan->sid)+"|";
+ tt<< s.setNum(chan->tp.tsid)+"|";
+ switch ( chan->tp.type ) {
+ case FE_QPSK : tt<< "S"; tt<< chan->tp.source; break;
+ case FE_QAM : tt<< "Cable"; break;
+ case FE_OFDM : tt<< "Terrestrial"; break;
+ case FE_ATSC : tt<< "Atsc"; break;
+ }
+ tt<< "|";
+ tt<< s.setNum(chan->tp.freq)+"|";
+ tt<< s.setNum(chan->tp.sr)+"|";
+ if ( chan->tp.pol=='h' )
+ tt<< "h|";
+ else
+ tt<< "v|";
+ switch ( chan->tp.coderateH ) {
+ case FEC_NONE : tt<< "0|"; break;
+ case FEC_1_2 : tt<< "12|"; break;
+ case FEC_2_3 : tt<< "23|"; break;
+ case FEC_3_4 : tt<< "34|"; break;
+ case FEC_4_5 : tt<< "45|"; break;
+ case FEC_5_6 : tt<< "56|"; break;
+ case FEC_6_7 : tt<< "67|"; break;
+ case FEC_7_8 : tt<< "78|"; break;
+ case FEC_8_9 : tt<< "89|"; break;
+ case FEC_AUTO : tt<< "-1|";
+ }
+ switch ( chan->tp.inversion ) {
+ case INVERSION_OFF : tt<< "0|"; break;
+ case INVERSION_ON : tt<< "1|"; break;
+ case INVERSION_AUTO : tt<< "-1|";
+ }
+ switch ( chan->tp.modulation ) {
+ case QPSK : tt<< "8|"; break;
+ case QAM_16 : tt<< "16|"; break;
+ case QAM_32 : tt<< "32|"; break;
+ case QAM_64 : tt<< "64|"; break;
+ case QAM_128 : tt<< "128|"; break;
+ case QAM_256 : tt<< "256|"; break;
+ case VSB_8 : tt<< "108|"; break;
+ case VSB_16 : tt<< "116|"; break;
+ case QAM_AUTO : tt<< "-1|";
+ }
+ switch ( chan->tp.coderateL ) {
+ case FEC_NONE : tt<< "0|"; break;
+ case FEC_1_2 : tt<< "12|"; break;
+ case FEC_2_3 : tt<< "23|"; break;
+ case FEC_3_4 : tt<< "34|"; break;
+ case FEC_4_5 : tt<< "45|"; break;
+ case FEC_5_6 : tt<< "56|"; break;
+ case FEC_6_7 : tt<< "67|"; break;
+ case FEC_7_8 : tt<< "78|"; break;
+ case FEC_8_9 : tt<< "89|"; break;
+ case FEC_AUTO : tt<< "-1|";
+ }
+ switch ( chan->tp.bandwidth ) {
+ case BANDWIDTH_8_MHZ : tt<< "8|"; break;
+ case BANDWIDTH_7_MHZ : tt<< "7|"; break;
+ case BANDWIDTH_6_MHZ : tt<< "6|"; break;
+ case BANDWIDTH_AUTO : tt<< "-1|";
+ }
+ switch ( chan->tp.transmission ) {
+ case TRANSMISSION_MODE_8K : tt<< "8|"; break;
+ case TRANSMISSION_MODE_2K : tt<< "2|"; break;
+ case TRANSMISSION_MODE_AUTO : tt<< "-1|";
+ }
+ switch ( chan->tp.guard ) {
+ case GUARD_INTERVAL_1_32 : tt<< "32|"; break;
+ case GUARD_INTERVAL_1_16 : tt<< "16|"; break;
+ case GUARD_INTERVAL_1_8 : tt<< "8|"; break;
+ case GUARD_INTERVAL_1_4 : tt<< "4|"; break;
+ case GUARD_INTERVAL_AUTO : tt<< "-1|";
+ }
+ switch ( chan->tp.hierarchy ) {
+ case HIERARCHY_NONE : tt<< "0|"; break;
+ case HIERARCHY_1 : tt<< "1|"; break;
+ case HIERARCHY_2 : tt<< "2|"; break;
+ case HIERARCHY_4 : tt<< "4|"; break;
+ case HIERARCHY_AUTO : tt<< "-1|";
+ }
+ tt<< s.setNum(chan->num)+"|";
+ for ( k=0; k<chan->nsubpid; k++ ) {
+ tt<< s.setNum(chan->subpid[k].pid);
+ tt<< "("+s.setNum(chan->subpid[k].type)+")";
+ tt<< "("+s.setNum(chan->subpid[k].page)+")";
+ tt<< "("+s.setNum(chan->subpid[k].id)+")";
+ tt<< "("+chan->subpid[k].lang+")";
+ tt<< ",";
+ }
+ tt<< "|";
+ tt<< chan->category+"|";
+ tt<< s.setNum(chan->tp.nid)+"|\n";
+ }
+ ret = true;
+ f.close();
+ }
+ return ret;
+}
+
+
+
+bool DvbPanel::getTimerList()
+{
+ bool ret=false;
+ QString s;
+ int pos;
+ RecTimer *t;
+
+ QFile f( locateLocal("appdata", "timers.dvb" ) );
+ if ( f.open(IO_ReadOnly) ) {
+ QTextStream tt( &f );
+ while ( !tt.eof() ) {
+ s = tt.readLine();
+ if ( s.startsWith("#") )
+ continue;
+ t = new RecTimer();
+ pos = s.find("|");
+ t->name = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ t->channel = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ t->begin = QDateTime::fromString( s.left( pos ), Qt::ISODate );
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ t->duration = QTime::fromString( s.left( pos ) );
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ //t->filetype = s.left( pos ).toInt();
+ t->mode = 0;
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ t->mode = s.left( pos ).toInt();
+ t->running = 0;
+ timers.append( t );
+ }
+ ret = true;
+ f.close();
+ }
+ return ret;
+}
+
+
+
+bool DvbPanel::saveTimerList()
+{
+ bool ret=false;
+ int i;
+ QString s;
+ RecTimer *t;
+
+ QFile f( locateLocal("appdata", "timers.dvb" ) );
+ if ( f.open(IO_WriteOnly|IO_Truncate) ) {
+ QTextStream tt( &f );
+ tt<<"#Generated by Kaffeine 0.5\n";
+ for( i=0; i<(int)timers.count(); i++ ) {
+ t = timers.at(i);
+ if ( t->running && !t->mode )
+ continue;
+ tt<< t->name+"|";
+ tt<< t->channel+"|";
+ tt<< t->begin.toString("yyyy-MM-ddThh:mm:ss")+"|";
+ tt<< t->duration.toString()+"|";
+ tt<< s.setNum(0/*t->filetype*/)+"|";
+ tt<< s.setNum(t->mode)+"|";
+ tt<< "\n";
+ }
+ ret = true;
+ f.close();
+ }
+ return ret;
+}
+
+
+
+bool DvbPanel::close()
+{
+ int ret=0, i;
+ bool rec = false;
+
+ for ( i=0; i<(int)dvb.count(); i++ ) {
+ if ( dvb.at(i)->hasRec() ) {
+ rec = true;
+ break;
+ }
+ }
+
+ if ( rec ) {
+ ret = KMessageBox::questionYesNo( 0, i18n("Kaffeine is still recording. Do you really want to quit?") );
+ if ( ret!=KMessageBox::Yes )
+ return false;
+ }
+ else if ( timers.count() ) {
+ ret = KMessageBox::questionYesNo( 0, i18n("Kaffeine has queued timers. Do you really want to quit?") );
+ if ( ret!=KMessageBox::Yes )
+ return false;
+ }
+ emit dvbStop();
+ stopLive();
+ return true;
+}
+
+
+
+void DvbPanel::saveConfig()
+{
+ saveTimerList();
+ saveChannelList();
+ dvbConfig->splitSizes = split->sizes();
+ dvbConfig->saveDvbChanOrder( channelsCb->sortOrder(), channelsCb->sortColumn() );
+ dvbConfig->saveConfig();
+ //delete dvbConfig;
+}
+
+
+DvbPanel::~DvbPanel()
+{
+ dvb.clear();
+ delete rtp;
+ delete cleaner;
+ if ( plug ) {
+ KService::Ptr service = KService::serviceByDesktopName( plugName );
+ KLibLoader::self()->unloadLibrary( service->library().ascii() );
+ }
+ events.saveEpg();
+}
+
+#include "dvbpanel.moc"
diff --git a/kaffeine/src/input/dvb/dvbpanel.h b/kaffeine/src/input/dvb/dvbpanel.h
new file mode 100644
index 0000000..5545040
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbpanel.h
@@ -0,0 +1,242 @@
+/*
+ * dvbpanel.h
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBPANEL_H
+#define DVBPANEL_H
+
+#include <qframe.h>
+#include <qcombobox.h>
+#include <qtoolbutton.h>
+#include <qptrlist.h>
+#include <qtimer.h>
+#include <qsplitter.h>
+#include <qvbox.h>
+
+#include <kapp.h>
+#include <kpushbutton.h>
+#include <kled.h>
+#include <klistview.h>
+#include <kiconview.h>
+#include <klineedit.h>
+
+#include "scandialog.h"
+#include "dvbconfig.h"
+#include "krecord.h"
+#include "ts2rtp.h"
+#include "cleaner.h"
+#include "dvbevents.h"
+
+
+
+class ChannelDesc;
+class DvbStream;
+class DvbPanel;
+class KaffeineInput;
+class KaffeineDvbPlugin;
+
+
+
+class DListView : public KListView
+{
+ Q_OBJECT
+public:
+ DListView( QWidget *parent );
+
+ int visibleItems;
+
+protected:
+ virtual QDragObject* dragObject();
+};
+
+
+
+class DIconViewItem : public KIconViewItem
+{
+public:
+ DIconViewItem( DvbPanel *pan, QIconView *parent, const QString &text, const QPixmap &icon );
+protected:
+ void dropped( QDropEvent *e, const QValueList<QIconDragItem> & );
+private:
+ DvbPanel *panel;
+};
+
+
+
+class DvbPanel : public KaffeineInput
+{
+ Q_OBJECT
+
+public:
+
+ DvbPanel( QWidget *parent, QObject *objParent, const char *name=0);
+ ~DvbPanel();
+ bool getChannelList();
+ bool saveChannelList();
+ bool timeShiftMode();
+ void setConfig();
+ void enableLiveDvb( bool on );
+ void checkFirstRun();
+ void moveChannel( const QString &cat, const QString &name );
+
+ // Reimplemented from KaffeineInput
+ QWidget *wantPlayerWindow();
+ QWidget *inputMainWidget();
+ void toggleLayout( bool );
+ bool close();
+ bool nextTrack( MRL& );
+ bool previousTrack( MRL& );
+ bool currentTrack( MRL& );
+ bool trackNumber( int, MRL& );
+ bool playbackFinished( MRL& );
+ void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames );
+ void togglePanel();
+ bool execTarget( const QString& );
+ void saveConfig();
+ //***************************************
+
+ QPtrList<ChannelDesc> channels;
+ QPtrList<RecTimer> timers;
+ QPtrList<DvbStream> dvb;
+ QString fifoName, fifoName1, currentFifo;
+ QString timeShiftFileName;
+ Ts2Rtp *rtp;
+ QVBox *mainWidget;
+ QVBox *playerBox, *pbox;
+
+public slots:
+
+ void playLastChannel();
+ void playNumChannel( int num );
+ void stopLive();
+ void setShiftLed( bool on );
+ void setRecordLed( bool on );
+ void setBroadcastLed( bool on );
+ void setRecord();
+ void setBroadcast();
+ void pauseLiveTV();
+ void killTimer( RecTimer *t );
+ void showEvents();
+ void showTimers();
+ void scanner();
+ void showConfigDialog();
+ void next();
+ void previous();
+ void recallZap();
+ void dvbOSD();
+
+ void dvbOSDNext();
+ void dvbOSDPrev();
+ void dvbOSDSkip(int skip, int timeShift = 0);
+ void dvbOSDZap();
+ void dvbOSDHide();
+
+ void dvbOSDAdvance();
+ void dvbOSDRetreat();
+
+ void dvbNewTimer( QString name, QString channel, QString datetime, QString duration );
+ int getSNR( int device );
+ void diskStatus();
+
+private:
+
+ void setupActions();
+ bool getTimerList();
+ bool saveTimerList();
+ void fillChannelList( ChannelDesc *ch=0 );
+ QPtrList<Transponder> getSourcesStatus();
+ void updateModeTimer( RecTimer *t );
+ DvbStream* getWorkingDvb( int mode, ChannelDesc *chan );
+
+ void dvbOSD(ChannelDesc liveChannel, DvbStream *d, int timeShift = 0);
+ DvbStream* getLiveDVBStream();
+
+ QPixmap tvPix, raPix, tvcPix, racPix;
+ QSplitter *split;
+ QFrame *panel;
+ KIconView *iconView;
+ DListView *channelsCb;
+ QToolButton *broadcastBtn, *recordBtn;
+ QToolButton *dateBtn, *infoBtn, *channelsBtn, *configBtn, *osdBtn, *recallBtn;
+ KLed *shiftLed, *recordLed, *broadcastLed;
+ QTimer timersTimer;
+ DVBconfig *dvbConfig;
+ KRecord *timersDialog;
+ int updown;
+ unsigned long autocount;
+ int currentChannelNumber;
+ Cleaner *cleaner;
+ int osdMode;
+ QTimer osdTimer;
+ QTimer showOsdTimer;
+ QString currentCategory;
+ bool isTuning;
+ QTimer tuningTimer, stopTuningTimer;
+ QTimer diskTimer;
+ KLineEdit *searchLE;
+ QToolButton *searchBtn;
+ int recallChannel;
+
+ int browseDvbStream;
+ int maxChannelNumber, minChannelNumber;
+ int browseDvbTimeShift;
+
+ KaffeineDvbPlugin *plug;
+ QString plugName;
+
+ EventTable events;
+
+private slots:
+
+ void searchChannel( const QString &text );
+ void resetSearch();
+ void checkTimers();
+ bool editChannel( QString &name );
+ void channelSelected( QListViewItem *it );
+ void channelClicked( QListViewItem *it );
+ void channelSelected( const QString &name );
+ void channelPopup( QListViewItem *it, const QPoint &pos, int col );
+ void dvbZap( ChannelDesc *chan );
+ void finalZap( DvbStream *d, ChannelDesc *chan );
+ void newTimer( QString channel, QString name, QDateTime begin, QTime duration, bool warn=true );
+ void dumpEvents();
+ void resetOSD();
+ void catContextMenu( QIconViewItem*, const QPoint& );
+ void catSelected( QIconViewItem* );
+ void channelNumberChanged( QListViewItem* );
+ void pipeOpened();
+ void setTuning();
+
+signals:
+
+ void zap( ChannelDesc* );
+ void playDvb();
+ void timersChanged();
+ void dvbOpen( const QString &filename, const QString &chanName, int haveVideo );
+ void dvbStop();
+ void dvbPause( bool pauseLive );
+ void setTimeShiftFilename( const QString& );
+ void showOSD( const QString &text, int duration, int priority );
+ void showDvbOSD( const QStringList& );
+ void showDvbOSD( const QString&, const QStringList& );
+
+ void updateTimer(RecTimer*, int);
+};
+
+#endif /* DVBPANEL_H */
diff --git a/kaffeine/src/input/dvb/dvbsection.h b/kaffeine/src/input/dvb/dvbsection.h
new file mode 100644
index 0000000..e86e834
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbsection.h
@@ -0,0 +1,26 @@
+/*
+ * dvbsection.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBSECTION_H
+#define DVBSECTION_H
+
+#include "kaffeinedvbsection.h"
+
+#endif /* DVBSECTION_H */
diff --git a/kaffeine/src/input/dvb/dvbsi.cpp b/kaffeine/src/input/dvb/dvbsi.cpp
new file mode 100644
index 0000000..395d796
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbsi.cpp
@@ -0,0 +1,866 @@
+/*
+ * dvbsi.cpp
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/poll.h>
+
+#include <qdir.h>
+
+#include <kapplication.h>
+
+#include "dvbsi.h"
+
+#define TIMER_EVENT_SCAN_END 100
+
+
+
+NitSection::NitSection( QPtrList<Transponder> *tp, bool *end, bool *ok, int anum, int tnum ) : KaffeineDVBsection( anum, tnum )
+{
+ ended = end;
+ transponders = tp;
+ start();
+}
+
+
+
+NitSection::~NitSection()
+{
+ stop();
+}
+
+
+
+void NitSection::stop()
+{
+ if ( !wait(10000) ) {
+ terminate();
+ wait();
+ }
+}
+
+
+
+void NitSection::run()
+{
+ getSection( 0x10, 0x40, 60000 );
+ *ended = true;
+}
+
+
+
+bool NitSection::getSection( int pid, int tid, int timeout )
+{
+ unsigned char buf[4096];
+ int i, n=0;
+ int skip=0;
+ int last=1, current=0, loop=0;
+ QValueList<int> list;
+
+ if ( !setFilter( pid, tid, timeout ) )
+ return false;
+
+ do {
+ if ( poll(pf,1,timeout)>0 ){
+ if ( pf[0].revents & POLLIN ){
+ n = read( fdDemux, buf, 4096 );
+ skip = 0;
+ }
+ else
+ skip++;
+ }
+ else
+ skip++;
+
+ if ( skip || n<4 ) {
+ fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid);
+ stopFilter();
+ return false;
+ }
+
+ last = getBits(buf,56,8);
+ current = getBits(buf,48,8);
+ for ( i=0; i<(int)list.count(); i++ ) {
+ if ( current==list[i] ) {
+ i = -1;
+ break;
+ }
+ }
+ if ( i>-1 )
+ list.append( current );
+ else {
+ loop++; // missing section ?
+ continue;
+ }
+ switch ( getBits(buf,0,8) ) {
+ case 0x40 :
+ fprintf(stderr,"Reading NIT: pid=%d\n", pid);
+ tableNIT( buf );
+ break;
+ default:
+ break;
+ }
+ loop = 0;
+ } while ( (int)list.count()<=last && loop<=last );
+
+ stopFilter();
+ return true;
+}
+
+
+
+bool NitSection::tableNIT( unsigned char* buf )
+{
+ int length, loop, i, j;
+ Transponder *trans, *curtrans;
+
+ loop = getBits(buf,68,12);
+ buf +=10+loop;
+ length = getBits(buf,4,12);
+ buf +=2;
+
+ while ( length>0 ) {
+ trans = new Transponder();
+ trans->source = transponders->at(0)->source;
+ trans->tsid = getBits(buf,0,16);
+ loop = getBits(buf,36,12);
+ buf +=6;
+ length -=(6+loop);
+ while ( loop>0 ) {
+ switch ( getBits(buf,0,8) ) {
+ case 0x43 :
+ satelliteDesc( buf, trans );
+ break;
+ case 0x44 :
+ cableDesc( buf, trans );
+ break;
+ case 0x5a :
+ terrestrialDesc( buf, trans );
+ break;
+ case 0x62 :
+ fprintf(stderr," Found frequency list.\n");
+ freqListDesc( buf, trans );
+ break;
+ default :
+ break;
+ }
+ loop -=( getBits(buf,8,8)+2 );
+ buf +=( getBits(buf,8,8)+2 );
+ }
+ if ( trans->freq==0 ) {
+ delete trans;
+ continue;
+ }
+ curtrans = 0;
+ for ( i=0; i<(int)transponders->count(); i++ ) {
+ if ( trans->tsid==transponders->at(i)->tsid || trans->sameAs( transponders->at(i) ) ) {
+ curtrans = transponders->at(i);
+ break;
+ }
+ }
+ if ( !curtrans )
+ transponders->append( trans );
+ else {
+ for ( i=0; i<(int)trans->freqlist.count(); i++ ) {
+ for ( j=0; j<(int)curtrans->freqlist.count(); j++ ) {
+ if ( curtrans->freqlist[j]==trans->freqlist[i] ) {
+ j = -1;
+ break;
+ }
+ }
+ if ( j!=-1 ) {
+ fprintf(stderr," Appending freq %lu to %lu\n", trans->freqlist[i], curtrans->freq );
+ curtrans->freqlist.append( trans->freqlist[i] );
+ }
+ }
+ delete trans;
+ }
+ }
+
+ return true;
+}
+
+
+
+void NitSection::satelliteDesc( unsigned char* buf, Transponder *trans )
+{
+ QString s, t;
+
+ trans->type = FE_QPSK;
+ s = t.setNum( getBits(buf,16,32), 16 );
+ trans->freq = s.toInt();
+ trans->freq /=100;
+ if ( getBits(buf,65,2) )
+ trans->pol = 'v';
+ else
+ trans->pol = 'h';
+ s = t.setNum( getBits(buf,72,28), 16 );
+ trans->sr = s.toInt();
+ trans->sr /=10;
+ switch ( getBits(buf,100,4) ) {
+ case 1 : trans->coderateH = FEC_1_2; break;
+ case 2 : trans->coderateH = FEC_2_3; break;
+ case 3 : trans->coderateH = FEC_3_4; break;
+ case 4 : trans->coderateH = FEC_5_6; break;
+ case 5 : trans->coderateH = FEC_7_8; break;
+ case 6 : trans->coderateH = FEC_8_9; break;
+ case 7 : trans->coderateH = FEC_NONE; break;
+ }
+}
+
+
+
+void NitSection::cableDesc( unsigned char* buf, Transponder *trans )
+{
+ QString s, t;
+
+ trans->type = FE_QAM;
+ s = t.setNum( getBits(buf,16,32), 16 );
+ trans->freq = s.toInt();
+ trans->freq /=10;
+ switch ( getBits(buf,64,8) ) {
+ case 1 : trans->modulation = QAM_16; break;
+ case 2 : trans->modulation = QAM_32; break;
+ case 3 : trans->modulation = QAM_64; break;
+ case 4 : trans->modulation = QAM_128; break;
+ case 5 : trans->modulation = QAM_256; break;
+ }
+ s = t.setNum( getBits(buf,72,28), 16 );
+ trans->sr = s.toInt();
+ trans->sr /=10;
+ switch ( getBits(buf,100,4) ) {
+ case 1 : trans->coderateH = FEC_1_2; break;
+ case 2 : trans->coderateH = FEC_2_3; break;
+ case 3 : trans->coderateH = FEC_3_4; break;
+ case 4 : trans->coderateH = FEC_5_6; break;
+ case 5 : trans->coderateH = FEC_7_8; break;
+ case 6 : trans->coderateH = FEC_8_9; break;
+ case 7 : trans->coderateH = FEC_NONE; break;
+ }
+}
+
+
+
+void NitSection::terrestrialDesc( unsigned char* buf, Transponder *trans )
+{
+ trans->type = FE_OFDM;
+ trans->freq = getBits(buf,16,32)/100;
+ trans->bandwidth = (fe_bandwidth_t)(BANDWIDTH_8_MHZ + getBits(buf,48,3));
+ switch ( getBits(buf,56,2) ) {
+ case 0 : trans->modulation = QPSK; break;
+ case 1 : trans->modulation = QAM_16; break;
+ case 2 : trans->modulation = QAM_64; break;
+ }
+ trans->hierarchy = (fe_hierarchy_t)(HIERARCHY_NONE + getBits(buf,58,3));
+ switch ( getBits(buf,61,3) ) {
+ case 0 : trans->coderateH = FEC_1_2; break;
+ case 1 : trans->coderateH = FEC_2_3; break;
+ case 2 : trans->coderateH = FEC_3_4; break;
+ case 3 : trans->coderateH = FEC_5_6; break;
+ case 4 : trans->coderateH = FEC_7_8; break;
+ }
+ switch ( getBits(buf,64,3) ) {
+ case 0 : trans->coderateL = FEC_1_2; break;
+ case 1 : trans->coderateL = FEC_2_3; break;
+ case 2 : trans->coderateL = FEC_3_4; break;
+ case 3 : trans->coderateL = FEC_5_6; break;
+ case 4 : trans->coderateL = FEC_7_8; break;
+ }
+ trans->guard = (fe_guard_interval_t)(GUARD_INTERVAL_1_32 + getBits(buf,67,2));
+ switch ( getBits(buf,69,2) ) {
+ case 0 : trans->transmission = TRANSMISSION_MODE_2K; break;
+ case 1 : trans->transmission = TRANSMISSION_MODE_8K; break;
+ }
+}
+
+
+
+void NitSection::freqListDesc( unsigned char* buf, Transponder *trans )
+{
+ unsigned char len, type;
+ unsigned char *b=buf;
+ QString s, t;
+ unsigned long freq;
+
+ len = getBits(b,8,8);
+ type = getBits(b,22,2);
+ len-= 1;
+ b+= 3;
+ while ( len>0 ) {
+ switch ( type ) {
+ case 1: // satellite
+ s = t.setNum( getBits(b,0,32), 16 );
+ freq = s.toInt();
+ freq /=100;
+ fprintf( stderr, " %lu\n", freq );
+ trans->freqlist.append( freq );
+ break;
+ case 2: // cable
+ s = t.setNum( getBits(b,0,32), 16 );
+ freq = s.toInt();
+ freq /=10;
+ fprintf( stderr, " %lu\n", freq );
+ trans->freqlist.append( freq );
+ break;
+ case 3: // terrestrial
+ freq = getBits(b,0,32)/100;
+ fprintf( stderr, " %lu\n", freq );
+ trans->freqlist.append( freq );
+ break;
+ }
+ len-= 4;
+ b+= 4;
+ }
+}
+
+
+
+DVBsi::DVBsi( bool *ok, int anum, int tnum, DvbStream *d, const QString &charset ) : KaffeineDVBsection( anum, tnum, charset )
+{
+ channels.setAutoDelete( true );
+ transponders.setAutoDelete( true );
+ isRunning = false;
+ dvb = d;
+ adapter = anum;
+ tuner = tnum;
+ ns = 0;
+}
+
+
+
+DVBsi::~DVBsi()
+{
+ isRunning = false;
+ wait();
+ channels.clear();
+ transponders.clear();
+}
+
+
+
+void DVBsi::serviceDesc( unsigned char* buf, ChannelDesc *desc )
+{
+ unsigned int i, j;
+
+ desc->type = getBits(buf,16,8);
+ i = getBits(buf,24,8);
+ desc->provider = getText( buf+4, i ).stripWhiteSpace();
+ j = getBits(buf+i,32,8);
+ desc->name = getText( buf+5+i, j ).stripWhiteSpace();
+ if ( desc->name.isEmpty() )
+ desc->name = "Unknown";
+ fprintf(stderr,"%s: sid=%d\n", desc->name.latin1(), desc->sid );
+}
+
+
+
+bool DVBsi::tableSDT( unsigned char* buf )
+{
+ int length, loop;
+ ChannelDesc *desc;
+ QString s;
+ unsigned short tsid;
+ unsigned short nid;
+
+ tsid = getBits(buf+3,0,16);
+ nid = getBits(buf+8,0,16);
+ length = getBits(buf,12,12);
+ length -=8;
+ buf +=11;
+
+ while ( length>4 ) {
+ desc = new ChannelDesc();
+ channels.append( desc );
+ desc->tp.tsid = tsid;
+ desc->tp.nid = nid;
+ desc->sid = getBits(buf,0,16);
+ //desc->fta = getBits(buf,27,1 );
+ loop = getBits(buf,28,12);
+ buf +=5;
+ length -=(5+loop);
+ while ( loop>0 ) {
+ switch ( getBits(buf,0,8) ) {
+ case 0x48 :
+ serviceDesc( buf, desc );
+ break;
+ default :
+ break;
+ }
+ loop -=( getBits(buf,8,8)+2 );
+ buf +=( getBits(buf,8,8)+2 );
+ }
+ }
+ return true;
+}
+
+
+
+bool DVBsi::tablePMT( unsigned char* buf )
+{
+ int length, loop;
+ int type;
+ int sid;
+ int i;
+ int pid=0;
+ ChannelDesc *desc=0;
+ QString lang;
+ int ns;
+ unsigned char st;
+ bool audio, ac3;
+
+
+ sid = getBits(buf+3,0,16);
+ for ( i=indexChannels; i<(int)channels.count(); i++ ) {
+ if ( channels.at( i )->sid==sid ) {
+ desc = channels.at( i );
+ break;
+ }
+ }
+
+ if ( !desc )
+ return false;
+
+ length = getBits(buf,12,12);
+ loop = getBits(buf+10,4,12);
+ length -=(9+loop);
+ buf +=12;
+
+ while ( loop>0 ) {
+ switch ( getBits(buf,0,8) ) {
+ case 0x09 :
+ desc->fta = 1;
+ break;
+ default :
+ break;
+ }
+ loop -=( getBits(buf,8,8)+2 );
+ buf +=( getBits(buf,8,8)+2 );
+ }
+
+ while ( length>4 ) {
+ audio=ac3=false;
+ type = getBits(buf,0,8);
+ pid = getBits(buf,11,13);
+ if ( type==1/*mpeg1*/ || type==2/*mpeg2*/ || type==16/*mpeg4*/ || type==27/*h264*/ ) {
+ desc->type=1;
+ desc->vpid = pid;
+ desc->vType = type;
+ }
+ if ( type==3 || type==4 ) {
+ audio = true;
+ }
+ loop = getBits(buf,28,12);
+ buf +=5;
+ length -=(5+loop);
+ while ( loop>0 ) {
+ switch ( getBits(buf,0,8) ) {
+ case 0x09 :
+ desc->fta = 1;
+ break;
+ case 0x0A :
+ lang = langDesc( buf );
+ break;
+ case 0x56 :
+ if ( type==6 )
+ desc->ttpid = pid;
+ break;
+ case 0x59 : // DVB subtitle descriptor
+ ns = (int)desc->nsubpid;
+ if ( type==6 && ns<desc->maxsubpid ) {
+ st = getBits(buf+5,0,8);
+ if ( st>=0x10 && st<=0x23 ) {
+ desc->subpid[ns].type = st;
+ desc->subpid[ns].pid = pid;
+ desc->subpid[ns].page = getBits(buf+6,0,16);
+ desc->subpid[ns].id = getBits(buf+8,0,16);
+ desc->subpid[ns].lang = langDesc(buf);
+ fprintf( stderr, "\nDVB SUB on %s page_id: %d anc_id: %d lang: %s\n\n",
+ desc->name.latin1(), desc->subpid[ns].page, desc->subpid[ns].id,
+ desc->subpid[ns].lang.latin1() );
+ desc->nsubpid++;
+ }
+ }
+ break;
+ case 0x6a :
+ audio = true;
+ ac3 = true;
+ break;
+ default :
+ break;
+ }
+ loop -=( getBits(buf,8,8)+2 );
+ buf +=( getBits(buf,8,8)+2 );
+ }
+ if ( audio && desc->napid<desc->maxapid ) {
+ if ( !desc->vpid )
+ desc->type=2;
+ desc->apid[(int)desc->napid].pid = pid;
+ if ( ac3 )
+ desc->apid[(int)desc->napid].ac3 = 1;
+ if ( !lang.isEmpty() )
+ desc->apid[(int)desc->napid].lang = lang;
+ desc->napid++;
+ }
+ }
+
+ return true;
+}
+
+
+
+bool DVBsi::tablePAT( unsigned char *buf )
+{
+ int length, i, sid, tsid, pmt;
+ bool got;
+ ChannelDesc *desc;
+
+ tsid = getBits(buf+3,0,16);
+ length = getBits(buf,12,12);
+ length -=5;
+ buf +=8;
+
+ while ( length>4 ) {
+ sid = getBits(buf,0,16);
+ pmt = getBits(buf,19,13);
+ buf +=4;
+ length -=4;
+ got = false;
+ for ( i=indexChannels; i<(int)channels.count(); i++ ) {
+ if ( channels.at( i )->sid==sid ) {
+ channels.at( i )->pmtpid = pmt;
+ got = true;
+ break;
+ }
+ }
+ if ( !got && sid!=0 ) {
+ desc = new ChannelDesc();
+ channels.append( desc );
+ desc->tp.tsid = tsid;
+ desc->sid = sid;
+ desc->pmtpid = pmt;
+ desc->name = QString("TSID:%1-SID:%2").arg(tsid).arg(sid);
+ }
+ }
+
+ return true;
+}
+
+
+
+bool DVBsi::getSection( int pid, int tid, int timeout, int sid )
+{
+ unsigned char buf[4096];
+ int i, n=0;
+ int skip=0;
+ int last=1, current=0, loop=0;
+ QValueList<int> list, sidList;
+ int cursid;
+
+ if ( !setFilter( pid, tid, timeout ) )
+ return false;
+
+ do {
+ if ( poll(pf,1,timeout)>0 ){
+ if ( pf[0].revents & POLLIN ){
+ n = read( fdDemux, buf, 4096 );
+ skip = 0;
+ }
+ else
+ skip++;
+ }
+ else
+ skip++;
+
+ if ( skip || n<4 ) {
+ fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid);
+ stopFilter();
+ return false;
+ }
+
+ cursid = getBits(buf+3,0,16);
+ if ( sid && cursid!=sid && !sidList.contains(cursid) ) {
+ sidList.append( cursid );
+ continue;
+ }
+
+ last = getBits(buf,56,8);
+ current = getBits(buf,48,8);
+ for ( i=0; i<(int)list.count(); i++ ) {
+ if ( current==list[i] ) {
+ i = -1;
+ break;
+ }
+ }
+ if ( i>-1 )
+ list.append( current );
+ else {
+ loop++; // missing section ?
+ continue;
+ }
+ switch ( getBits(buf,0,8) ) {
+ case 0x42 :
+ fprintf(stderr,"Reading SDT: pid=%d\n", pid);
+ tableSDT( buf );
+ break;
+ case 0x00 :
+ fprintf(stderr,"Reading PAT: pid=%d\n", pid);
+ tablePAT( buf );
+ break;
+ case 0x02 :
+ fprintf(stderr,"Reading PMT: pid=%d\n", pid);
+ tablePMT( buf );
+ break;
+ default:
+ break;
+ }
+ loop = 0;
+ } while ( (int)list.count()<=last && loop<=last );
+
+ stopFilter();
+ return true;
+}
+
+
+
+void DVBsi::stop()
+{
+ if ( !isRunning )
+ return;
+
+ isRunning = false;
+ if ( !wait(10000) ) {
+ if ( ns ) {
+ ns->stop();
+ delete ns;
+ ns = 0;
+ }
+ terminate();
+ wait();
+ if ( scanMode<2 )
+ dvb->stopScan();
+ }
+}
+
+
+
+void DVBsi::out( bool stopscan )
+{
+ if ( ns ) {
+ ns->stop();
+ delete ns;
+ ns = 0;
+ }
+ if ( stopscan )
+ dvb->stopScan();
+ KApplication::kApplication()->postEvent( this, new QTimerEvent( TIMER_EVENT_SCAN_END ) );
+}
+
+
+
+void DVBsi::go( QPtrList<Transponder> trans, int mode )
+{
+ int i;
+
+ if ( isRunning )
+ return;
+
+ scanMode = mode;
+ transponders.clear();
+ for ( i=0; i<(int)trans.count(); i++ )
+ transponders.append( new Transponder( *trans.at(i) ) );
+ channels.clear();
+ isRunning = true;
+ start();
+}
+
+
+
+void DVBsi::timerEvent( QTimerEvent *e )
+{
+ switch ( e->timerId() ) {
+ case TIMER_EVENT_SCAN_END :
+ emit end( true );
+ break;
+ }
+}
+
+
+
+void DVBsi::run()
+{
+ int i, j=0, k=0;
+ ChannelDesc chan;
+ Transponder trans;
+ unsigned short tsid, nid;
+ bool nitEnded=true, ok;
+
+ progressTransponder = 0;
+
+ if ( scanMode<2 ) {
+ dvb->stopScan();
+ for ( i=0; i<(int)transponders.count(); i++ ) {
+ if ( !isRunning ) {
+ out();
+ return;
+ }
+ chan.tp = *transponders.at(i);
+ usleep( 100000 );
+ if ( !dvb->tuneDvb( &chan, false ) ) {
+ for ( k=0; k<(int)chan.tp.freqlist.count(); k++ ) {
+ chan.tp.freq = chan.tp.freqlist[k];
+ fprintf(stderr,"Trying alternate frequency\n");
+ if ( dvb->tuneDvb( &chan, false ) ) {
+ k = -1;
+ transponders.at(i)->freq = chan.tp.freq;
+ break;
+ }
+ else
+ usleep( 400000 );
+ }
+ if ( k>-1 ) {
+ fprintf(stderr,"dvbsi: Cant tune DVB\n");
+ progressTransponder++;
+ usleep( 400000 );
+ continue;
+ }
+ }
+
+ indexChannels = j;
+ fprintf(stderr,"Transponders: %d/%d\n", i+1, transponders.count() );
+ if ( scanMode ) {
+ nitEnded = false;
+ ns = new NitSection( &transponders, &nitEnded, &ok, adapter, tuner ); //NIT
+ }
+ if ( !getSection( 0x11, 0x42 ) ) //SDT
+ continue;
+ if ( !isRunning ) {
+ out();
+ return;
+ }
+ getSection( 0x00, 0x00 ); //PAT
+ for ( ; j<(int)channels.count(); j++ ) {
+ if ( channels.at( j )->pmtpid==0 ) {
+ channels.at(j)->completed = 1;
+ continue;
+ }
+ if ( !isRunning ) {
+ out();
+ return;
+ }
+ getSection( channels.at( j )->pmtpid, 0x02, 5000, channels.at( j )->sid ); //PMTs
+ tsid = channels.at(j)->tp.tsid;
+ nid = channels.at(j)->tp.nid;
+ channels.at(j)->tp = *transponders.at(i);
+ if ( channels.at(j)->tp.tsid==0 )
+ channels.at(j)->tp.tsid = tsid;
+ channels.at(j)->tp.nid = nid;
+ channels.at(j)->tp.snr = dvb->getSNR();
+ channels.at(j)->completed = 1;
+ }
+ while( !nitEnded ) {
+ if ( !ok ) {
+ ns->stop();
+ break;
+ }
+ else
+ msleep( 50 );
+ }
+ if ( scanMode ) {
+ delete ns;
+ ns = 0;
+ }
+ dvb->stopScan();
+ progressTransponder++;
+ }
+ fprintf(stderr,"Transponders: %d\n", transponders.count());
+ }
+ else if ( scanMode==2 ) {
+ indexChannels = 0;
+ trans = dvb->getCurrentTransponder();
+ getSection( 0x11, 0x42 ); //SDT
+ getSection( 0x00, 0x00 ); //PAT
+ for ( j=0; j<(int)channels.count(); j++ ) {
+ if ( channels.at( j )->pmtpid==0 ) {
+ channels.at(j)->completed = 1;
+ continue;
+ }
+ if ( !isRunning ) {
+ out(false);
+ return;
+ }
+ getSection( channels.at( j )->pmtpid, 0x02, 5000, channels.at( j )->sid ); //PMTs
+ tsid = channels.at(j)->tp.tsid;
+ nid = channels.at(j)->tp.nid;
+ channels.at(j)->tp = trans;
+ channels.at(j)->tp.tsid = tsid;
+ channels.at(j)->tp.nid = nid;
+ channels.at(j)->tp.snr = dvb->getSNR();
+ channels.at(j)->completed = 1;
+ }
+ }
+ fprintf(stderr,"dvbsi: The end :)\n");
+ isRunning = false;
+ listChannels();
+ KApplication::kApplication()->postEvent( this, new QTimerEvent( TIMER_EVENT_SCAN_END ) );
+}
+
+
+
+bool DVBsi::listChannels()
+{
+ QString s,t;
+ int i, valid=0;
+ bool ac3;
+
+ for ( i=0; i<(int)channels.count(); i++ ) {
+ ac3 = false;
+ if ( channels.at( i )->vType<16 )
+ continue;
+ /*if ( channels.at( i )->nsubpid==0 )
+ continue;
+ if ( channels.at( i )->pmtpid==0 )
+ continue;
+ if ( channels.at(i)->name.isEmpty() )
+ continue;
+ if ( channels.at( i )->type<1 )
+ continue;
+ if ( channels.at( i )->type>2 )
+ continue;
+ if ( channels.at( i )->type==1 && channels.at(i)->vpid==0 )
+ continue;
+ if ( channels.at( i )->type==1 && channels.at(i)->napid==0 )
+ continue;
+ if ( channels.at( i )->type==2 && channels.at(i)->napid==0 )
+ continue;
+ if ( channels.at( i )->type==2 && channels.at(i)->vpid!=0 )
+ continue;*/
+
+ s = "|"+channels.at(i)->name;
+ s = s+"|"+t.setNum(channels.at(i)->tp.freq);
+ s = s+"|"+channels.at(i)->tp.pol;
+ s = s+"|"+t.setNum(channels.at(i)->tp.sr);
+ fprintf(stderr, "%s\n", s.latin1() );
+ valid++;
+ }
+ fprintf(stderr, "Channels found: %d\n", valid );
+ return true;
+}
+
+#include "dvbsi.moc"
diff --git a/kaffeine/src/input/dvb/dvbsi.h b/kaffeine/src/input/dvb/dvbsi.h
new file mode 100644
index 0000000..df1f6e7
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbsi.h
@@ -0,0 +1,98 @@
+/*
+ * dvbsi.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBSI_H
+#define DVBSI_H
+
+#include "dvbsection.h"
+#include "dvbstream.h"
+
+
+
+class NitSection : public KaffeineDVBsection
+{
+
+public:
+
+ NitSection( QPtrList<Transponder> *tp, bool *end, bool *ok, int anum, int tnum );
+ ~NitSection();
+ bool getSection( int pid, int tid, int timeout=5000 );
+ bool tableNIT( unsigned char* buf );
+ void satelliteDesc( unsigned char* buf, Transponder *trans );
+ void cableDesc( unsigned char* buf, Transponder *trans );
+ void terrestrialDesc( unsigned char* buf, Transponder *trans );
+ void freqListDesc( unsigned char* buf, Transponder *trans );
+ void stop();
+
+ bool *ended;
+ QPtrList<Transponder> *transponders;
+
+protected:
+
+ virtual void run();
+};
+
+
+
+class DVBsi : public QObject, public KaffeineDVBsection
+{
+ Q_OBJECT
+
+public:
+
+ DVBsi( bool *ok, int anum, int tnum, DvbStream *d, const QString &charset );
+ ~DVBsi();
+ bool getSection( int pid, int tid, int timeout=5000, int sid=0 );
+ bool listChannels();
+ bool tableSDT( unsigned char* buf );
+ bool tablePAT( unsigned char *buf );
+ bool tablePMT( unsigned char* buf );
+ void serviceDesc( unsigned char* buf, ChannelDesc *desc );
+
+ QPtrList<ChannelDesc> channels;
+ QPtrList<Transponder> transponders;
+ DvbStream *dvb;
+ int indexChannels;
+ int progressTransponder;
+ int adapter, tuner;
+
+public slots:
+
+ void go( QPtrList<Transponder> trans, int mode=1 );
+ void stop();
+
+protected:
+
+ virtual void run();
+ virtual void timerEvent( QTimerEvent *e );
+
+private:
+
+ void out( bool stopscan=true );
+
+ int scanMode;
+ NitSection *ns;
+
+signals:
+
+ void end( bool );
+};
+
+#endif /* DVBSI_H */
diff --git a/kaffeine/src/input/dvb/dvbstream.cpp b/kaffeine/src/input/dvb/dvbstream.cpp
new file mode 100644
index 0000000..302c0d0
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbstream.cpp
@@ -0,0 +1,1390 @@
+/*
+ * dvbstream.cpp
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <resolv.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <values.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <math.h>
+
+#include <linux/dvb/dmx.h>
+
+#include <qdir.h>
+#include <qprogressdialog.h>
+
+#include <klocale.h>
+#include <kapplication.h>
+
+#include "dvbstream.h"
+#include "dvbevents.h"
+#include "gdvb.h"
+#include "dvbcam.h"
+#include "kaffeinedvbplugin.h"
+
+#define MAXTUNETRY 1
+
+
+
+DvbStream::DvbStream( Device *d, const QString &charset, EventTable *et )
+{
+ dvbDevice = d;
+ isRunning = false;
+ timeShifting = false;
+ waitPause = 0;
+ delOut = 0;
+ fdFrontend = fdDvr = 0;
+ ndmx = 0;
+ currentTransponder = Transponder();
+ frontendName = QString("/dev/dvb/adapter%1/frontend%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner );
+ dvrName = QString("/dev/dvb/adapter%1/dvr%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner );
+ demuxName = QString("/dev/dvb/adapter%1/demux%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner );
+
+ out.setAutoDelete( true );
+
+ QString deviceType="NONE";
+ switch ( dvbDevice->type ) {
+ case FE_QPSK: deviceType = "DVBS"; break;
+ case FE_OFDM: deviceType = "DVBT"; break;
+ case FE_QAM: deviceType = "DVBC"; break;
+ case FE_ATSC: deviceType = "DVBA"; break;
+ }
+ dvbEvents = new DVBevents( deviceType, dvbDevice->adapter, dvbDevice->tuner, charset, et );
+
+ camProbed = false;
+ cam = NULL;
+ plug = NULL;
+
+ connect( &statusTimer, SIGNAL(timeout()), this, SLOT(checkStatus()) );
+}
+
+
+
+void DvbStream::setPlug( KaffeineDvbPlugin *p )
+{
+ plug = p;
+}
+
+
+
+void DvbStream::probeCam()
+{
+ int ci_type=0;
+ if ( camProbed )
+ return;
+ if ( (ci_type=DvbCam::probe( dvbDevice->adapter, 0 ))>0 )
+ cam = new DvbCam( dvbDevice->adapter, 0, dvbDevice->tuner, ci_type );
+ camProbed = true;
+}
+
+
+
+QStringList DvbStream::getSources( bool all )
+{
+ if ( !all ) {
+ if ( dvbDevice->type==FE_OFDM )
+ return QStringList( "Terrestrial" );
+ if ( dvbDevice->type==FE_QAM )
+ return QStringList( "Cable" );
+ if ( dvbDevice->type==FE_ATSC )
+ return QStringList( "Atsc" );
+ }
+ QStringList source;
+ int i;
+ if ( dvbDevice->type==FE_QPSK ) {
+ for ( i=0; i<dvbDevice->numLnb; i++ )
+ source+= dvbDevice->lnb[i].source;
+ }
+ else {
+ QString s = dvbDevice->source;
+ source+= s.remove(0,2);
+ }
+ return source;
+}
+
+
+
+bool DvbStream::canSource( ChannelDesc *chan )
+{
+ if ( chan->tp.type!=dvbDevice->type ) {
+ return false;
+ }
+ if ( dvbDevice->type!=FE_QPSK ) {
+ if ( chan->tp.type==dvbDevice->type )
+ return true;
+ else
+ return false;
+ }
+ int i;
+ for ( i=0; i<dvbDevice->numLnb; i++ ) {
+ if ( dvbDevice->lnb[i].source.contains(chan->tp.source) )
+ return true;
+ }
+ return false;
+}
+
+
+
+int DvbStream::getSatPos( const QString &src )
+{
+ int i;
+
+ if ( dvbDevice->type!=FE_QPSK )
+ return -1;
+
+ for ( i=0; i<dvbDevice->numLnb; i++ )
+ if ( dvbDevice->lnb[i].source.contains(src) )
+ return i;
+ return -1;
+}
+
+
+
+bool DvbStream::openFe()
+{
+ if ( fdFrontend ) {
+ fprintf(stderr,"openFe: fdFrontend != 0\n");
+ return false;
+ }
+ fdFrontend = open( frontendName.ascii(), O_RDWR );
+ if ( fdFrontend<0 ) {
+ perror("openFe:");
+ fdFrontend = 0;
+ return false;
+ }
+ return true;
+}
+
+
+
+bool DvbStream::closeFe()
+{
+ if ( !fdFrontend )
+ return true;
+ if ( close( fdFrontend )<0 ) {
+ perror("closeFe: ");
+ return false;
+ }
+ fprintf(stderr,"Frontend closed\n");
+ fdFrontend = 0;
+ currentTransponder = Transponder();
+ return true;
+}
+
+
+
+void DvbStream::connectStatus( bool con )
+{
+ if ( con )
+ statusTimer.start( 1000 );
+ else
+ statusTimer.stop();
+}
+
+
+
+ChannelDesc DvbStream::getLiveChannel()
+{
+ int i;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->hasLive() )
+ return out.at(i)->channel;
+ }
+ return ChannelDesc();
+}
+
+
+
+bool DvbStream::hasLive()
+{
+ int i;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->hasLive() )
+ return true;
+ }
+ return false;
+}
+
+
+
+bool DvbStream::hasRec()
+{
+ int i;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->hasRec() )
+ return true;
+ }
+ return false;
+}
+
+
+
+bool DvbStream::hasBroadcast()
+{
+ int i;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->hasBroadcast() )
+ return true;
+ }
+ return false;
+}
+
+
+
+bool DvbStream::liveIsRecording()
+{
+ int i;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->hasLive() ) {
+ if ( out.at(i)->hasRec() )
+ return true;
+ else
+ return false;
+ }
+ }
+ return false;
+}
+
+
+
+Transponder DvbStream::getCurrentTransponder()
+{
+ return currentTransponder;
+}
+
+
+
+unsigned long DvbStream::getCurrentFreq()
+{
+ return currentTransponder.freq;
+}
+
+
+
+bool DvbStream::isTuned()
+{
+ if ( fdFrontend )
+ return true;
+ else
+ return false;
+}
+
+
+
+bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
+{
+ unsigned long lof=0;
+ int res, hiband=0;
+ struct dvb_frontend_parameters feparams;
+ struct dvb_frontend_info fe_info;
+ fe_status_t status;
+ unsigned long freq=chan->tp.freq;
+ unsigned long srate=chan->tp.sr;
+ int lnbPos = getSatPos( chan->tp.source );
+ int rotorMove = 0;
+ int loop=0, i;
+
+ closeFe();
+ if ( !openFe() )
+ return false;
+
+ if ( (res = ioctl( fdFrontend, FE_GET_INFO, &fe_info ) < 0) ) {
+ perror("FE_GET_INFO: ");
+ return false;
+ }
+
+ probeCam();
+
+ fprintf(stderr, "Using DVB device %d:%d \"%s\"\n", dvbDevice->adapter, dvbDevice->tuner, fe_info.name);
+
+ freq*=1000;
+ srate*=1000;
+
+ switch( fe_info.type ) {
+ case FE_OFDM : {
+ if (freq < 1000000)
+ freq*=1000UL;
+ feparams.frequency=freq;
+ feparams.u.ofdm.bandwidth=chan->tp.bandwidth;
+ feparams.u.ofdm.code_rate_HP=chan->tp.coderateH;
+ feparams.u.ofdm.code_rate_LP=chan->tp.coderateL;
+ feparams.u.ofdm.constellation=chan->tp.modulation;
+ feparams.u.ofdm.transmission_mode=chan->tp.transmission;
+ feparams.u.ofdm.guard_interval=chan->tp.guard;
+ feparams.u.ofdm.hierarchy_information=chan->tp.hierarchy;
+ fprintf(stderr,"tuning DVB-T to %lu Hz\n", freq);
+ fprintf(stderr,"inv:%d bw:%d fecH:%d fecL:%d mod:%d tm:%d gi:%d hier:%d\n", chan->tp.inversion,
+ chan->tp.bandwidth, chan->tp.coderateH, chan->tp.coderateL, chan->tp.modulation,
+ chan->tp.transmission, chan->tp.guard, chan->tp.hierarchy );
+ break;
+ }
+ case FE_QAM : {
+ fprintf(stderr,"tuning DVB-C to %lu\n", freq);
+ feparams.frequency=freq;
+ feparams.u.qam.symbol_rate = srate;
+ feparams.u.qam.fec_inner = chan->tp.coderateH;
+ feparams.u.qam.modulation = chan->tp.modulation;
+ fprintf(stderr,"inv:%d sr:%lu fecH:%d mod:%d\n", chan->tp.inversion,
+ srate, chan->tp.coderateH, chan->tp.modulation );
+ break;
+ }
+ case FE_QPSK : {
+ fprintf(stderr,"tuning DVB-S to %lu %c %lu\n", freq, chan->tp.pol, srate);
+ if (freq > 2200000) {
+ if ( dvbDevice->lnb[lnbPos].switchFreq ) { // Dual LO
+ if ( freq<(dvbDevice->lnb[lnbPos].switchFreq*1000) ) {
+ lof = dvbDevice->lnb[lnbPos].loFreq*1000;
+ }
+ else {
+ lof = dvbDevice->lnb[lnbPos].hiFreq*1000;
+ hiband = 1;
+ }
+ }
+ else {
+ if ( dvbDevice->lnb[lnbPos].hiFreq ) { // C Band Multipoint
+ if ( (chan->tp.pol=='h') || (chan->tp.pol=='H') )
+ lof = (dvbDevice->lnb[lnbPos].hiFreq*1000);
+ else
+ lof = (dvbDevice->lnb[lnbPos].loFreq*1000);
+ }
+ else // Single LO
+ lof = (dvbDevice->lnb[lnbPos].loFreq*1000);
+ }
+ if ( freq<lof )
+ feparams.frequency = ( lof-freq );
+ else
+ feparams.frequency = ( freq-lof );
+ }
+ else
+ feparams.frequency=freq;
+
+ feparams.u.qpsk.symbol_rate=srate;
+ feparams.u.qpsk.fec_inner=chan->tp.coderateH;
+ fprintf(stderr,"inv:%d fecH:%d\n", chan->tp.inversion, chan->tp.coderateH );
+ if ( setDiseqc( lnbPos, chan, hiband, rotorMove, dvr )!=0 ) {
+ closeFe();
+ return false;
+ }
+ break;
+ }
+ case FE_ATSC : {
+ fprintf(stderr,"tuning ATSC to %lu\n", freq);
+ feparams.frequency=freq;
+ feparams.u.vsb.modulation = chan->tp.modulation;
+ fprintf(stderr,"inv:%d mod:%d\n", chan->tp.inversion, chan->tp.modulation );
+ break;
+ }
+ }
+ if ( chan->tp.inversion==INVERSION_AUTO ) {
+ if ( fe_info.caps & FE_CAN_INVERSION_AUTO )
+ feparams.inversion=chan->tp.inversion;
+ else {
+ fprintf(stderr,"Can NOT inversion_auto\n");
+ feparams.inversion=INVERSION_OFF;
+ }
+ }
+ else
+ feparams.inversion=chan->tp.inversion;
+
+ if ( rotorMove )
+ loop = 2;
+
+ while ( loop>-1 ) {
+ if (ioctl(fdFrontend,FE_SET_FRONTEND,&feparams) < 0) {
+ perror("ERROR tuning \n");
+ closeFe();
+ return false;
+ }
+ for ( i=0; i<(dvbDevice->tuningTimeout/100); i++ ) {
+ usleep( 100000 );
+ fprintf( stderr, "." );
+ if ( ioctl( fdFrontend, FE_READ_STATUS, &status )==-1 ) {
+ perror( "FE_READ_STATUS" );
+ break;
+ }
+ if ( status & FE_HAS_LOCK ) {
+ fprintf(stderr," LOCKED.");
+ loop = 0;
+ break;
+ }
+ }
+ fprintf(stderr,"\n");
+ --loop;
+ }
+
+ if ( !( status & FE_HAS_LOCK ) ) {
+ fprintf( stderr, "\nNot able to lock to the signal on the given frequency\n" );
+ closeFe();
+ return false;
+ }
+
+ if ( rotorMove )
+ dvbDevice->lnb[lnbPos].currentSource = chan->tp.source;
+
+ if ( !dvr )
+ return true;
+
+ if ( ( fdDvr = open( dvrName.ascii(), O_RDONLY|O_NONBLOCK)) < 0 ) {
+ perror("DVR DEVICE: ");
+ closeFe();
+ fdDvr = 0;
+ return false;
+ }
+ pfd.fd=fdDvr;
+ pfd.events=POLLIN|POLLPRI;
+
+ currentTransponder = chan->tp;
+ return true;
+}
+
+
+
+int DvbStream::setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rotor, bool dvr )
+{
+ struct dvb_diseqc_master_cmd switchCmd[] = {
+ { { 0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf2, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf1, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf3, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf4, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf6, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf5, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf7, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf8, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xfa, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xf9, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xfb, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xfc, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xfe, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xfd, 0x00, 0x00 }, 4 },
+ { { 0xe0, 0x10, 0x38, 0xff, 0x00, 0x00 }, 4 },
+ };
+
+ int i;
+ int voltage18 = ( (chan->tp.pol=='H')||(chan->tp.pol=='h') );
+ int ci = 4 * switchPos + 2 * hiband + (voltage18 ? 1 : 0);
+
+ fprintf( stderr, "DiSEqC: switch pos %i, %sV, %sband (index %d)\n", switchPos, voltage18 ? "18" : "13", hiband ? "hi" : "lo", ci );
+ if ( ci < 0 || ci >= (int)(sizeof(switchCmd)/sizeof(struct dvb_diseqc_master_cmd)) )
+ return -EINVAL;
+
+ if ( ioctl(fdFrontend, FE_SET_TONE, SEC_TONE_OFF) )
+ perror("FE_SET_TONE failed");
+ usleep(15*1000);
+ if ( ioctl(fdFrontend, FE_SET_VOLTAGE, ci%2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13) )
+ perror("FE_SET_VOLTAGE failed");
+
+ fprintf( stderr, "DiSEqC: %02x %02x %02x %02x %02x %02x\n", switchCmd[ci].msg[0], switchCmd[ci].msg[1], switchCmd[ci].msg[2], switchCmd[ci].msg[3], switchCmd[ci].msg[4], switchCmd[ci].msg[5] );
+ for ( i=0; i<2; ++i ) {
+ usleep(15*1000);
+ if ( ioctl(fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &switchCmd[ci]) )
+ perror("FE_DISEQC_SEND_MASTER_CMD failed");
+ }
+
+ QString msg;
+ if ( dvbDevice->lnb[switchPos].rotorType!=0 && chan->tp.source!=dvbDevice->lnb[switchPos].currentSource ) {
+ int i, index=-1;
+ double angle=0.0, oldAngle=0.0;
+ fprintf( stderr, "Driving rotor to %s\n", chan->tp.source.ascii() );
+ for ( i=0; i<(int)dvbDevice->lnb[switchPos].source.count(); i++ ) {
+ if ( dvbDevice->lnb[switchPos].source[i]==chan->tp.source ) {
+ index = i;
+ break;
+ }
+ }
+ angle = getSourceAngle( chan->tp.source );
+ if ( dvbDevice->lnb[switchPos].rotorType==1 ) {
+ fprintf( stderr, "Rotor: gotoX=%f\n", angle );
+ gotoX( angle );
+ }
+ else {
+ int pos = dvbDevice->lnb[switchPos].position[index];
+ fprintf( stderr, "Rotor: gotoN=%d\n", pos );
+ rotorCommand( 9, pos );
+ }
+ if ( dvbDevice->lnb[switchPos].currentSource.isEmpty() ) {
+ rotor = 10;
+ msg = i18n("Moving rotor from unknown position...");
+ }
+ else {
+ oldAngle = getSourceAngle( dvbDevice->lnb[switchPos].currentSource );
+ fprintf( stderr, "old rotor pos: %f °\n", oldAngle );
+ fprintf( stderr, "new rotor pos: %f °\n", angle );
+ angle = fabs(angle-oldAngle);
+ fprintf( stderr, "Rotation angle: %f °\n", angle );
+ if ( voltage18 )
+ rotor = (int)(angle*dvbDevice->lnb[switchPos].speed18v)+1;
+ else
+ rotor = (int)(angle*dvbDevice->lnb[switchPos].speed13v)+1;
+ msg = i18n("Moving rotor...");
+ }
+ fprintf( stderr, "Rotation time: %d sec.\n", rotor );
+ }
+
+ if ( rotor ) {
+ int j;
+ if ( !dvr ) {
+ for ( j=0; j<(rotor*2); j++ ) {
+ usleep( 500000 );
+ }
+ }
+ else {
+ QProgressDialog progress( msg, i18n("Cancel"), rotor*2, 0, "progress", true );
+ for ( j=0; j<(rotor*2); j++ ) {
+ progress.setProgress( j );
+ qApp->processEvents();
+ if ( progress.wasCanceled() )
+ break;
+ usleep( 500000 );
+ }
+ progress.setProgress( rotor*2 );
+ qApp->processEvents();
+ }
+ }
+
+ for ( i=0; i<2; ++i ) {
+ usleep(15*1000);
+ if ( ioctl(fdFrontend, FE_DISEQC_SEND_BURST, (ci/4)%2 ? SEC_MINI_B : SEC_MINI_A) )
+ perror("FE_DISEQC_SEND_BURST failed");
+ }
+
+ usleep(15*1000);
+ if ( ioctl(fdFrontend, FE_SET_TONE, (ci/2)%2 ? SEC_TONE_ON : SEC_TONE_OFF) )
+ perror("FE_SET_TONE failed");
+
+ return 0;
+}
+
+
+
+double DvbStream::getSourceAngle( QString source )
+{
+ double angle=1.0;
+ int pos = source.findRev("-");
+ source.remove(0,pos+1);
+ source = source.upper();
+ if ( source.endsWith("W") )
+ angle = -1.0;
+ source.truncate( source.length()-1 );
+ angle*= source.toDouble();
+ return getAzimuth( angle );
+}
+
+
+
+#define TO_RADS (M_PI / 180.0)
+#define TO_DEC (180.0 / M_PI)
+
+double DvbStream::getAzimuth( double angle )
+{
+ double latitude = dvbDevice->usalsLatitude;
+ double longitude = dvbDevice->usalsLongitude;
+ double P, Ue, Us, az, x, el, Azimuth;
+
+ P = latitude*TO_RADS; // Earth Station Latitude
+ Ue = longitude*TO_RADS; // Earth Station Longitude
+ Us = angle*TO_RADS; // Satellite Longitude
+
+ az = M_PI+atan( tan( Us-Ue )/sin( P ) );
+ x = acos( cos(Us-Ue)*cos(P) );
+ el = atan( ( cos( x )-0.1513 )/sin( x ) );
+ Azimuth = atan( ( -cos(el)*sin(az) )/( sin(el)*cos(P)-cos(el)*sin(P)*cos(az)) )* TO_DEC;
+
+ return Azimuth;
+}
+
+
+
+void DvbStream::gotoX( double azimuth )
+{
+ double USALS=0.0;
+ int CMD1=0x00, CMD2=0x00;
+ int DecimalLookup[10] = { 0x00, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0A, 0x0B, 0x0D, 0x0E };
+
+ if ( azimuth>0.0 )
+ CMD1 = 0xE0; // East
+ else
+ CMD1 = 0xD0; // West
+
+ USALS = fabs( azimuth );
+
+ while (USALS > 16) {
+ CMD1++;
+ USALS-= 16;
+ }
+ while (USALS >= 1.0) {
+ CMD2+=0x10;
+ USALS--;
+ }
+ USALS*= 10.0;
+ int rd = (int)USALS;
+ USALS-= rd;
+ if ( USALS>0.5 )
+ ++rd;
+ CMD2+= DecimalLookup[rd];
+
+ rotorCommand( 12, CMD1, CMD2 );
+}
+
+
+
+void DvbStream::rotorCommand( int cmd, int n1, int n2, int n3 )
+{
+ struct dvb_diseqc_master_cmd cmds[] = {
+ { { 0xe0, 0x31, 0x60, 0x00, 0x00, 0x00 }, 3 }, //0 Stop Positioner movement
+ { { 0xe0, 0x31, 0x63, 0x00, 0x00, 0x00 }, 3 }, //1 Disable Limits
+ { { 0xe0, 0x31, 0x66, 0x00, 0x00, 0x00 }, 3 }, //2 Set East Limit
+ { { 0xe0, 0x31, 0x67, 0x00, 0x00, 0x00 }, 3 }, //3 Set West Limit
+ { { 0xe0, 0x31, 0x68, 0x00, 0x00, 0x00 }, 4 }, //4 Drive Motor East continously
+ { { 0xe0, 0x31, 0x68,256-n1,0x00, 0x00 }, 4 }, //5 Drive Motor East nn steps
+ { { 0xe0, 0x31, 0x69,256-n1,0x00, 0x00 }, 4 }, //6 Drive Motor West nn steps
+ { { 0xe0, 0x31, 0x69, 0x00, 0x00, 0x00 }, 4 }, //7 Drive Motor West continously
+ { { 0xe0, 0x31, 0x6a, n1, 0x00, 0x00 }, 4 }, //8 Store nn
+ { { 0xe0, 0x31, 0x6b, n1, 0x00, 0x00 }, 4 }, //9 Goto nn
+ { { 0xe0, 0x31, 0x6f, n1, n2, n3 }, 4}, //10 Recalculate Position
+ { { 0xe0, 0x31, 0x6a, 0x00, 0x00, 0x00 }, 4 }, //11 Enable Limits
+ { { 0xe0, 0x31, 0x6e, n1, n2, 0x00 }, 5 }, //12 Gotoxx
+ { { 0xe0, 0x10, 0x38, 0xF4, 0x00, 0x00 }, 4 } //13 User
+ };
+
+ int i;
+ for ( i=0; i<2; ++i ) {
+ usleep(15*1000);
+ if ( ioctl( fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &cmds[cmd] ) )
+ perror("Rotor : FE_DISEQC_SEND_MASTER_CMD failed");
+ }
+}
+
+
+
+bool DvbStream::setPids( DVBout *o )
+{
+ int i, dmx;
+ struct dmx_pes_filter_params pesFilterParams;
+ dmx_pes_type_t pestype = DMX_PES_OTHER;
+ QValueList<int> pidList;
+
+ pidList = o->pidsList();
+
+ for ( i=0; i<(int)pidList.count(); i++ ) {
+ if ( ( dmx = open( demuxName.ascii(), O_RDWR)) < 0 ) {
+ fprintf(stderr,"FD %i: ",i);
+ perror("DEMUX DEVICE: ");
+ return false;
+ }
+ else
+ o->dmx.append(dmx);
+ }
+
+ for ( i=0; i<(int)pidList.count(); i++ ) {
+ pesFilterParams.pid = pidList[i];
+ pesFilterParams.input = DMX_IN_FRONTEND;
+ pesFilterParams.output = DMX_OUT_TS_TAP;
+ pesFilterParams.pes_type = pestype;
+ pesFilterParams.flags = DMX_IMMEDIATE_START;
+ if ( ioctl( o->dmx[i], DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+ fprintf( stderr, "FILTER %i: ", pidList[i] );
+ perror("DMX SET PES FILTER");
+ }
+ }
+
+ ndmx +=pidList.count();
+
+ return true;
+}
+
+
+
+void DvbStream::removePids( DVBout *o )
+{
+ int i;
+
+ for ( i=0; i<(int)o->dmx.count(); i++ )
+ close( o->dmx[i] );
+ ndmx -=o->dmx.count();
+}
+
+
+
+void DvbStream::removeOut( DVBout *o )
+{
+ disconnect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) );
+ disconnect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) );
+ disconnect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) );
+ delOut = o;
+ while ( delOut )
+ usleep(100);
+}
+
+
+
+bool DvbStream::checkStatus()
+{
+ int32_t strength;
+ fe_status_t festatus;
+ bool ret=true;
+
+ strength=0;
+ ioctl(fdFrontend,FE_READ_SIGNAL_STRENGTH,&strength);
+ emit signalStatus(strength*100/65535);
+
+ strength=0;
+ ioctl(fdFrontend,FE_READ_SNR,&strength);
+ emit snrStatus(strength*100/65535);
+
+ memset( &festatus, 0, sizeof(festatus) );
+ ioctl(fdFrontend,FE_READ_STATUS,&festatus);
+
+ if (festatus & FE_HAS_LOCK)
+ emit lockStatus( true );
+ else {
+ emit lockStatus( false );
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+
+int DvbStream::getSNR()
+{
+ int32_t snr=0;
+ if ( fdFrontend ) {
+ ioctl( fdFrontend, FE_READ_SNR, &snr );
+ snr = snr*100/65535;
+ }
+ return snr;
+}
+
+
+
+bool DvbStream::hasVideo()
+{
+ if ( getLiveChannel().vpid )
+ return true;
+ return false;
+}
+
+
+
+void DvbStream::run()
+{
+ unsigned char buf[188];
+ int n, i, thWrite=0;
+ int WSIZE=188*8;
+ DVBout *o=0;
+
+ signal( SIGPIPE, SIG_IGN );
+
+ while ( isRunning ) {
+ if ( poll( &pfd, 1, 100 ) ) {
+ n = read( fdDvr, buf, 188 );
+ if ( n==188 ) {
+ memcpy( thBuf+thWrite, buf, n );
+ thWrite+=n;
+ if ( thWrite==WSIZE ) {
+ for ( i=0; i<(int)out.count(); i++ )
+ out.at(i)->process( thBuf, WSIZE );
+ thWrite = 0;
+ }
+ }
+ }
+ else
+ usleep(1000);
+
+ if ( waitPause>0 ) {
+ o = 0;
+ for ( i=0; i<(int)out.count(); i++ )
+ if ( out.at(i)->hasLive() )
+ o = out.at(i);
+ if ( o ) {
+ if ( o->doPause( timeShiftFileName ) )
+ waitPause = 0;
+ else
+ waitPause = -1;
+ }
+ else
+ waitPause = -1;
+ }
+
+ if ( delOut ) {
+ out.remove( delOut );
+ delOut = 0;
+ }
+ }
+
+ fprintf(stderr,"dvbstream::run() end\n");
+}
+
+
+
+bool DvbStream::doPause( const QString &name )
+{
+ //if ( !hasVideo() ) return false;
+
+ if ( !timeShifting ) {
+ timeShiftFileName = name;
+ waitPause = 1;
+ while ( waitPause>0 )
+ usleep(100);
+ if ( waitPause<0 )
+ return false;
+ else
+ receiveShifting( true );
+ return true;
+ }
+ return false;
+}
+
+
+
+bool DvbStream::timeShiftMode()
+{
+ return timeShifting;
+}
+
+
+
+void DvbStream::receiveShifting( bool b )
+{
+ timeShifting = b;
+ emit shifting( b );
+}
+
+
+
+bool DvbStream::running() const
+{
+ return isRunning;
+}
+
+
+
+void DvbStream::receivePlayDvb()
+{
+ KApplication::kApplication()->postEvent( this, new QTimerEvent( 500 ) );
+}
+
+
+
+void DvbStream::timerEvent( QTimerEvent* ev )
+{
+ switch ( ev->timerId() ) {
+ case 500:
+ emit playDvb();
+ }
+}
+
+
+
+void DvbStream::recordEnded( DVBout *o, RecTimer* t, bool kill )
+{
+ int i;
+
+ if ( kill ) {
+ removePids( o );
+ removeOut( o );
+ if ( out.count()==0 )
+ stop();
+ else if ( cam ) {
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->channel.fta ) {
+ i=-1;
+ break;
+ }
+ }
+ if ( i!=-1 )
+ cam->stop();
+ }
+ }
+ recordingState();
+ if ( t )
+ emit timerEnded( t );
+}
+
+
+
+void DvbStream::recordingState()
+{
+ int i;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->hasRec() ) {
+ emit isRecording( true );
+ return;
+ }
+ }
+ emit isRecording( false );
+}
+
+
+
+void DvbStream::updateTimer( RecTimer *t, int ms )
+{
+ int i;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->recTimer==t ) {
+ if ( ms )
+ out.at(i)->changeTimer( ms );
+ else
+ out.at(i)->stopRec();
+ return;
+ }
+ }
+ if ( !ms )
+ emit timerEnded( t ); // not running
+}
+
+
+
+void DvbStream::stopBroadcast()
+{
+ int i;
+ DVBout *o=0;
+ QPtrList<DVBout> p;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ o = out.at(i);
+ o->stopBroadcast();
+ if ( !o->hasLive() && !o->hasRec() )
+ p.append( o );
+ }
+ for ( i=0; i<(int)p.count(); i++ ) {
+ removePids( p.at(i) );
+ removeOut( p.at(i) );
+ }
+ if ( out.count()==0 )
+ stop();
+ emit isBroadcasting( false );
+}
+
+
+
+int DvbStream::canStartBroadcast( bool &live, ChannelDesc *chan )
+{
+ int i, ret=0;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasRec() )
+ return ErrIsRecording;
+ if ( cam && out.at(i)->hasRec() && out.at(i)->channel.fta && chan->fta && out.at(i)->channel.sid!=chan->sid )
+ return ErrCamUsed;
+ if ( out.at(i)->hasLive() && chan->tp!=out.at(i)->channel.tp )
+ live = true;
+ }
+ return ret;
+}
+
+
+
+bool DvbStream::startBroadcast( QPtrList<ChannelDesc> *list, Ts2Rtp *rtp )
+{
+ int i, j;
+ bool stop=false, newout;
+ DVBout *o=0;
+ int no=0;
+ ChannelDesc *chan=list->at(0);
+ QPtrList<ChannelDesc> broadcastList;
+ broadcastList.setAutoDelete( true );
+
+ if ( !isTuned() ) {
+ for ( i=0; i<MAXTUNETRY; i++ ) {
+ if ( tuneDvb( chan ) ) {
+ i = -1;
+ break;
+ }
+ else
+ usleep(100000);
+ }
+ if ( i<0 )
+ stop = true;
+ else
+ return false;
+ }
+
+ for ( i=0; i<(int)list->count(); i++ ) {
+ newout = false;
+ o = 0;
+ for ( j=0; j<(int)out.count(); j++ ) {
+ if ( out.at(j)->channel.name==list->at(i)->name )
+ o = out.at(j);
+ }
+
+ if ( !o ) {
+ o = new DVBout( *list->at(i), dvbDevice->adapter, dvbDevice->tuner, plug );
+ connect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) );
+ connect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) );
+ connect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) );
+ out.append( o );
+ if ( !setPids( o ) ) {
+ removePids( o );
+ removeOut( o );
+ o = 0;
+ }
+ else
+ newout = true;
+ }
+
+ if ( o ) {
+ if ( !o->goBroadcast( rtp ) ) {
+ if ( newout ) {
+ removePids( o );
+ removeOut( o );
+ }
+ }
+ else {
+ broadcastList.append( new ChannelDesc( *list->at(i) ) );
+ no++;
+ }
+ }
+ }
+
+ if ( !no && stop )
+ stopFrontend();
+ else
+ rtp->addChannels( &broadcastList );
+
+ fprintf(stderr,"NOUT: %d\n", out.count() );
+
+ if ( !no )
+ return false;
+ else
+ startReading();
+ emit isBroadcasting( true );
+ return true;
+}
+
+
+
+int DvbStream::canStartTimer( bool &live, ChannelDesc *chan )
+{
+ int i, ret=0;
+ DVBout *o;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ o = out.at(i);
+ if ( (chan->tp!=o->channel.tp) && o->hasRec() )
+ return ErrIsRecording;
+ if ( (o->channel.name==chan->name) && o->hasRec() )
+ return ErrIsRecording;
+ if ( (chan->tp==o->channel.tp) && o->hasRec() ) {
+ if ( chan->fta && cam && o->channel.fta )
+ return ErrCamUsed;
+ }
+ if ( o->hasLive() ) {
+ if ( chan->tp!=o->channel.tp )
+ live = true;
+ else if ( cam && chan->fta && o->channel.fta )
+ live = true;
+ }
+ }
+ return ret;
+}
+
+
+
+bool DvbStream::startTimer( ChannelDesc *chan, QString path, int maxsize, RecTimer *t, QString name )
+{
+ int i;
+ bool stop=false, newout=false;
+ DVBout *o=0;
+ QPtrList<DVBout> p;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->channel.name==chan->name )
+ o = out.at(i);
+ else {
+ if ( out.at(i)->hasBroadcast() && out.at(i)->channel.tp!=chan->tp ) {
+ p.append( out.at(i) );
+ }
+ }
+ }
+
+ for ( i=0; i<(int)p.count(); i++ ) {
+ p.at(i)->stopBroadcast();
+ removePids( p.at(i) );
+ removeOut( p.at(i) );
+ }
+
+ if ( p.count() ) {
+ emit isBroadcasting( false );
+ this->stop();
+ }
+
+ if ( !isTuned() ) {
+ for ( i=0; i<MAXTUNETRY; i++ ) {
+ if ( tuneDvb( chan ) ) {
+ i = -1;
+ break;
+ }
+ else
+ usleep(100000);
+ }
+ if ( i<0 )
+ stop = true;
+ else
+ return false;
+ }
+
+ if ( !o ) {
+ o = new DVBout( *chan, dvbDevice->adapter, dvbDevice->tuner, plug );
+ connect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) );
+ connect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) );
+ connect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) );
+ out.append( o );
+ if ( !setPids( o ) ) {
+ if ( stop )
+ stopFrontend();
+ removePids( o );
+ removeOut( o );
+ return false;
+ }
+ newout = true;
+ }
+
+ if ( t->mode && !name.contains("%date") )
+ name+= "-%date";
+ name = name.replace( "%chan", chan->name ).replace("%date", t->begin.toString( "yyyyMMdd-hhmmss" ) ).replace("%name", t->name );
+ name = name.replace( "/", "_" ).replace( ">", "_" ).replace("<","_").replace(":","_").replace('"',"_").replace("\\","_").replace("|","_");
+ name = path+name;
+
+ if ( !o->goRec( name, maxsize, t ) ) {
+ if ( stop )
+ stopFrontend();
+ if ( newout ) {
+ removePids( o );
+ removeOut( o );
+ }
+ return false;
+ }
+
+ fprintf(stderr,"NOUT: %d\n", out.count() );
+ if ( chan->fta && cam && ( ((cam->running() && chan->sid!=cam->serviceId()) || !cam->running()) ) )
+ cam->restart( chan->sid );
+
+ startReading();
+
+ recordingState();
+ return true;
+}
+
+
+
+int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName )
+{
+ int i;
+ bool stop=false;
+ DVBout *o=0;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasRec() )
+ return ErrIsRecording;
+ if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasBroadcast() )
+ return ErrIsBroadcasting;
+ if ( (chan->tp==out.at(i)->channel.tp) && (out.at(i)->hasBroadcast() || out.at(i)->hasRec())) {
+ if ( chan->fta && cam && cam->running() && (cam->serviceId()!=chan->sid) )
+ return ErrCamUsed;
+ }
+ if ( out.at(i)->channel.name==chan->name )
+ o = out.at(i);
+ }
+
+ if ( !isTuned() ) {
+ for ( i=0; i<MAXTUNETRY; i++ ) {
+ if ( tuneDvb( chan ) ) {
+ i = -1;
+ break;
+ }
+ else
+ usleep(100000);
+ }
+ if ( i<0 )
+ stop = true;
+ else
+ return ErrCantTune;
+ }
+
+ if ( !o ) {
+ o = new DVBout( *chan, dvbDevice->adapter, dvbDevice->tuner, plug );
+ connect( o, SIGNAL(endRecord(DVBout*,RecTimer*,bool)), this, SLOT(recordEnded(DVBout*,RecTimer*,bool)) );
+ connect( o, SIGNAL(playDvb()), this, SLOT(receivePlayDvb()) );
+ connect( o, SIGNAL(shifting(bool)), this, SLOT(receiveShifting(bool)) );
+ out.append( o );
+ if ( !setPids( o ) ) {
+ if ( stop )
+ stopFrontend();
+ removePids( o );
+ removeOut( o );
+ return ErrCantSetPids;
+ }
+ }
+
+ if ( o->hasRec() )
+ i = ErrDontSwitchAudio;
+ else
+ i = 0;
+
+ o->goLive( pipeName );
+ fprintf(stderr,"NOUT: %d\n", out.count() );
+
+ if ( chan->fta && cam && !cam->running() )
+ cam->restart( chan->sid );
+ startReading();
+
+ return i;
+}
+
+
+
+void DvbStream::preStopLive()
+{
+ int i;
+ DVBout *o;
+
+ for ( i=0; i<(int)out.count(); i++ ) {
+ o = out.at(i);
+ if ( o->hasLive() ) {
+ o->preStopLive();
+ break;
+ }
+ }
+}
+
+
+
+void DvbStream::stopLive( ChannelDesc *chan )
+{
+ int i;
+ DVBout *o;
+ QPtrList<DVBout> p;
+ bool camUsed = false;
+
+ fprintf(stderr,"Asked to stop\n");
+ for ( i=0; i<(int)out.count(); i++ ) {
+ o = out.at(i);
+ if ( o->hasLive() ) {
+ o->stopLive();
+ if ( !o->hasRec() && !o->hasBroadcast() ) {
+ p.append( o );
+ }
+ break;
+ }
+ }
+ for ( i=0; i<(int)p.count(); i++ ) {
+ removePids( p.at(i) );
+ removeOut( p.at(i) );
+ }
+ fprintf(stderr,"Live stopped\n");
+ if ( cam ) {
+ for ( i=0; i<(int)out.count(); i++ ) {
+ if ( out.at(i)->channel.fta )
+ camUsed = true;
+ }
+ }
+ if ( cam && !camUsed )
+ cam->stop();
+ if ( out.count()==0 && chan->tp!=currentTransponder )
+ stop();
+}
+
+
+
+void DvbStream::startReading()
+{
+ if ( !isRunning ) {
+ isRunning = true;
+ start();
+ dvbEvents->go( currentTransponder.source, currentTransponder.freq, true );
+ }
+}
+
+
+
+void DvbStream::stop()
+{
+ isRunning = false;
+ if ( !wait(10000) ) {
+ terminate();
+ wait();
+ fprintf(stderr,"dvbstream::run() terminated\n");
+ }
+ if ( cam )
+ cam->stop();
+ dvbEvents->stop();
+ stopFrontend();
+}
+
+
+
+void DvbStream::stopFrontend()
+{
+ if ( fdDvr ) {
+ close( fdDvr );
+ fprintf(stderr,"fdDvr closed\n");
+ fdDvr = 0;
+ }
+ closeFe();
+}
+
+
+
+void DvbStream::setScanning( bool b )
+{
+ connectStatus( b );
+}
+
+
+
+void DvbStream::stopScan()
+{
+ closeFe();
+}
+
+
+
+DvbStream::~DvbStream()
+{
+ stop();
+ if ( cam ) {
+ cam->stop();
+ delete cam;
+ }
+ delete dvbEvents;
+}
+
+#include "dvbstream.moc"
diff --git a/kaffeine/src/input/dvb/dvbstream.h b/kaffeine/src/input/dvb/dvbstream.h
new file mode 100644
index 0000000..a5deb52
--- /dev/null
+++ b/kaffeine/src/input/dvb/dvbstream.h
@@ -0,0 +1,163 @@
+/*
+ * dvbstream.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef DVBSTREAM_H
+#define DVBSTREAM_H
+
+#include <sys/poll.h>
+#include <sys/stat.h>
+
+#include <qthread.h>
+#include <qptrlist.h>
+#include <qfile.h>
+#include <qobject.h>
+#include <qtimer.h>
+#include <qstringlist.h>
+
+#include "channeldesc.h"
+#include "dvbout.h"
+#include "ts2rtp.h"
+#include "dvbconfig.h"
+
+#define MAX_CHANNELS 8
+
+class DVBevents;
+class DvbCam;
+class KaffeineDvbPlugin;
+class EventTable;
+
+
+
+class DvbStream : public QObject, public QThread
+{
+ Q_OBJECT
+
+public :
+
+ enum { ErrDontSwitchAudio=-1, ErrCantTune=1, ErrCantSetPids=2, ErrIsRecording=3, ErrNoLive=4,
+ ErrCantOpenFile=5, ErrIsBroadcasting=6, ErrCamUsed=7 };
+
+ DvbStream( Device *d, const QString &charset, EventTable *et );
+ ~DvbStream();
+ int getAdapter() { return dvbDevice->adapter; }
+ int getTuner() { return dvbDevice->tuner; }
+ fe_type_t getType() {return dvbDevice->type; }
+ void setPlug( KaffeineDvbPlugin *p );
+ QStringList getSources( bool all=false );
+ bool canSource( ChannelDesc *chan );
+ bool tuneDvb( ChannelDesc *chan, bool dvr=true );
+ void stopFrontend();
+ virtual void run();
+ int goLive( ChannelDesc *chan, const QString &pipeName );
+ void preStopLive();
+ void stopLive( ChannelDesc *chan );
+ void stop();
+ void stopScan();
+ void setScanning( bool b );
+ bool hasVideo();
+ bool doPause( const QString &name );
+ bool timeShiftMode();
+ bool running() const;
+ ChannelDesc getLiveChannel();
+ Transponder getCurrentTransponder();
+ unsigned long getCurrentFreq();
+ bool isTuned();
+ bool startTimer( ChannelDesc *chan, QString path, int maxsize, RecTimer *t, QString filename );
+ int canStartTimer( bool &live, ChannelDesc *chan );
+ int canStartBroadcast( bool &live, ChannelDesc *chan );
+ bool startBroadcast( QPtrList<ChannelDesc> *list, Ts2Rtp *rtp );
+ void stopBroadcast();
+ bool hasRec();
+ bool hasBroadcast();
+ bool hasLive();
+ bool liveIsRecording();
+ int getSNR();
+
+ unsigned char thBuf[188*10];
+ struct pollfd pfd;
+ DVBevents *dvbEvents;
+
+public slots:
+
+ bool checkStatus();
+ void receivePlayDvb();
+ void recordEnded( DVBout *o, RecTimer *t, bool kill );
+ void receiveShifting( bool b );
+ void updateTimer( RecTimer *t, int ms );
+
+protected:
+
+ void timerEvent( QTimerEvent* ev );
+
+private :
+
+ int setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rotor, bool dvr );
+ void rotorCommand( int cmd, int n1=0, int n2=0, int n3=0 );
+ void gotoX( double azimuth );
+ double getAzimuth( double angle );
+ double getSourceAngle( QString source );
+ int getSatPos( const QString &src );
+ bool setPids( DVBout *o );
+ void removePids( DVBout *o );
+ void removeOut( DVBout *o );
+ void recordingState();
+ void startReading();
+ void probeCam();
+ bool openFe();
+ bool closeFe();
+ void connectStatus( bool con );
+
+ QFile liveFile;
+ bool timeShifting;
+ QPtrList<DVBout> out;
+ Device *dvbDevice;
+ int waitPause;
+ DVBout *delOut;
+ Transponder currentTransponder;
+
+ QString frontendName;
+ QString dvrName;
+ QString demuxName;
+ int fdFrontend;
+ int ndmx;
+ int fdDvr, fdPipe;
+ bool isRunning;
+ QTimer statusTimer;
+ QString timeShiftFileName;
+ DvbCam *cam;
+ bool camProbed;
+ KaffeineDvbPlugin *plug;
+
+signals:
+
+ void playDvb();
+ void isRecording(bool);
+ void isBroadcasting(bool);
+ void timerEnded(RecTimer*);
+
+ void errorMsg( QString );
+ void snrStatus( int );
+ void signalStatus( int );
+ void lockStatus( bool );
+ void shifting( bool );
+
+};
+
+#endif /* DVBSTREAM_H */
diff --git a/kaffeine/src/input/dvb/gdvb.h b/kaffeine/src/input/dvb/gdvb.h
new file mode 100644
index 0000000..7f1951c
--- /dev/null
+++ b/kaffeine/src/input/dvb/gdvb.h
@@ -0,0 +1,30 @@
+/*
+ * gdvb.h
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef GDVB_H
+#define GDVB_H
+
+#define TS_SIZE 188
+#define MAX_AUDIO 6
+#define MAX_DVBSUB 3
+
+enum { OutLive=2, OutRec=4, OutRtp=8, OutTS=16 };
+
+#endif /* GDVB_H */
diff --git a/kaffeine/src/input/dvb/kaffeinedvb.rc b/kaffeine/src/input/dvb/kaffeinedvb.rc
new file mode 100644
index 0000000..0104b78
--- /dev/null
+++ b/kaffeine/src/input/dvb/kaffeinedvb.rc
@@ -0,0 +1,24 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kaffeinedvb" version="5">
+<MenuBar>
+ <Menu name="dvb"><text>&amp;DVB</text>
+ <Action name="dvb_show_osd"/>
+ <Action name="dvb_browse_next" />
+ <Action name="dvb_browse_prev" />
+ <Action name="dvb_browse_zap" />
+ <Action name="dvb_browse_advance" />
+ <Action name="dvb_browse_retreat" />
+ <Separator/>
+ <Action name="dvb_instant_record"/>
+ <Separator/>
+ <Action name="dvb_recall"/>
+ <Separator/>
+ <Action name="dvb_show_epg"/>
+ <Action name="dvb_show_timers"/>
+ <Action name="dvb_show_broadcast"/>
+ <Separator/>
+ <Action name="dvb_channels"/>
+ <Action name="dvb_config"/>
+ </Menu>
+</MenuBar>
+</kpartgui>
diff --git a/kaffeine/src/input/dvb/kevents.cpp b/kaffeine/src/input/dvb/kevents.cpp
new file mode 100644
index 0000000..c24d1c4
--- /dev/null
+++ b/kaffeine/src/input/dvb/kevents.cpp
@@ -0,0 +1,478 @@
+/*
+ * kevents.cpp
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qlayout.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qwhatsthis.h>
+#include <qcheckbox.h>
+#include <qtooltip.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+
+#include "kevents.h"
+#include "channeldesc.h"
+#include "dvbevents.h"
+#include "dvbstream.h"
+
+
+
+EListViewItem::EListViewItem( QListView *parent, QString chanName, QString eBegin, QString eDuration, QString eTitle, EventDesc *desc ) : KListViewItem( parent, chanName, eBegin, eDuration, eTitle )
+{
+ event = desc;
+}
+
+
+
+int EListViewItem::compare( QListViewItem *i, int col, bool ascending ) const
+{
+ EListViewItem *ei = (EListViewItem*)i;
+
+ if ( col != 1 )
+ return QListViewItem::compare( i, col, ascending );
+
+ if ( event->startDateTime<ei->event->startDateTime )
+ return -1;
+ if ( event->startDateTime==ei->event->startDateTime )
+ return 0;
+ return 1;
+}
+
+
+
+KEvents::KEvents( QPtrList<ChannelDesc> *chans, QPtrList<DvbStream> *d, EventTable *t, QWidget *parent, QSize size ) : QDialog( parent )
+{
+ dvb = d;
+ events = t;
+ channels = chans;
+
+ setCaption( i18n("Electronic Program Guide") );
+
+ QGridLayout *grid = new QGridLayout( this, 1, 1, 11, 6, "grid");
+ QHBoxLayout *hbox = new QHBoxLayout( 0, 0, 6, "hbox" );
+ QVBoxLayout *vbox = new QVBoxLayout( 0, 0, 6 , "vbox");
+
+ resetBtn = new KPushButton( i18n("Refresh"), this );
+ hbox->addWidget( resetBtn );
+ allBtn = new KPushButton( i18n("Scheduled"), this );
+ hbox->addWidget( allBtn );
+ currentNextBtn = new KPushButton( i18n("Current/Next"), this );
+ hbox->addWidget( currentNextBtn );
+ currentChannelEpgBtn = new KPushButton( i18n("Current Channel"), this );
+ hbox->addWidget( currentChannelEpgBtn );
+
+ QSpacerItem* spacer = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ hbox->addItem( spacer );
+
+ vbox->addLayout( hbox);
+
+ hbox = new QHBoxLayout();
+
+ searchBtn = new QToolButton( this );
+ searchBtn->setAutoRaise( true );
+ QToolTip::add( searchBtn, i18n("Electronic Program Guide Search"));
+ hbox->addWidget( searchBtn );
+
+ QLabel* filterLabel = new QLabel( i18n("Search") + ":", this );
+ hbox->addWidget( filterLabel );
+
+ searchLineEdit = new KLineEdit(this);
+ hbox->addWidget( searchLineEdit );
+
+ tvradioCb = new QCheckBox(i18n("TV "), this );
+ QToolTip::add( tvradioCb, i18n("Search TV Channels only (omit Radio)"));
+ tvradioCb->setChecked(true);
+ hbox->addWidget( tvradioCb);
+
+ titleCb = new QCheckBox(i18n("Titles "), this );
+ QToolTip::add( titleCb, i18n("Search Event Titles only (omit Description)"));
+ titleCb->setChecked(true);
+ hbox->addWidget( titleCb);
+
+ ftaCb = new QCheckBox(i18n("FTA "), this );
+ QToolTip::add( ftaCb, i18n("Search Free to Air Channels only (omit PayTV)"));
+ ftaCb->setChecked(false);
+ hbox->addWidget( ftaCb);
+
+ vbox->addLayout( hbox );
+
+ grid->addLayout( vbox, 0, 0 );
+
+ listView = new KListView( this, "listView" );
+ listView->addColumn( i18n( "Channel" ) );
+ listView->addColumn( i18n( "Begin" ) );
+ listView->addColumn( i18n( "Duration" ) );
+ listView->addColumn( i18n( "Title" ) );
+ listView->setResizePolicy( KListView::AutoOneFit );
+ listView->setAllColumnsShowFocus( TRUE );
+ listView->setFullWidth( TRUE );
+ grid->addWidget( listView, 1, 0 );
+ grid->setRowStretch( 1, 4 );
+
+ textBrow = new QTextBrowser( this );
+ grid->addWidget( textBrow, 2, 0 );
+ grid->setRowStretch( 2, 2 );
+
+ KIconLoader *icon = new KIconLoader();
+ resetBtn->setGuiItem( KGuiItem(i18n("Refresh"), icon->loadIconSet("reload", KIcon::Small) ) );
+ allBtn->setGuiItem( KGuiItem(i18n("Scheduled"), icon->loadIconSet("date", KIcon::Small) ) );
+ currentNextBtn->setGuiItem( KGuiItem(i18n("Current/Next"), icon->loadIconSet("toggle_log", KIcon::Small) ) );
+ currentChannelEpgBtn->setGuiItem( KGuiItem(i18n("Current Channel"), icon->loadIconSet("date", KIcon::Small) ) );
+ searchBtn->setIconSet( icon->loadIconSet("locationbar_erase", KIcon::Small) );
+
+ new EListViewItem( (QListView*)listView, "Une chaine", "99/99/99 99:99 9999", "99:99 99", "un titre de programme", 0 );
+
+ resize( size );
+ connect( resetBtn , SIGNAL( pressed() ), this, SLOT( reset() ) );
+ connect( allBtn , SIGNAL( clicked() ), this, SLOT( setScheduled() ) );
+ connect( currentNextBtn , SIGNAL( clicked() ), this, SLOT( setCurrentNext() ) );
+ connect( currentChannelEpgBtn, SIGNAL( clicked() ), this, SLOT( setCurrentChannelEpg() ) );
+ connect( searchBtn, SIGNAL( clicked() ), this, SLOT(resetSearch()) );
+ connect( searchLineEdit, SIGNAL( returnPressed() ), this, SLOT( epgSearch() ) );
+
+ connect( listView, SIGNAL( mouseButtonClicked(int,QListViewItem*,const QPoint&,int) ),
+ this, SLOT(mouseClickedSlot(int,QListViewItem*,const QPoint&,int)) );
+
+ connect( listView, SIGNAL(doubleClicked(QListViewItem*,const QPoint &,int)),
+ this, SLOT(zap(QListViewItem*,const QPoint &,int)) );
+
+ setMode( 1 );
+ delete icon;
+}
+
+void KEvents::resetSearch()
+{
+ searchLineEdit->clear();
+}
+
+void KEvents::checkEpgSearch(QString searchword)
+{
+ int i, j, k, m, n, l;
+ EventSource *esrc;
+ EventTsid *et;
+ EventSid *es;
+ EventDesc *desc;
+ EListViewItem *itt=0;
+ ChannelDesc *ch;
+ QString s, begin, duration, title;
+ bool found;
+
+ for( k=0; k<events->getNSource(); k++ ) {
+ if ( !(esrc=events->getNEventSource( k )) )
+ continue;
+ for ( m=0; m<esrc->getNTsid(); m++ ) {
+ if ( !(et=esrc->getNEventTsid( m )) )
+ continue;
+ for ( n=0; n<et->getNSid(); n++ ) {
+ if ( !(es=et->getNEventSid( n )) )
+ continue;
+ for ( j=0; j<es->getNDesc(); j++ ) {
+ if ( !(desc=es->getEventDesc( j )) )
+ continue;
+
+ if ( desc->title.isEmpty() )
+ continue;
+
+ for ( i=0; i<(int)channels->count(); i++ ) {
+ ch = channels->at(i);
+ if ( desc->source==ch->tp.source && desc->nid==ch->tp.nid && desc->sid==ch->sid && desc->tsid==ch->tp.tsid ) {
+ if(tvradioCb->isChecked() && ch->type==2)
+ break;
+
+ if(ftaCb->isChecked() && ch->fta==1)
+ break;
+
+ found=false;
+ if(desc->title.upper().find(searchword.upper())!=-1)
+ found=true;
+
+ if(!desc->subtitle.isEmpty()) {
+ if(desc->subtitle.upper().find(searchword.upper())!=-1)
+ found=true;
+ }
+
+ if(!titleCb->isChecked()) {
+ if(!found) {
+ for ( l=0; l<(int)desc->extEvents.count(); l++ ) {
+ s = *desc->extEvents.at(l);
+ if(!s.isEmpty()) {
+ if(s.upper().find(searchword.upper())!=-1) {
+ found=true;
+ s="";
+ break;
+ }
+ }
+ }
+ }
+ if(!found) {
+ for ( l=0; l<(int)desc->shortEvents.count(); l++ ) {
+ s = desc->shortEvents.at(l)->name;
+ if(!s.isEmpty()) {
+ if(s.upper().find(searchword.upper())!=-1) {
+ found=true;
+ s="";
+ break;
+ }
+ }
+ s = desc->shortEvents.at(l)->text;
+ if(!s.isEmpty()) {
+ if(s.upper().find(searchword.upper())!=-1) {
+ found=true;
+ s="";
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(!found)
+ break;
+
+ begin = KGlobal::locale()->formatDateTime( desc->startDateTime );
+ duration = desc->duration.toString("hh:mm");
+ title = desc->title;
+
+ itt = new EListViewItem( (QListView*)listView, ch->name, begin, duration, title, desc );
+
+ if ( !ch->pix.isNull() )
+ itt->setPixmap( 0, ch->pix );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void KEvents::epgSearch()
+{
+
+ QString text = searchLineEdit->text();
+ if (text.stripWhiteSpace().isEmpty()) return;
+
+ listView->clear();
+ checkEpgSearch(text);
+}
+
+void KEvents::setCurrentChannelEpg()
+{
+ ChannelDesc curchan;
+ int i;
+ for ( i=0; i<(int)dvb->count(); i++ ) {
+ if ( dvb->at(i)->hasLive() ) {
+ curchan = dvb->at(i)->getLiveChannel();
+ break;
+ }
+ }
+ if ( !curchan.name.isEmpty() )
+ setMode( 2, curchan.name );
+
+}
+
+void KEvents::zap( QListViewItem* it, const QPoint &p, int col )
+{
+ QPoint pt=p;
+ int c=col;
+ c++;
+
+ if ( it->text(0) != QString::null )
+ emit zapTo( it->text(0) );
+}
+
+
+
+void KEvents::mouseClickedSlot( int btn, QListViewItem *it, const QPoint &p, int c )
+{
+ int i=c;
+ QPoint pt=p;
+ QString s;
+
+ if ( !it )
+ return;
+ EListViewItem *ei = (EListViewItem*)it;
+
+ switch ( btn ) {
+ case Qt::RightButton : {
+ QPopupMenu *pop = new QPopupMenu();
+ pop->insertItem( i18n("View All Programs"), 1 );
+ pop->insertSeparator();
+ pop->insertItem( i18n("Add to Timers"), 2 );
+ if ( ei->event->running==4 )
+ pop->setItemEnabled( 2, false );
+ i = 0;
+ i = pop->exec( QCursor::pos() );
+ switch ( i ) {
+ case 0 :
+ break;
+ case 1 :
+ setMode( 2, it->text(0) );
+ break;
+ case 2 :
+ emit addTimer( it->text(0), it->text(3), ei->event->startDateTime, ei->event->duration );
+ break;
+ }
+ delete pop;
+ break;
+ }
+ case Qt::LeftButton : {
+ s = "<qt><h3><font color=\"darkblue\">";
+ s = s+it->text(0)+"</font></h3>";
+ if ( !ei->event->title.isEmpty() ) {
+ s = s+"<b><font color=\"darkgreen\"><big>";
+ s = s+ei->event->title;
+ s = s+"</big></font></b><br>";
+ }
+ if ( !ei->event->subtitle.isEmpty() ) {
+ s = s+"<b><font color=\"#A69631\">";
+ s = s+ei->event->subtitle;
+ s = s+"</font></b><br>";
+ }
+ s = s+"<br><font color=\"darkred\">";
+ s = s+KGlobal::locale()->formatDateTime( ei->event->startDateTime, false )+"<br>";
+ s = s+ei->event->duration.toString("hh:mm");
+ s = s+"</font><br><br>";
+ for ( i=0; i<(int)ei->event->shortEvents.count(); i++ ) {
+ s = s+"<p>";
+ s = s + ei->event->shortEvents.at(i)->name;
+ if (!ei->event->shortEvents.at(i)->name.isEmpty() && !ei->event->shortEvents.at(i)->text.isEmpty()) {
+ s = s + " : ";
+ }
+ s = s + ei->event->shortEvents.at(i)->text;
+ s = s + "</p>";
+ }
+ for ( i=0; i<(int)ei->event->extEvents.count(); i++ ) {
+ s = s+ *ei->event->extEvents.at(i);
+ }
+ s = s+"</qt>";
+ textBrow->setText( s );
+ break;
+ }
+ }
+}
+
+
+
+void KEvents::setCurrentNext()
+{
+ setMode( 1 );
+}
+
+
+
+void KEvents::setScheduled()
+{
+ QListViewItem *it = listView->currentItem();
+ if ( !it )
+ return;
+ setMode( 2, it->text(0) );
+}
+
+
+
+void KEvents::setMode( int m, QString name )
+{
+ int i;
+
+ mode = m;
+ if ( !name.isEmpty() ) {
+ currentNextBtn->show();
+ allBtn->hide();
+ for ( i=0; i<(int)channels->count(); i++ ) {
+ if ( channels->at(i)->name==name ) {
+ chan = channels->at(i);
+ break;
+ }
+ }
+ }
+ else {
+ chan = 0;
+ currentNextBtn->hide();
+ allBtn->show();
+ }
+ reset();
+}
+
+
+
+void KEvents::reset()
+{
+ listView->clear();
+ checkNewEvent();
+}
+
+
+
+void KEvents::checkNewEvent()
+{
+ int i;
+ EventSource *esrc;
+ EventSid *es;
+ EventDesc *desc;
+ EListViewItem *itt=0;
+ ChannelDesc *ch;
+ QString s, t, channel, begin, duration, title;
+
+ if ( mode==2 ) {
+ if ( !chan )
+ return;
+ if ( !(esrc=events->getEventSource( chan->tp.source )) )
+ return;
+ if ( !(es=esrc->getEventSid( chan->tp.nid, chan->tp.tsid, chan->sid )) )
+ return;
+ i = 0;
+ while ( (desc=es->getEventDesc(i)) ) {
+ ++i;
+ begin = KGlobal::locale()->formatDateTime( desc->startDateTime );
+ duration = desc->duration.toString("hh:mm");
+ title = desc->title;
+ if ( title.isEmpty() )
+ continue;
+ itt = new EListViewItem( (QListView*)listView, chan->name, begin, duration, title, desc );
+ if ( !chan->pix.isNull() )
+ itt->setPixmap( 0, chan->pix );
+ }
+ return;
+ }
+
+ for ( i=0; i<(int)channels->count(); i++ ) {
+ ch = channels->at(i);
+ if ( (desc=events->getEventDesc( ch->tp.source, ch->tp.nid, ch->tp.tsid, ch->sid, 0 )) ) {
+ begin = KGlobal::locale()->formatDateTime( desc->startDateTime );
+ duration = desc->duration.toString("hh:mm");
+ title = desc->title;
+ if ( title.isEmpty() )
+ continue;
+ itt = new EListViewItem( (QListView*)listView, ch->name, begin, duration, title, desc );
+ if ( !ch->pix.isNull() )
+ itt->setPixmap( 0, ch->pix );
+ }
+ }
+}
+
+
+
+KEvents::~KEvents()
+{
+}
+
+#include "kevents.moc"
diff --git a/kaffeine/src/input/dvb/kevents.h b/kaffeine/src/input/dvb/kevents.h
new file mode 100644
index 0000000..3779452
--- /dev/null
+++ b/kaffeine/src/input/dvb/kevents.h
@@ -0,0 +1,98 @@
+/*
+ * kevents.h
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KEVENTS_H
+#define KEVENTS_H
+
+#include <qtimer.h>
+#include <qdialog.h>
+#include <qdatetime.h>
+#include <qtextbrowser.h>
+
+#include <klistview.h>
+#include <kpushbutton.h>
+#include <klineedit.h>
+
+class EventDesc;
+class DvbStream;
+class EventTable;
+class ChannelDesc;
+
+
+class EListViewItem : public KListViewItem
+{
+
+public:
+
+ EListViewItem( QListView *parent, QString chanName, QString eBegin, QString eDuration, QString eTitle, EventDesc *desc );
+ virtual int compare( QListViewItem *i, int col, bool ascending ) const;
+
+ EventDesc *event;
+};
+
+
+
+class KEvents : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ KEvents( QPtrList<ChannelDesc> *chans, QPtrList<DvbStream> *d, EventTable *t, QWidget *parent, QSize size );
+ ~KEvents();
+
+private slots:
+
+ void mouseClickedSlot( int btn, QListViewItem *it, const QPoint &p, int c );
+ void reset();
+ void setMode( int m, QString name="" );
+ void setScheduled();
+ void setCurrentNext();
+ void setCurrentChannelEpg();
+ void epgSearch();
+ void resetSearch();
+ void zap( QListViewItem* it, const QPoint &p, int col );
+
+private:
+ void checkEpgSearch(QString searchword);
+ void checkNewEvent();
+
+ QPtrList<DvbStream> *dvb;
+ EventTable *events;
+ KListView *listView;
+ KPushButton *resetBtn, *currentNextBtn, *allBtn, *currentChannelEpgBtn;
+ QToolButton *searchBtn;
+ QCheckBox *titleCb,*tvradioCb,*ftaCb;
+ QPtrList<ChannelDesc> *channels;
+ QTextBrowser *textBrow;
+ int mode;
+ ChannelDesc *chan;
+
+protected:
+
+ KLineEdit *searchLineEdit;
+
+signals:
+
+ void addTimer( QString channel, QString name, QDateTime begin, QTime duration );
+ void zapTo( const QString &channel );
+};
+
+#endif /* KEVENTS_H */
diff --git a/kaffeine/src/input/dvb/kgradprogress.cpp b/kaffeine/src/input/dvb/kgradprogress.cpp
new file mode 100644
index 0000000..092cfb3
--- /dev/null
+++ b/kaffeine/src/input/dvb/kgradprogress.cpp
@@ -0,0 +1,136 @@
+/*
+ * kgradprogress.cpp
+ *
+ * Copyright (C) 2003-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qpainter.h>
+#include <qlabel.h>
+
+#include "kgradprogress.h"
+
+
+
+KGradProgress::KGradProgress( QWidget *parent ) : QLabel( parent )
+{
+ barPix = 0;
+ colorUp = QColor( 0, 255, 0 );
+ colorDown = QColor( 255, 0, 0 );
+ current = 0;
+ setFrameStyle( QFrame::Box | QFrame::Plain );
+ setLineWidth(1);
+ setMidLineWidth(0);
+ setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
+}
+
+
+
+void KGradProgress::setProgress( int progress )
+{
+ current = progress;
+ draw();
+ repaint(false);
+}
+
+
+
+void KGradProgress::draw()
+{
+ int i, j;
+ int a, b;
+ int off = frameWidth();
+ int h = height() - ( 2*off );
+ int w = width() - ( 2*off );
+ int per;
+ QString s;
+ QFont f;
+
+ s = s.setNum( current )+"%";
+ per = current*w/100;
+
+ if ( barPix ) delete barPix;
+ barPix = new QPixmap( w, h, -1, QPixmap::BestOptim );
+ QPainter p( barPix );
+ p.fillRect( 0, 0, w, h, paletteBackgroundColor() );
+
+ for ( j=0; j<per; j++ ) {
+ if ( j<(w/2) ) {
+ a = 255;
+ b = 2*j*255/w;
+ }
+ else {
+ a = 255-(2*(j-w/2)*255/w);
+ b = 255;
+ }
+ p.setPen( QColor( a, b, 0 ) );
+ for ( i=0; i<h; i++ ) p.drawPoint( j+off, i+off );
+ }
+
+ f = font();
+ f.setPointSize( int(h/1.2) );
+ p.setFont( f );
+ p.setPen( QColor( 0, 0, 0 ) );
+ p.drawText( w/2, (h/2)+(f.pointSize()/2), s );
+ p.end();
+}
+
+
+
+void KGradProgress::resizeEvent( QResizeEvent *e )
+{
+ QSize s=e->size();
+ draw();
+}
+
+
+
+void KGradProgress::paintEvent(QPaintEvent *event)
+{
+ int x, y, w, h;
+
+ x = y = frameWidth();
+ w = width() - (2*x);
+ h = height() - (2*y);
+
+ QLabel::paintEvent( event );
+
+ bitBlt( this, x, y, barPix, 0, 0, w, h, CopyROP );
+}
+
+
+
+QSize KGradProgress::sizeHint()
+{
+ QLabel lab( "This is a progress bar.", 0 );
+ return QSize( lab.width(), int(font().pointSize()*1.2) );
+}
+
+
+
+QSizePolicy KGradProgress::sizePolicy()
+{
+ return QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
+}
+
+
+
+KGradProgress::~KGradProgress()
+{
+ delete barPix;
+}
+
+#include "kgradprogress.moc"
diff --git a/kaffeine/src/input/dvb/kgradprogress.h b/kaffeine/src/input/dvb/kgradprogress.h
new file mode 100644
index 0000000..a55591e
--- /dev/null
+++ b/kaffeine/src/input/dvb/kgradprogress.h
@@ -0,0 +1,59 @@
+/*
+ * kgradprocess.h
+ *
+ * Copyright (C) 2003-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KGRADPROGRESS_H
+#define KGRADPROGRESS_H
+
+#include <qlabel.h>
+#include <qpixmap.h>
+
+
+
+class KGradProgress : public QLabel
+{
+
+ Q_OBJECT
+
+public:
+
+ KGradProgress( QWidget *parent );
+ ~KGradProgress();
+ virtual void paintEvent(QPaintEvent *event);
+ virtual QSize sizeHint();
+ virtual QSizePolicy sizePolicy();
+
+public slots:
+
+ void setProgress( int progress );
+
+protected:
+
+ virtual void resizeEvent( QResizeEvent *e );
+
+private:
+
+ void draw();
+
+ QPixmap *barPix;
+ QColor colorDown, colorUp;
+ int current;
+};
+
+#endif /* KGRADPROGRESS_H */
diff --git a/kaffeine/src/input/dvb/krecord.cpp b/kaffeine/src/input/dvb/krecord.cpp
new file mode 100644
index 0000000..7e14036
--- /dev/null
+++ b/kaffeine/src/input/dvb/krecord.cpp
@@ -0,0 +1,295 @@
+/*
+ * krecord.cpp
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qframe.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+#include "krecord.h"
+
+
+
+KRecord::KRecord( QStringList chanList, QPtrList<RecTimer> *t, QWidget *parent, QSize size ) : QDialog( parent )
+{
+ timers = t;
+ channelsList = chanList;
+
+ QVBoxLayout *vb = new QVBoxLayout( 0, 0, 6 );
+ QLabel *lab = new QLabel( i18n("Timers list:"), this );
+ vb->addWidget( lab );
+
+ list = new KListView( this );
+ list->addColumn( "" );
+ list->addColumn( i18n( "Name" ) );
+ list->addColumn( i18n( "Channel" ) );
+ list->addColumn( i18n( "Begin" ) );
+ list->addColumn( i18n( "Duration" ) );
+ list->setResizePolicy( KListView::AutoOneFit );
+ list->setAllColumnsShowFocus( true );
+ list->setFullWidth( true );
+ QListViewItem * item = new QListViewItem( list, 0 );
+ item->setText( 0, "00" );
+ item->setText( 1, "Un nom assez long mais pas trop" );
+ item->setText( 2, "Une chaine du meme calibre" );
+ item->setText( 3, "00:00 00/00/00mm" );
+ item->setText( 4, "00:00mm" );
+ vb->addWidget( list );
+
+ QVBoxLayout *vb1 = new QVBoxLayout( 0, 0, 6 );
+ newBtn = new KPushButton(i18n("New"), this);
+ vb1->addWidget( newBtn );
+ editBtn = new KPushButton(i18n("Edit"), this);
+ vb1->addWidget( editBtn );
+ deleteBtn = new KPushButton(i18n("Delete"), this);
+ vb1->addWidget( deleteBtn );
+ vb1->addItem( new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding ) );
+
+ QHBoxLayout *hb = new QHBoxLayout( 0, 0, 6 );
+ hb->addLayout( vb );
+ hb->addLayout( vb1 );
+
+ QHBoxLayout *hb1 = new QHBoxLayout( 0 );
+ hb1->addItem( new QSpacerItem( 20, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum ) );
+ okBtn = new KPushButton(i18n("Close"), this);
+ hb1->addWidget( okBtn );
+
+ QVBoxLayout *vb2 = new QVBoxLayout( this, 6, 6 );
+ vb2->addLayout( hb );
+ QFrame *line = new QFrame( this, "line1" );
+ line->setFrameStyle( QFrame::HLine );
+ line->setFrameShadow( QFrame::Sunken );
+ line->setFrameShape( QFrame::HLine );
+ vb2->addWidget( line );
+ vb2->addLayout( hb1 );
+
+ KIconLoader *icon = new KIconLoader();
+ newBtn->setGuiItem( KGuiItem(i18n("New"), icon->loadIconSet("filenew", KIcon::Small) ) );
+ editBtn->setGuiItem( KGuiItem(i18n("Edit"), icon->loadIconSet("edit", KIcon::Small) ) );
+ //editBtn->setEnabled( false );
+ deleteBtn->setGuiItem( KGuiItem(i18n("Stop/Delete"), icon->loadIconSet("editcut", KIcon::Small) ) );
+ okBtn->setGuiItem( KGuiItem(i18n("Close"), icon->loadIconSet("exit", KIcon::Small) ) );
+
+ isRecording = icon->loadIcon("player_record", KIcon::Small);
+ yesRepeat = icon->loadIcon("reload", KIcon::Small);
+
+ setCaption( i18n("Timers") );
+
+ connect( okBtn, SIGNAL(clicked()), this, SLOT(accept()) );
+ connect( newBtn, SIGNAL(clicked()), this, SLOT(newTimer()) );
+ connect( deleteBtn, SIGNAL(clicked()), this, SLOT(deleteTimer()) );
+ connect( editBtn, SIGNAL(clicked()), this, SLOT(editTimer()) );
+
+ refresh();
+ resize( size );
+ delete icon;
+}
+
+
+
+void KRecord::refresh()
+{
+ QListViewItem *after, *itt;
+ RecTimer *ti;
+ int i;
+ QString s;
+
+ list->clear();
+ list->setSorting( -1 );
+ for ( i=0; i<(int)timers->count(); i++ ) {
+ ti = timers->at(i);
+ after = where( ti );
+ /*if ( ti->running ) s = ">";
+ else s = "";
+ s = s+ti->name;*/
+ s = ti->name;
+ itt = new KListViewItem( (QListView*)list, "", s, ti->channel, KGlobal::locale()->formatDateTime( ti->begin ), ti->duration.toString("hh:mm") );
+ if ( ti->mode )
+ itt->setPixmap( 0, yesRepeat );
+ if ( ti->running )
+ itt->setPixmap( 1, isRecording );
+ if ( after )
+ itt->moveItem( after );
+ }
+}
+
+
+
+void KRecord::newTimer()
+{
+ QListViewItem *itt, *after;
+ RecTimer *t = new RecTimer();
+
+ t->running = 0;
+ t->mode = 0;
+
+ KTimerEditor dlg( true, channelsList, *t, this );
+ int ret=dlg.exec();
+ if ( ret==KTimerEditor::Accepted ) {
+ *t = dlg.timer;
+ after = where( t, true );
+ itt = new KListViewItem( (QListView*)list, "", t->name, t->channel, KGlobal::locale()->formatDateTime( t->begin ), t->duration.toString("hh:mm") );
+ if ( t->mode )
+ itt->setPixmap( 0, yesRepeat );
+ if ( t->running )
+ itt->setPixmap( 1, isRecording );
+ if ( after )
+ itt->moveItem( after );
+ }
+ else delete t;
+}
+
+
+
+void KRecord::editTimer()
+{
+ QListViewItem *it, *after;
+ int i=0;
+ RecTimer *t, *tn=0;
+
+ it = list->firstChild();
+ while ( it!=0 ) {
+ if ( it->isSelected() )
+ break;
+ it = it->nextSibling();
+ }
+ if ( !it )
+ return;
+
+ for ( i=0; i<(int)timers->count(); i++ ) {
+ t = timers->at(i);
+ if ( t->name==it->text(1) && t->channel==it->text(2) ) {
+ tn = t;
+ break;
+ }
+ }
+
+ if ( !tn )
+ return;
+
+ KTimerEditor dlg( false, channelsList, *tn, this );
+ int ret=dlg.exec();
+ if ( ret==KTimerEditor::Accepted ) {
+ for ( i=0; i<(int)timers->count(); i++ ) {
+ if ( timers->at(i)==tn ) {
+ if ( tn->running ) {
+ int ms = tn->begin.time().secsTo( QTime::currentTime() );
+ ms = ((dlg.timer.duration.hour()*3600+dlg.timer.duration.minute()*60)-ms)*1000;
+ if ( ms<2000 )
+ ms = 0;
+ tn->duration = dlg.timer.duration;
+ emit updateTimer( tn, ms );
+ if ( ms )
+ refresh();
+ }
+ else {
+ timers->remove( tn );
+ t = new RecTimer();
+ *t = dlg.timer;
+ after = where( t, true );
+ refresh();
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+
+void KRecord::deleteTimer()
+{
+ QListViewItem *it;
+ int i=0, ret;
+ KIconLoader *icon = new KIconLoader();
+
+ it = list->firstChild();
+ while ( it!=0 ) {
+ if ( it->isSelected() ) {
+ if ( timers->at(i)->mode )
+ ret = KMessageBox::questionYesNoCancel( this, i18n("This timer is repeated. Do you want to skip the current job or delete the timer?"), i18n("Warning"), KGuiItem(i18n("Skip Current"), icon->loadIconSet("next", KIcon::Small) ), KGuiItem(i18n("Delete"), icon->loadIconSet("editcut", KIcon::Small) ) );
+ else
+ ret = KMessageBox::questionYesNo( this, i18n("Delete the selected timer?") );
+ if ( ret==KMessageBox::Yes ) {
+ emit updateTimer( timers->at(i), 0 );
+ }
+ else if ( ret==KMessageBox::No && timers->at(i)->mode ) {
+ timers->at(i)->mode=0;
+ emit updateTimer( timers->at(i), 0 );
+ }
+ break;
+ }
+ i++;
+ it = it->nextSibling();
+ }
+
+ delete icon;
+}
+
+
+
+QListViewItem* KRecord::where( RecTimer *rt, bool add )
+{
+ QListViewItem *it, *ret=0;
+ int i, r=0;
+ RecTimer *t;
+
+ for ( i=0; i<(int)timers->count(); i++ ) {
+ t = timers->at(i);
+ if ( rt->begin>t->begin )
+ r=i+1;
+ }
+ if ( add )
+ timers->insert( r, rt );
+ if ( !r )
+ return ret;
+
+ it = list->firstChild();
+ i=0;
+ while ( it!=0 ) {
+ if ( i==(r-1) ) {
+ ret = it;
+ break;
+ }
+ i++;
+ it = it->nextSibling();
+ }
+ return ret;
+}
+
+
+
+void KRecord::accept()
+{
+ done( Accepted );
+}
+
+
+
+KRecord::~KRecord()
+{
+}
+
+#include "krecord.moc"
diff --git a/kaffeine/src/input/dvb/krecord.h b/kaffeine/src/input/dvb/krecord.h
new file mode 100644
index 0000000..6a9f1f3
--- /dev/null
+++ b/kaffeine/src/input/dvb/krecord.h
@@ -0,0 +1,69 @@
+/*
+ * krecord.h
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KRECORD_H
+#define KRECORD_H
+
+#include <qdialog.h>
+#include <qpixmap.h>
+
+#include <kpushbutton.h>
+#include <klistview.h>
+
+#include "channeldesc.h"
+#include "ktimereditor.h"
+
+
+
+class KRecord : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ KRecord( QStringList chanList, QPtrList<RecTimer> *t, QWidget *parent, QSize size );
+ ~KRecord();
+
+ QStringList channelsList;
+
+protected slots:
+
+ virtual void accept();
+ void newTimer();
+ void editTimer();
+ void deleteTimer();
+ void refresh();
+
+private:
+
+ QListViewItem* where( RecTimer *rt, bool add=false );
+
+ KPushButton *newBtn, *editBtn, *deleteBtn, *okBtn;
+ KListView *list;
+ QPtrList<RecTimer> *timers;
+ QPixmap isRecording, yesRepeat;
+
+signals:
+
+ void updateTimer(RecTimer*, int);
+
+};
+
+#endif /* KRECORD_H */
diff --git a/kaffeine/src/input/dvb/ktimereditor.cpp b/kaffeine/src/input/dvb/ktimereditor.cpp
new file mode 100644
index 0000000..63993c0
--- /dev/null
+++ b/kaffeine/src/input/dvb/ktimereditor.cpp
@@ -0,0 +1,231 @@
+/*
+ * ktimereditor.cpp
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+#include "ktimereditor.h"
+
+
+
+KTimerEditor::KTimerEditor( bool newone, QStringList &chanList, RecTimer t, QWidget *parent ) : QDialog( parent )
+{
+ int i;
+
+ QGridLayout *grid = new QGridLayout( 0, 1, 1, 11, 6 );
+ QLabel *lab = new QLabel( i18n("Name:"), this );
+ grid->addWidget( lab, 0, 0 );
+ nameLe = new QLineEdit( this );
+ grid->addWidget( nameLe, 0, 1 );
+ lab = new QLabel( i18n("Channel:"), this );
+ grid->addWidget( lab, 1, 0 );
+ channelComb = new QComboBox( this );
+ grid->addWidget( channelComb, 1, 1 );
+ lab = new QLabel( i18n("Begin:"), this );
+ grid->addWidget( lab, 2, 0 );
+ begin = new QDateTimeEdit( this );
+ grid->addWidget( begin, 2, 1 );
+ lab = new QLabel( i18n("Duration:"), this );
+ grid->addWidget( lab, 3, 0 );
+ duration = new QTimeEdit( this );
+ grid->addWidget( duration, 3, 1 );
+ lab = new QLabel( i18n("End:"), this );
+ grid->addWidget( lab, 4, 0 );
+ end = new QDateTimeEdit( this );
+ grid->addWidget( end, 4, 1 );
+ repeatBtn = new KPushButton( this );
+ grid->addWidget( repeatBtn, 5, 0 );
+ repeatLab = new QLabel( this );
+ grid->addWidget( repeatLab, 5, 1 );
+
+ QFrame *line = new QFrame( this, "line1" );
+ line->setFrameStyle( QFrame::HLine );
+ line->setFrameShadow( QFrame::Sunken );
+ line->setFrameShape( QFrame::HLine );
+
+ QHBoxLayout *hb = new QHBoxLayout( 0, 0, 6 );
+ cancelBtn = new KPushButton( this );
+ hb->addWidget( cancelBtn );
+ hb->addItem( new QSpacerItem( 20, 20, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum ) );
+ okBtn = new KPushButton( this );
+ okBtn->setDefault( true );
+ hb->addWidget( okBtn );
+
+ QVBoxLayout *vb = new QVBoxLayout( this, 6, 6 );
+ vb->addLayout( grid );
+ vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding ) );
+ vb->addWidget( line );
+ vb->addLayout( hb );
+
+ timer = t;
+
+
+ //begin->dateEdit()->setOrder( QDateEdit::DMY );
+ channelComb->insertStringList( chanList );
+
+ if ( newone ) {
+ begin->setDateTime( QDateTime::currentDateTime() );
+ duration->setTime( QTime(2,0,0) );
+ }
+ else {
+ nameLe->setText( timer.name );
+ for ( i=0; i<channelComb->count(); i++ ) {
+ if ( channelComb->text(i)==timer.channel ) {
+ channelComb->setCurrentItem(i);
+ break;
+ }
+ }
+ begin->setDateTime( timer.begin );
+ duration->setTime( timer.duration );
+ if ( timer.running ) {
+ nameLe->setEnabled( false );
+ channelComb->setEnabled( false );
+ begin->setEnabled( false );
+ repeatBtn->setEnabled( false );
+ }
+ }
+ switch ( timer.mode ) {
+ case CronTimer::Noone : repeatLab->setText( i18n("None") ); break;
+ case CronTimer::Daily : repeatLab->setText( i18n("Daily") ); break;
+ case CronTimer::Weekly : repeatLab->setText( i18n("Weekly") ); break;
+ case CronTimer::Monthly : repeatLab->setText( i18n("Monthly") ); break;
+ default : repeatLab->setText( i18n("Custom") );
+ }
+
+ KIconLoader *icon = new KIconLoader();
+ cancelBtn->setGuiItem( KStdGuiItem::cancel() );
+ okBtn->setGuiItem( KStdGuiItem::ok() );
+ repeatBtn->setGuiItem( KGuiItem(i18n("Repeat..."), icon->loadIconSet("reload", KIcon::Small) ) );
+
+ setCaption( i18n("Timer Editor") );
+
+ connect( okBtn, SIGNAL(clicked()), this, SLOT(accept()) );
+ connect( cancelBtn, SIGNAL(clicked()), this, SLOT(reject()) );
+ connect( repeatBtn, SIGNAL(clicked()), this, SLOT(setRepeat()) );
+ connect( begin, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setMaxEnd(const QDateTime&)) );
+ connect( end, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setDuration(const QDateTime&)) );
+ connect( duration, SIGNAL(valueChanged(const QTime&)), this, SLOT(setEnd(const QTime&)) );
+ setMaxEnd( begin->dateTime() );
+ delete icon;
+}
+
+
+
+void KTimerEditor::setMaxEnd( const QDateTime &dt )
+{
+ QDateTime max = dt.addSecs( 23*3600+59*60+59 );
+ end->dateEdit()->setMinValue( dt.date() );
+ end->dateEdit()->setMaxValue( max.date() );
+ setEnd( duration->time() );
+}
+
+
+
+void KTimerEditor::setDuration( const QDateTime &dt )
+{
+ disconnect( duration, SIGNAL(valueChanged(const QTime&)), this, SLOT(setEnd(const QTime&)) );
+ duration->setTime( QTime().addSecs( begin->dateTime().secsTo( dt ) ) );
+ connect( duration, SIGNAL(valueChanged(const QTime&)), this, SLOT(setEnd(const QTime&)) );
+}
+
+
+
+void KTimerEditor::setEnd( const QTime &t )
+{
+ disconnect( end, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setDuration(const QDateTime&)) );
+ end->setDateTime( begin->dateTime().addSecs( QTime().secsTo( t ) ) );
+ connect( end, SIGNAL(valueChanged(const QDateTime&)), this, SLOT(setDuration(const QDateTime&)) );
+}
+
+
+
+void KTimerEditor::setRepeat()
+{
+ CronTimer dlg( timer.mode, this );
+
+ if ( dlg.exec()==CronTimer::Accepted )
+ timer.mode = dlg.getMode();
+ switch ( timer.mode ) {
+ case CronTimer::Noone : repeatLab->setText( i18n("None") ); break;
+ case CronTimer::Daily : repeatLab->setText( i18n("Daily") ); break;
+ case CronTimer::Weekly : repeatLab->setText( i18n("Weekly") ); break;
+ case CronTimer::Monthly : repeatLab->setText( i18n("Monthly") ); break;
+ default : repeatLab->setText( i18n("Custom") );
+ }
+}
+
+
+
+void KTimerEditor::accept()
+{
+ if ( nameLe->text().stripWhiteSpace().isEmpty() ) {
+ KMessageBox::sorry( this, i18n("You must give it a name!") );
+ nameLe->setFocus();
+ return;
+ }
+
+ if ( nameLe->text().stripWhiteSpace().contains("/") )
+ goto stop;
+ if ( nameLe->text().stripWhiteSpace().contains(">") )
+ goto stop;
+ if ( nameLe->text().stripWhiteSpace().contains("<") )
+ goto stop;
+ if ( nameLe->text().stripWhiteSpace().contains("\\") )
+ goto stop;
+ if ( nameLe->text().stripWhiteSpace().contains(":") )
+ goto stop;
+ if ( nameLe->text().stripWhiteSpace().contains("\"") )
+ goto stop;
+ if ( nameLe->text().stripWhiteSpace().contains("|") )
+ goto stop;
+
+ if ( duration->time()<QTime(0,1) ) {
+ KMessageBox::sorry( this, i18n("Duration must be at least 1 minute!") );
+ duration->setFocus();
+ return;
+ }
+
+ timer.duration = duration->time();
+ if ( timer.running )
+ done( Accepted );
+
+ timer.name = nameLe->text().stripWhiteSpace();
+ timer.channel = channelComb->currentText();
+ timer.begin = begin->dateTime();
+ done( Accepted );
+ return;
+
+stop:
+ KMessageBox::sorry( this, i18n("Name must not contain any of the following characters: > < \\ / : \" |") );
+ nameLe->setFocus();
+ return;
+}
+
+
+
+KTimerEditor::~KTimerEditor()
+{
+}
+
+#include "ktimereditor.moc"
diff --git a/kaffeine/src/input/dvb/ktimereditor.h b/kaffeine/src/input/dvb/ktimereditor.h
new file mode 100644
index 0000000..dfe1683
--- /dev/null
+++ b/kaffeine/src/input/dvb/ktimereditor.h
@@ -0,0 +1,67 @@
+/*
+ * ktimereditor.h
+ *
+ * Copyright (C) 2004-2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTIMEREDITOR_H
+#define KTIMEREDITOR_H
+
+#include <qdialog.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qdatetimeedit.h>
+#include <qlabel.h>
+
+#include <kpushbutton.h>
+
+#include "channeldesc.h"
+#include "gdvb.h"
+#include "crontimer.h"
+
+
+
+class KTimerEditor : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ KTimerEditor( bool newone, QStringList &chanList, RecTimer t, QWidget *parent );
+ ~KTimerEditor();
+
+ KPushButton *okBtn, *cancelBtn, *repeatBtn;
+ QLabel *repeatLab;
+ QLineEdit *nameLe;
+ QComboBox *channelComb;
+ QDateTimeEdit *begin, *end;
+ QTimeEdit *duration;
+ RecTimer timer;
+
+public slots:
+
+ void setRepeat();
+
+protected slots:
+
+ virtual void accept();
+ void setDuration( const QDateTime &dt );
+ void setEnd( const QTime &t );
+ void setMaxEnd( const QDateTime &dt );
+};
+
+#endif /* KTIMEREDITOR_H */
diff --git a/kaffeine/src/input/dvb/lib/Makefile.am b/kaffeine/src/input/dvb/lib/Makefile.am
new file mode 100644
index 0000000..aa4701c
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libdvbapi libdvben50221 libucsi
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am b/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am
new file mode 100644
index 0000000..59f288b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = libdvbapi.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib
+
+libdvbapi_la_SOURCES = diseqc.c \
+ dvbca.c \
+ dvbdemux.c \
+ dvbfe.c \
+ dvbnet.c
+
+CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.c b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.c
new file mode 100644
index 0000000..8c8771d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.c
@@ -0,0 +1,141 @@
+/*
+ libdvbfe - a DVB frontend library
+
+ Copyright (C) 2005 Manu Abraham <manu@kromtek.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <linux/dvb/frontend.h>
+#include "diseqc.h"
+#include <libdvbmisc/dvbmisc.h>
+
+
+int verbose = 1;
+
+int set_22k_tone(int fd, dvbfe_sec_tone_mode_t tone)
+{
+ int ret = 0;
+
+ if (fd > 0) {
+ switch (tone) {
+ case DVBFE_SEC_TONE_OFF:
+ ret = ioctl(fd, FE_SET_TONE, DVBFE_SEC_TONE_OFF);
+ break;
+ case DVBFE_SEC_TONE_ON:
+ ret = ioctl(fd, FE_SET_TONE, DVBFE_SEC_TONE_ON);
+ break;
+ default:
+ print(verbose, ERROR, 1, "Invalid command !");
+ break;
+ }
+ if (ret == -1)
+ print(verbose, ERROR, 1, "IOCTL failed !");
+ } else
+ print(verbose, ERROR, 1, "Device open error !");
+
+ return ret;
+}
+
+int set_tone_data_burst(int fd, dvbfe_sec_mini_cmd_t minicmd)
+{
+ int ret = 0;
+
+ if (fd > 0) {
+ switch (minicmd) {
+ case DVBFE_SEC_MINI_A:
+ ret = ioctl(fd, FE_DISEQC_SEND_BURST, DVBFE_SEC_MINI_A);
+ break;
+ case DVBFE_SEC_MINI_B:
+ ret = ioctl(fd, FE_DISEQC_SEND_BURST, DVBFE_SEC_MINI_B);
+ break;
+ default:
+ print(verbose, ERROR, 1, "Invalid command");
+ break;
+ }
+ if (ret == -1)
+ print(verbose, ERROR, 1, "IOCTL failed");
+ } else
+ print(verbose, ERROR, 1, "Device open error !");
+
+ return ret;
+}
+
+int set_polarization(int fd, dvbfe_sec_voltage_t polarization)
+{
+ int ret = 0;
+
+ if (fd > 0) {
+ switch (polarization) {
+ case DVBFE_SEC_VOLTAGE_13:
+ ret = ioctl(fd, FE_SET_VOLTAGE, DVBFE_SEC_VOLTAGE_13);
+ break;
+ case DVBFE_SEC_VOLTAGE_18:
+ ret = ioctl(fd, FE_SET_VOLTAGE, DVBFE_SEC_VOLTAGE_18);
+ break;
+ default:
+ print(verbose, ERROR, 1, "Invalid command");
+ break;
+ }
+ if (ret == -1)
+ print(verbose, ERROR, 1, "IOCTL failed");
+ } else
+ print(verbose, ERROR, 1, "Device open error !");
+
+ return ret;
+}
+
+int do_diseqc_cmd(int fd, uint8_t cmd, uint8_t address, uint8_t *data)
+{
+ int ret = 0;
+ uint8_t length;
+ struct diseqc_cmd diseqc_message;
+
+ memcpy(&diseqc_message.message[0], &msgtbl->command[1], 6);
+ length = msgtbl->command[0];
+ diseqc_message.length = length;
+
+ /* Set Address */
+ diseqc_message.message[2] = address;
+ switch (length) {
+ case 6:
+ /* Set Data */
+ diseqc_message.message[5] = data[2];
+ case 5:
+ /* Set Data */
+ diseqc_message.message[4] = data[1];
+ case 4:
+ /* Set Data */
+ diseqc_message.message[3] = data[0];
+ case 3:
+ /* Only cmd */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (fd > 0) {
+ ret = ioctl(fd, cmd, &diseqc_message);
+ if (ret == -1)
+ print(verbose, ERROR, 1, "IOCTL failed");
+
+ } else
+ print(verbose, ERROR, 1, "Device open error !");
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.h b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.h
new file mode 100644
index 0000000..fc8ffd4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/diseqc.h
@@ -0,0 +1,171 @@
+/*
+ libdvbfe - a DVB frontend library
+
+ Copyright (C) 2005 Manu Abraham <manu@kromtek.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#ifndef DISEQC_H
+#define DISEQC_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/* Addresses */
+#define DISEQCxx_MASTER 0x00
+#define SMATV_MASTER 0x10
+#define LNB_MASTER 0x10
+#define SWITCHER_MASTER 0x10
+#define LNB 0x11
+#define LNB_LOOP 0x12
+#define SWITCHER_DC 0x14
+#define SWITCHER_DC_LOOP 0x15
+#define POL_CONTROLLER 0x21
+#define POSITIONER_MASTER 0x30
+#define POSITIONER_POLAR 0x31
+#define POSITIONER_ELEVATION 0x32
+
+/* Commands */
+#define DISEQC_SET_LOW_LO 0
+#define DISEQC10_SET_VERT_POL 1
+#define DISEQC10_SET_SAT_POS_A 2
+#define DISEQC10_SET_SWITCH_OPT_A 3
+#define DISEQC10_SET_HIGH_LO 4
+#define DISEQC10_SET_HORIZ_POL 5
+#define DISEQC10_SET_SAT_POS_B 6
+
+#define DISEQC10_SET_SWITCH_OPT_B 7
+#define DISEQC11_SET_SWITCH1_INP_A 8
+#define DISEQC11_SET_SWITCH2_INP_A 9
+#define DISEQC11_SET_SWITCH3_INP_A 10
+#define DISEQC11_SET_SWITCH4_INP_A 11
+#define DISEQC11_SET_SWITCH1_INP_B 12
+#define DISEQC11_SET_SWITCH2_INP_B 13
+#define DISEQC11_SET_SWITCH3_INP_B 14
+#define DISEQC11_SET_SWITCH4_INP_B 15
+
+#define DISEQCxx_SET_BUS_SLEEP 16
+#define DISEQCxx_SET_BUS_AWAKE 17
+#define DISEQC11_SET_CHAN_FREQ 18
+#define DISEQC11_SET_RCVR_CHAN 19
+#define DISEQC12_SET_MOTOR_HALT 20
+#define DISEQC12_SET_LIMITS_OFF 21
+#define DISEQC12_SET_LIMITS_ON 22
+#define DISEQC22_GET_MOTOR_STATE 23
+#define DISEQC12_SET_MOTOR_WEST 24
+#define DISEQC12_SET_MOTOR_EAST 25
+#define DISEQC12_SET_WEST_LIMIT 26
+#define DISEQC12_SET_EAST_LIMIT 27
+#define DISEQC12_STEP_MOTOR_UP 28 //???????
+#define DISEQC12_STEP_MOTOR_DOWN 29
+
+struct diseqc_cmd {
+ uint8_t message[6];
+ uint8_t length;
+};
+
+struct cmd_types {
+ uint8_t command[7];
+ char *cmd_descr;
+};
+
+typedef enum dvbfe_sec_voltage {
+ DVBFE_SEC_VOLTAGE_13,
+ DVBFE_SEC_VOLTAGE_18,
+ DVBFE_SEC_VOLTAGE_OFF
+} dvbfe_sec_voltage_t;
+
+typedef enum dvbfe_sec_tone_mode {
+ DVBFE_SEC_TONE_ON,
+ DVBFE_SEC_TONE_OFF
+} dvbfe_sec_tone_mode_t;
+
+typedef enum dvbfe_sec_mini_cmd {
+ DVBFE_SEC_MINI_A,
+ DVBFE_SEC_MINI_B
+} dvbfe_sec_mini_cmd_t;
+
+
+struct cmd_types msgtbl[] = {
+
+ { { 0x03, 0xe0, 0x00, 0x20, 0x00, 0x00, 0x00 }, "DISEQC_SET_LOW_LO" },
+ { { 0x03, 0xe0, 0x00, 0x21, 0x00, 0x00, 0x00 }, "DISEQC10_SET_VERT_POL" },
+ { { 0x03, 0xe0, 0x00, 0x22, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SAT_POS_A" },
+ { { 0x03, 0xe0, 0x00, 0x23, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SWITCH_OPT_A" },
+ { { 0x03, 0xe0, 0x00, 0x24, 0x00, 0x00, 0x00 }, "DISEQC10_SET_HIGH_LO" },
+ { { 0x03, 0xe0, 0x00, 0x25, 0x00, 0x00, 0x00 }, "DISEQC10_SET_HORIZ_POL" },
+ { { 0x03, 0xe0, 0x00, 0x26, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SAT_POS_B" },
+
+ { { 0x03, 0xe0, 0x00, 0x27, 0x00, 0x00, 0x00 }, "DISEQC10_SET_SWITCH_OPT_B" },
+ { { 0x03, 0xe0, 0x00, 0x28, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH1_INP_A" },
+ { { 0x03, 0xe0, 0x00, 0x29, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH2_INP_A" },
+ { { 0x03, 0xe0, 0x00, 0x2a, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH3_INP_A" },
+ { { 0x03, 0xe0, 0x00, 0x2b, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH4_INP_A" },
+ { { 0x03, 0xe0, 0x00, 0x2c, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH1_INP_B" },
+ { { 0x03, 0xe0, 0x00, 0x2d, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH2_INP_B" },
+ { { 0x03, 0xe0, 0x00, 0x2e, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH3_INP_B" },
+ { { 0x03, 0xe0, 0x00, 0x2f, 0x00, 0x00, 0x00 }, "DISEQC11_SET_SWITCH4_INP_B" },
+
+ { { 0x03, 0xe0, 0x00, 0x30, 0x00, 0x00, 0x00 }, "DISEQCxx_SET_BUS_SLEEP" },
+ { { 0x03, 0xe0, 0x00, 0x31, 0x00, 0x00, 0x00 }, "DISEQCxx_SET_BUS_AWAKE" },
+ { { 0x06, 0x0e, 0x00, 0x05, 0x80, 0x00, 0x00 }, "DISEQC11_SET_CHAN_FREQ" },
+ { { 0x05, 0xe0, 0x00, 0x59, 0x00, 0x00, 0x00 }, "DISEQC11_SET_RCVR_CHAN" },
+
+ { { 0x03, 0xe0, 0x00, 0x60, 0x00, 0x00, 0x00 }, "DISEQC12_SET_MOTOR_HALT" },
+ { { 0x03, 0xe0, 0x00, 0x63, 0x00, 0x00, 0x00 }, "DISEQC12_SET_LIMITS_OFF" },
+ { { 0x04, 0xe0, 0x00, 0x6a, 0x00, 0x00, 0x00 }, "DISEQC12_SET_LIMITS_ON" },
+ { { 0x03, 0xe0, 0x00, 0x64, 0x00, 0x00, 0x00 }, "DISEQC22_GET_MOTOR_STATE" } ,
+ { { 0x04, 0xe1, 0x00, 0x69, 0x00, 0x00, 0x00 }, "DISEQC12_SET_MOTOR_WEST" },
+ { { 0x04, 0xe1, 0x00, 0x68, 0x00, 0x00, 0x00 }, "DISEQC12_SET_MOTOR_EAST" },
+ { { 0x03, 0xe1, 0x00, 0x67, 0x00, 0x00, 0x00 }, "DISEQC12_SET_WEST_LIMIT" },
+ { { 0x03, 0xe1, 0x00, 0x66, 0x00, 0x00, 0x00 }, "DISEQC12_SET_EAST_LIMIT" },
+ { { 0x04, 0xe2, 0x00, 0x68, 0x00, 0x00, 0x00 }, "DISEQC12_STEP_MOTOR_UP" },
+ { { 0x04, 0xe2, 0x00, 0x69, 0x00, 0x00, 0x00 }, "DISEQC12_STEP_MOTOR_DOWN"},
+
+ { {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
+};
+
+
+/*
+ * Tone/Data Burst control
+ * @param fd, FD opened with libdvbfe_open().
+ * @param tone, SEC_TONE_ON/SEC_TONE_OFF
+ */
+extern int set_22k_tone(int fd, dvbfe_sec_tone_mode_t tone);
+
+/*
+ * 22khz Tone control
+ * @param fd, FD opened with libdvbfe_open().
+ * @param adapter, minicmd, SEC_MINI_A/SEC_MINI_B
+ */
+extern int set_tone_data_burst(int fd, dvbfe_sec_mini_cmd_t minicmd);
+
+/*
+ * H/V polarization control
+ * @param fd, FD opened with libdvbfe_open().
+ * @param polarization, SEC_VOLTAGE_13/SEC_VOLTAGE_18/SEC_VOLTAGE_OFF
+ */
+extern int set_polarization(int fd, dvbfe_sec_voltage_t polarization);
+
+/*
+ * Send a DiSEqC Command
+ * @param fd, FD opened with libdvbfe_open().
+ * @param cmd, the defined diseqc commands
+ * @param address, the address of the DiSEqC device to be controlled
+ * @param data, a pointer to am array containing the data to be sent
+ * max. length of data, that can be sent is 3 bytes
+ */
+extern int do_diseqc_command(int fd, uint8_t cmd, uint8_t address, uint8_t *data);
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.c
new file mode 100644
index 0000000..8261cd2
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.c
@@ -0,0 +1,159 @@
+/*
+ * libdvbca - interface onto raw CA devices
+ *
+ * Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <linux/dvb/ca.h>
+#include "dvbca.h"
+
+
+int dvbca_open(int adapter, int cadevice)
+{
+ char filename[PATH_MAX+1];
+ int fd;
+
+ sprintf(filename, "/dev/dvb/adapter%i/ca%i", adapter, cadevice);
+ if ((fd = open(filename, O_RDWR)) < 0) {
+ // if that failed, try a flat /dev structure
+ sprintf(filename, "/dev/dvb%i.ca%i", adapter, cadevice);
+ fd = open(filename, O_RDWR);
+ }
+
+ return fd;
+}
+
+int dvbca_reset(int fd, uint8_t slot)
+{
+ return ioctl(fd, CA_RESET, (1 << slot));
+}
+
+int dvbca_get_interface_type(int fd, uint8_t slot)
+{
+ ca_slot_info_t info;
+
+ info.num = slot;
+ if (ioctl(fd, CA_GET_SLOT_INFO, &info))
+ return -1;
+
+ if (info.type & CA_CI_LINK)
+ return DVBCA_INTERFACE_LINK;
+ if (info.type & CA_CI)
+ return DVBCA_INTERFACE_HLCI;
+
+ return -1;
+}
+
+int dvbca_get_cam_state(int fd, uint8_t slot)
+{
+ ca_slot_info_t info;
+
+ info.num = slot;
+ if (ioctl(fd, CA_GET_SLOT_INFO, &info))
+ return -1;
+
+ if (info.flags == 0)
+ return DVBCA_CAMSTATE_MISSING;
+ if (info.flags & CA_CI_MODULE_READY)
+ return DVBCA_CAMSTATE_READY;
+ if (info.flags & CA_CI_MODULE_PRESENT)
+ return DVBCA_CAMSTATE_INITIALISING;
+
+ return -1;
+}
+
+int dvbca_link_write(int fd, uint8_t slot, uint8_t connection_id,
+ uint8_t *data, uint16_t data_length)
+{
+ uint8_t *buf = malloc(data_length + 2);
+ if (buf == NULL)
+ return -1;
+
+ buf[0] = slot;
+ buf[1] = connection_id;
+ memcpy(buf+2, data, data_length);
+
+ int result = write(fd, buf, data_length+2);
+ free(buf);
+ return result;
+}
+
+int dvbca_link_read(int fd, uint8_t *slot, uint8_t *connection_id,
+ uint8_t *data, uint16_t data_length)
+{
+ int size;
+
+ uint8_t *buf = malloc(data_length + 2);
+ if (buf == NULL)
+ return -1;
+
+ if ((size = read(fd, buf, data_length+2)) < 2)
+ return -1;
+
+ *slot = buf[0];
+ *connection_id = buf[1];
+ memcpy(data, buf+2, size-2);
+ free(buf);
+
+ return size - 2;
+}
+
+int dvbca_hlci_write(int fd, uint8_t *data, uint16_t data_length)
+{
+ struct ca_msg msg;
+
+ if (data_length > 256) {
+ return -1;
+ }
+ memset(&msg, 0, sizeof(msg));
+ msg.length = data_length;
+
+ memcpy(msg.msg, data, data_length);
+
+ return ioctl(fd, CA_SEND_MSG, &msg);
+}
+
+int dvbca_hlci_read(int fd, uint32_t app_tag, uint8_t *data,
+ uint16_t data_length)
+{
+ struct ca_msg msg;
+
+ if (data_length > 256) {
+ data_length = 256;
+ }
+ memset(&msg, 0, sizeof(msg));
+ msg.length = data_length;
+ msg.msg[0] = app_tag >> 16;
+ msg.msg[1] = app_tag >> 8;
+ msg.msg[2] = app_tag;
+
+ int status = ioctl(fd, CA_GET_MSG, &msg);
+ if (status < 0) return status;
+
+ if (msg.length > data_length) msg.length = data_length;
+ memcpy(data, msg.msg, msg.length);
+ return msg.length;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.h
new file mode 100644
index 0000000..c65423b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbca.h
@@ -0,0 +1,135 @@
+/*
+ * libdvbca - interface onto raw CA devices
+ *
+ * Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef LIBDVBCA_H
+#define LIBDVBCA_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+/**
+ * The types of CA interface we support.
+ */
+#define DVBCA_INTERFACE_LINK 0
+#define DVBCA_INTERFACE_HLCI 1
+
+/**
+ * States a CAM in a slot can be in.
+ */
+#define DVBCA_CAMSTATE_MISSING 0
+#define DVBCA_CAMSTATE_INITIALISING 1
+#define DVBCA_CAMSTATE_READY 2
+
+
+/**
+ * Open a CA device. Multiple CAMs can be accessed through a CA device.
+ *
+ * @param adapter Index of the DVB adapter.
+ * @param cadevice Index of the CA device on that adapter (usually 0).
+ * @return A unix file descriptor on success, or -1 on failure.
+ */
+extern int dvbca_open(int adapter, int cadevice);
+
+/**
+ * Reset a CAM.
+ *
+ * @param fd File handle opened with dvbca_open.
+ * @param slot Slot where the requested CAM is in.
+ * @return 0 on success, -1 on failure.
+ */
+extern int dvbca_reset(int fd, uint8_t slot);
+
+/**
+ * Get the interface type of a CAM.
+ *
+ * @param fd File handle opened with dvbca_open.
+ * @param slot Slot where the requested CAM is in.
+ * @return One of the DVBCA_INTERFACE_* values, or -1 on failure.
+ */
+extern int dvbca_get_interface_type(int fd, uint8_t slot);
+
+/**
+ * Get the state of a CAM.
+ *
+ * @param fd File handle opened with dvbca_open.
+ * @param slot Slot where the requested CAM is in.
+ * @return One of the DVBCA_CAMSTATE_* values, or -1 on failure.
+ */
+extern int dvbca_get_cam_state(int fd, uint8_t slot);
+
+/**
+ * Write a message to a CAM using a link-layer interface.
+ *
+ * @param fd File handle opened with dvbca_open.
+ * @param slot Slot where the requested CAM is in.
+ * @param connection_id Connection ID of the message.
+ * @param data Data to write.
+ * @param data_length Number of bytes to write.
+ * @return 0 on success, or -1 on failure.
+ */
+extern int dvbca_link_write(int fd, uint8_t slot, uint8_t connection_id,
+ uint8_t *data, uint16_t data_length);
+
+/**
+ * Read a message from a CAM using a link-layer interface.
+ *
+ * @param fd File handle opened with dvbca_open.
+ * @param slot Slot where the responding CAM is in.
+ * @param connection_id Destination for the connection ID the message came from.
+ * @param data Data that was read.
+ * @param data_length Max number of bytes to read.
+ * @return Number of bytes read on success, or -1 on failure.
+ */
+extern int dvbca_link_read(int fd, uint8_t *slot, uint8_t *connection_id,
+ uint8_t *data, uint16_t data_length);
+
+// FIXME how do we determine which CAM slot of a CA is meant?
+/**
+ * Write a message to a CAM using an HLCI interface.
+ *
+ * @param fd File handle opened with dvbca_open.
+ * @param data Data to write.
+ * @param data_length Number of bytes to write.
+ * @return 0 on success, or -1 on failure.
+ */
+extern int dvbca_hlci_write(int fd, uint8_t *data, uint16_t data_length);
+
+// FIXME how do we determine which CAM slot of a CA is meant?
+/**
+ * Read a message from a CAM using an HLCI interface.
+ *
+ * @param fd File handle opened with dvbca_open.
+ * @param app_tag Application layer tag giving the message type to read.
+ * @param data Data that was read.
+ * @param data_length Max number of bytes to read.
+ * @return Number of bytes read on success, or -1 on failure.
+ */
+extern int dvbca_hlci_read(int fd, uint32_t app_tag, uint8_t *data,
+ uint16_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBDVBCA_H
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c
new file mode 100644
index 0000000..aebad34
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.c
@@ -0,0 +1,243 @@
+/*
+ * libdvbdemux - a DVB demux library
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <linux/dvb/dmx.h>
+#include "dvbdemux.h"
+
+
+int dvbdemux_open_demux(int adapter, int demuxdevice, int nonblocking)
+{
+ char filename[PATH_MAX+1];
+ int flags = O_RDWR;
+ int fd;
+
+ if (nonblocking)
+ flags |= O_NONBLOCK;
+
+ sprintf(filename, "/dev/dvb/adapter%i/demux%i", adapter, demuxdevice);
+ if ((fd = open(filename, flags)) < 0) {
+ // if that failed, try a flat /dev structure
+ sprintf(filename, "/dev/dvb%i.demux%i", adapter, demuxdevice);
+ fd = open(filename, flags);
+ }
+
+ return fd;
+}
+
+int dvbdemux_open_dvr(int adapter, int dvrdevice, int readonly, int nonblocking)
+{
+ char filename[PATH_MAX+1];
+ int flags = O_RDWR;
+ int fd;
+
+ if (readonly)
+ flags = O_RDONLY;
+ if (nonblocking)
+ flags |= O_NONBLOCK;
+
+ sprintf(filename, "/dev/dvb/adapter%i/dvr%i", adapter, dvrdevice);
+ if ((fd = open(filename, flags)) < 0) {
+ // if that failed, try a flat /dev structure
+ sprintf(filename, "/dev/dvb%i.dvr%i", adapter, dvrdevice);
+ fd = open(filename, flags);
+ }
+
+ return fd;
+}
+
+int dvbdemux_set_section_filter(int fd, int pid,
+ uint8_t filter[18], uint8_t mask[18],
+ int start, int checkcrc)
+{
+ struct dmx_sct_filter_params sctfilter;
+
+ memset(&sctfilter, 0, sizeof(sctfilter));
+ sctfilter.pid = pid;
+ memcpy(sctfilter.filter.filter, filter, 1);
+ memcpy(sctfilter.filter.filter+1, filter+3, 15);
+ memcpy(sctfilter.filter.mask, mask, 1);
+ memcpy(sctfilter.filter.mask+1, mask+3, 15);
+ memset(sctfilter.filter.mode, 0, 16);
+ if (start)
+ sctfilter.flags |= DMX_IMMEDIATE_START;
+ if (checkcrc)
+ sctfilter.flags |= DMX_CHECK_CRC;
+
+ return ioctl(fd, DMX_SET_FILTER, &sctfilter);
+}
+
+int dvbdemux_set_pes_filter(int fd, int pid,
+ int input, int output,
+ int pestype,
+ int start)
+{
+ struct dmx_pes_filter_params filter;
+
+ memset(&filter, 0, sizeof(filter));
+ filter.pid = pid;
+
+ switch(input) {
+ case DVBDEMUX_INPUT_FRONTEND:
+ filter.input = DMX_IN_FRONTEND;
+ break;
+
+ case DVBDEMUX_INPUT_DVR:
+ filter.input = DMX_IN_DVR;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch(output) {
+ case DVBDEMUX_OUTPUT_DECODER:
+ filter.output = DMX_OUT_DECODER;
+ break;
+
+ case DVBDEMUX_OUTPUT_DEMUX:
+ filter.output = DMX_OUT_TAP;
+ break;
+
+ case DVBDEMUX_OUTPUT_DVR:
+ filter.output = DMX_OUT_TS_TAP;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch(pestype) {
+ case DVBDEMUX_PESTYPE_AUDIO:
+ filter.pes_type = DMX_PES_AUDIO;
+ break;
+
+ case DVBDEMUX_PESTYPE_VIDEO:
+ filter.pes_type = DMX_PES_VIDEO;
+ break;
+
+ case DVBDEMUX_PESTYPE_TELETEXT:
+ filter.pes_type = DMX_PES_TELETEXT;
+ break;
+
+ case DVBDEMUX_PESTYPE_SUBTITLE:
+ filter.pes_type = DMX_PES_SUBTITLE;
+ break;
+
+ case DVBDEMUX_PESTYPE_PCR:
+ filter.pes_type = DMX_PES_PCR;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (start)
+ filter.flags |= DMX_IMMEDIATE_START;
+
+ return ioctl(fd, DMX_SET_PES_FILTER, &filter);
+}
+
+int dvbdemux_set_pid_filter(int fd, int pid,
+ int input, int output,
+ int start)
+{
+ struct dmx_pes_filter_params filter;
+
+ memset(&filter, 0, sizeof(filter));
+ if (pid == -1)
+ filter.pid = 0x2000;
+ else
+ filter.pid = pid;
+
+ switch(input) {
+ case DVBDEMUX_INPUT_FRONTEND:
+ filter.input = DMX_IN_FRONTEND;
+ break;
+
+ case DVBDEMUX_INPUT_DVR:
+ filter.input = DMX_IN_DVR;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch(output) {
+ case DVBDEMUX_OUTPUT_DECODER:
+ filter.output = DMX_OUT_DECODER;
+ break;
+
+ case DVBDEMUX_OUTPUT_DEMUX:
+ filter.output = DMX_OUT_TAP;
+ break;
+
+ case DVBDEMUX_OUTPUT_DVR:
+ filter.output = DMX_OUT_TS_TAP;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ filter.pes_type = DMX_PES_OTHER;
+
+ if (start)
+ filter.flags |= DMX_IMMEDIATE_START;
+
+ return ioctl(fd, DMX_SET_PES_FILTER, &filter);
+}
+
+int dvbdemux_start(int fd)
+{
+ return ioctl(fd, DMX_START);
+}
+
+int dvbdemux_stop(int fd)
+{
+ return ioctl(fd, DMX_STOP);
+}
+
+int dvbdemux_get_stc(int fd, uint64_t *stc)
+{
+ struct dmx_stc _stc;
+ int result;
+
+ memset(stc, 0, sizeof(_stc));
+ if ((result = ioctl(fd, DMX_GET_STC, &_stc)) != 0) {
+ return result;
+ }
+
+ *stc = _stc.stc / _stc.base;
+ return 0;
+}
+
+int dvbdemux_set_buffer(int fd, int bufsize)
+{
+ return ioctl(fd, DMX_SET_BUFFER_SIZE, bufsize);
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h
new file mode 100644
index 0000000..3fe4a4b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbdemux.h
@@ -0,0 +1,202 @@
+/*
+ * libdvbdemux - a DVB demux library
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef LIBDVBDEMUX_H
+#define LIBDVBDEMUX_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+/**
+ * Source of the data to be demuxed.
+ *
+ * FRONTEND. The data will be read from the frontend on the adapter.
+ *
+ * DVR. The data will be read from the DVR device of the adapter (of course,
+ * you need to write data TO the DVR device as well).
+ */
+#define DVBDEMUX_INPUT_FRONTEND 0
+#define DVBDEMUX_INPUT_DVR 1
+
+/**
+ * Destination of the demuxed data.
+ *
+ * DECODER. Sends the data directly to a hardware decoder (if present).
+ *
+ * DEMUX. Sends the PID stream to the current demux file descriptor. HOWEVER, the
+ * data will be the payload *only* - transport stream headers will be stripped.
+ *
+ * DVR sends the data to the DVR device. The data will be the complete transport
+ * stream packets with headers intact. Note: if multiple filters specify
+ * DVBDEMUX_OUTPUT_DVR, the individual PID streams will be re-multiplexed
+ * together.
+ */
+#define DVBDEMUX_OUTPUT_DECODER 0
+#define DVBDEMUX_OUTPUT_DEMUX 1
+#define DVBDEMUX_OUTPUT_DVR 2
+
+/**
+ * PES types.
+ */
+#define DVBDEMUX_PESTYPE_AUDIO 0
+#define DVBDEMUX_PESTYPE_VIDEO 1
+#define DVBDEMUX_PESTYPE_TELETEXT 2
+#define DVBDEMUX_PESTYPE_SUBTITLE 3
+#define DVBDEMUX_PESTYPE_PCR 4
+
+/**
+ * Open a demux device. Can be called multiple times. These let you setup a
+ * single filter per FD. It can can also be read() from if you use a section
+ * filter, or create a pes_filter or raw_filter with output DVBDEMUX_OUTPUT_DEMUX.
+ *
+ * @param adapter Index of the DVB adapter.
+ * @param demuxdevice Index of the demux device on that adapter (usually 0).
+ * @param nonblocking If 1, frontend will be opened in nonblocking mode.
+ * @return A unix file descriptor on success, or -1 on failure.
+ */
+extern int dvbdemux_open_demux(int adapter, int demuxdevice, int nonblocking);
+
+/**
+ * Open a DVR device. May be opened for writing once, or multiple times in readonly
+ * mode. It is used to either write() transport stream data to be demuxed
+ * (if input == DVBDEMUX_INPUT_DVR), or to read() a stream of demuxed data
+ * (if output == DVBDEMUX_OUTPUT_DVR).
+ *
+ * Note, all demux filters with output set to DVBDEMUX_OUTPUT_DVR will be
+ * multiplexed together and output their data on this device.
+ *
+ * @param adapter Index of the DVB adapter.
+ * @param dvrdevice Index of the dvr device on that adapter (usually 0)
+ * @param readonly If 1, frontend will be opened in readonly mode only.
+ * @param nonblocking If 1, frontend will be opened in nonblocking mode.
+ * @return A unix file descriptor on success, or -1 on failure.
+ */
+extern int dvbdemux_open_dvr(int adapter, int dvrdevice, int readonly, int nonblocking);
+
+/**
+ * Set filter for the first 18 bytes of decoded SI table sections. Note that
+ * bytes 1 and 2 are _not_ filtered since they contain the length field.
+ *
+ * Conceptually, the driver computes the following for each filtered bit.
+ *
+ * (filter[X].bit[Y] & mask[X].bit[Y]) == (header[X].bit[Y] & mask[X].bit[Y])
+ *
+ * Any sections which do not match this criteria for every bit will be discarded.
+ *
+ * The SI data is always read from the frontend, and is always returned by
+ * read()ing the demux fd. FIXME: check this statement!
+ *
+ * @param fd FD as opened with dvbdemux_open_demux() above.
+ * @param pid PID of the stream.
+ * @param filter The filter values of the first 18 bytes of the desired sections.
+ * @param mask Bitmask indicating which bits in the filter array should be tested
+ * (if a bit is 1, it will be tested).
+ * @param start If 1, the filter will be started immediately. Otherwise you must
+ * call dvbdemux_start() manually.
+ * @param checkcrc If 1, the driver will check the CRC on the table sections.
+ * Any bad sections will be dropped.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbdemux_set_section_filter(int fd, int pid,
+ uint8_t filter[18], uint8_t mask[18],
+ int start, int checkcrc);
+
+/**
+ * Set filter for a stream of PES data. This call can only used for cards
+ * equipped with a hardware decoder.
+ *
+ * @param fd FD as opened with dvbdemux_open_demux() above.
+ * @param pid PID of the stream.
+ * @param input One of DVBDEMUX_INPUT_*.
+ * @param output One of DVBDEMUX_OUTPUT_*.
+ * @param pestype One of DVBDEMUX_PESTYPE_* - this tells the decoder the type
+ * of data in this stream.
+ * @param start If 1, the filter will be started immediately. Otherwise you must
+ * call dvbdemux_start() manually.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbdemux_set_pes_filter(int fd, int pid,
+ int input, int output,
+ int pestype,
+ int start);
+
+/**
+ * Create a pid filter - this will extract transport stream packets for a
+ * specified PID.
+ *
+ * Note: The wildcard PID can only be used on "budget" cards.
+ *
+ * @param fd FD as opened with dvbdemux_open_demux() above.
+ * @param pid PID to retrieve, or use -1 as a wildcard for ALL PIDs.
+ * @param input One of DVBDEMUX_INPUT_*.
+ * @param output One of DVBDEMUX_OUTPUT_*.
+ * @param start If 1, the filter will be started immediately. Otherwise you must
+ * call dvbdemux_start() manually.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbdemux_set_pid_filter(int fd, int pid,
+ int input, int output,
+ int start);
+
+/**
+ * Start a demux going.
+ *
+ * @param fd FD as opened with dvbdemux_open_demux() above.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbdemux_start(int fd);
+
+/**
+ * Stop a demux.
+ *
+ * @param fd FD as opened with dvbdemux_open_demux() above.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbdemux_stop(int fd);
+
+/**
+ * Retrieve the current STC from the demux. This call can only used for cards
+ * equipped with a hardware decoder.
+ *
+ * @param fd FD as opened with dvbdemux_open_demux() above.
+ * @param stc Where to put the retrieved STC value (in 90kHz clock).
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbdemux_get_stc(int fd, uint64_t *stc);
+
+/**
+ * Change the internal buffer size used by the demuxer. The default buffer size
+ * is 8192 bytes. Can only be used if the demux in question is stopped.
+ *
+ * @param fd FD as opened with dvbdemux_open_demux() above.
+ * @param bufsize New buffer size to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbdemux_set_buffer(int fd, int bufsize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBDVBDEMUX_H
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c
new file mode 100644
index 0000000..fc6ecf4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c
@@ -0,0 +1,760 @@
+/*
+ * libdvbfe - a DVB frontend library
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <linux/dvb/frontend.h>
+#include "dvbfe.h"
+
+#define GET_INFO_MIN_DELAY_US 100000
+
+static int dvbfe_spectral_inversion_to_kapi[][2] =
+{
+ { DVBFE_INVERSION_OFF, INVERSION_OFF },
+ { DVBFE_INVERSION_ON, INVERSION_ON },
+ { DVBFE_INVERSION_AUTO, INVERSION_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_code_rate_to_kapi[][2] =
+{
+ { DVBFE_FEC_NONE, FEC_NONE },
+ { DVBFE_FEC_1_2, FEC_1_2 },
+ { DVBFE_FEC_2_3, FEC_2_3 },
+ { DVBFE_FEC_3_4, FEC_3_4 },
+ { DVBFE_FEC_4_5, FEC_4_5 },
+ { DVBFE_FEC_5_6, FEC_5_6 },
+ { DVBFE_FEC_6_7, FEC_6_7 },
+ { DVBFE_FEC_7_8, FEC_7_8 },
+ { DVBFE_FEC_8_9, FEC_8_9 },
+ { DVBFE_FEC_AUTO, FEC_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_const_to_kapi[][2] =
+{
+ { DVBFE_DVBT_CONST_QPSK, FE_QPSK },
+ { DVBFE_DVBT_CONST_QAM_16, QAM_16 },
+ { DVBFE_DVBT_CONST_QAM_32, QAM_32 },
+ { DVBFE_DVBT_CONST_QAM_64, QAM_64 },
+ { DVBFE_DVBT_CONST_QAM_128, QAM_128 },
+ { DVBFE_DVBT_CONST_QAM_256, QAM_256 },
+ { DVBFE_DVBT_CONST_AUTO, QAM_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbc_mod_to_kapi[][2] =
+{
+ { DVBFE_DVBC_MOD_QAM_16, QAM_16 },
+ { DVBFE_DVBC_MOD_QAM_32, QAM_32 },
+ { DVBFE_DVBC_MOD_QAM_64, QAM_64 },
+ { DVBFE_DVBC_MOD_QAM_128, QAM_128 },
+ { DVBFE_DVBC_MOD_QAM_256, QAM_256 },
+ { DVBFE_DVBC_MOD_AUTO, QAM_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_atsc_mod_to_kapi[][2] =
+{
+ { DVBFE_ATSC_MOD_QAM_64, QAM_64 },
+ { DVBFE_ATSC_MOD_QAM_256, QAM_256 },
+ { DVBFE_ATSC_MOD_VSB_8, VSB_8 },
+ { DVBFE_ATSC_MOD_VSB_16, VSB_16 },
+ { DVBFE_ATSC_MOD_AUTO, QAM_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_transmit_mode_to_kapi[][2] =
+{
+ { DVBFE_DVBT_TRANSMISSION_MODE_2K, TRANSMISSION_MODE_2K },
+ { DVBFE_DVBT_TRANSMISSION_MODE_8K, TRANSMISSION_MODE_8K },
+ { DVBFE_DVBT_TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_bandwidth_to_kapi[][2] =
+{
+ { DVBFE_DVBT_BANDWIDTH_8_MHZ, BANDWIDTH_8_MHZ },
+ { DVBFE_DVBT_BANDWIDTH_7_MHZ, BANDWIDTH_7_MHZ },
+ { DVBFE_DVBT_BANDWIDTH_6_MHZ, BANDWIDTH_6_MHZ },
+ { DVBFE_DVBT_BANDWIDTH_AUTO, BANDWIDTH_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_guard_interval_to_kapi[][2] =
+{
+ { DVBFE_DVBT_GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_32},
+ { DVBFE_DVBT_GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_16},
+ { DVBFE_DVBT_GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_8},
+ { DVBFE_DVBT_GUARD_INTERVAL_1_4, GUARD_INTERVAL_1_4},
+ { DVBFE_DVBT_GUARD_INTERVAL_AUTO, GUARD_INTERVAL_AUTO},
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_hierarchy_to_kapi[][2] =
+{
+ { DVBFE_DVBT_HIERARCHY_NONE, HIERARCHY_NONE },
+ { DVBFE_DVBT_HIERARCHY_1, HIERARCHY_1 },
+ { DVBFE_DVBT_HIERARCHY_2, HIERARCHY_2 },
+ { DVBFE_DVBT_HIERARCHY_4, HIERARCHY_4 },
+ { DVBFE_DVBT_HIERARCHY_AUTO, HIERARCHY_AUTO },
+ { -1, -1 }
+};
+
+static int lookupval(int val, int reverse, int table[][2])
+{
+ int i =0;
+
+ while(table[i][0] != -1) {
+ if (!reverse) {
+ if (val == table[i][0]) {
+ return table[i][1];
+ }
+ } else {
+ if (val == table[i][1]) {
+ return table[i][0];
+ }
+ }
+ i++;
+ }
+
+ return -1;
+}
+
+
+struct dvbfe_handle_prv {
+ int fd;
+ dvbfe_type_t type;
+ char *name;
+ struct timeval nextinfotime;
+ struct dvbfe_info cachedinfo;
+ int cachedreturnval;
+};
+
+dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly)
+{
+ char filename[PATH_MAX+1];
+ struct dvbfe_handle_prv *fehandle;
+ int fd;
+ struct dvb_frontend_info info;
+
+ // flags
+ int flags = O_RDWR;
+ if (readonly) {
+ flags = O_RDONLY;
+ }
+
+ // open it (try normal /dev structure first)
+ sprintf(filename, "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
+ if ((fd = open(filename, flags)) < 0) {
+ // if that failed, try a flat /dev structure
+ sprintf(filename, "/dev/dvb%i.frontend%i", adapter, frontend);
+ if ((fd = open(filename, flags)) < 0) {
+ return NULL;
+ }
+ }
+
+ // determine fe type
+ if (ioctl(fd, FE_GET_INFO, &info)) {
+ close(fd);
+ return NULL;
+ }
+
+ // setup structure
+ fehandle = (struct dvbfe_handle_prv*) malloc(sizeof(struct dvbfe_handle_prv));
+ memset(fehandle, 0, sizeof(struct dvbfe_handle_prv));
+ fehandle->fd = fd;
+ switch(info.type) {
+ case FE_QPSK:
+ fehandle->type = DVBFE_TYPE_DVBS;
+ break;
+
+ case FE_QAM:
+ fehandle->type = DVBFE_TYPE_DVBC;
+ break;
+
+ case FE_OFDM:
+ fehandle->type = DVBFE_TYPE_DVBT;
+ break;
+
+ case FE_ATSC:
+ fehandle->type = DVBFE_TYPE_ATSC;
+ break;
+ }
+ fehandle->name = strndup(info.name, sizeof(info.name));
+
+ // done
+ return fehandle;
+}
+
+void dvbfe_close(dvbfe_handle_t _fehandle)
+{
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+
+ close(fehandle->fd);
+ free(fehandle->name);
+ free(fehandle);
+}
+
+int dvbfe_get_info(dvbfe_handle_t _fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result)
+{
+ int returnval = 0;
+ fe_status_t status;
+ struct dvb_frontend_parameters kparams;
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+ struct timeval curtime;
+
+ // limit how often this is called to reduce bus traffic
+ gettimeofday(&curtime, NULL);
+ if ((curtime.tv_sec < fehandle->nextinfotime.tv_sec) ||
+ ((curtime.tv_sec == fehandle->nextinfotime.tv_sec) && (curtime.tv_usec < fehandle->nextinfotime.tv_usec))) {
+ memcpy(result, &fehandle->cachedinfo, sizeof(struct dvbfe_info));
+ return fehandle->cachedreturnval;
+ }
+
+ // retrieve the requested values
+ memset(result, 0, sizeof(result));
+ result->type = fehandle->type;
+ result->name = fehandle->name;
+ if (querymask & DVBFE_INFO_LOCKSTATUS) {
+ if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) {
+ returnval |= DVBFE_INFO_LOCKSTATUS;
+ if (status & FE_HAS_SIGNAL)
+ result->signal = 1;
+
+ if (status & FE_HAS_CARRIER)
+ result->carrier = 1;
+
+ if (status & FE_HAS_VITERBI)
+ result->viterbi = 1;
+
+ if (status & FE_HAS_SYNC)
+ result->sync = 1;
+
+ if (status & FE_HAS_LOCK)
+ result->lock = 1;
+ }
+ }
+ if (querymask & DVBFE_INFO_FEPARAMS) {
+ if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kparams)) {
+ returnval |= DVBFE_INFO_FEPARAMS;
+ result->feparams.frequency = kparams.frequency;
+ result->feparams.inversion = lookupval(kparams.inversion, 1, dvbfe_spectral_inversion_to_kapi);
+ switch(fehandle->type) {
+ case FE_QPSK:
+ result->feparams.u.dvbs.symbol_rate = kparams.u.qpsk.symbol_rate;
+ result->feparams.u.dvbs.fec_inner =
+ lookupval(kparams.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi);
+ break;
+
+ case FE_QAM:
+ result->feparams.u.dvbc.symbol_rate = kparams.u.qam.symbol_rate;
+ result->feparams.u.dvbc.fec_inner =
+ lookupval(kparams.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi);
+ result->feparams.u.dvbc.modulation =
+ lookupval(kparams.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi);
+ break;
+
+ case FE_OFDM:
+ result->feparams.u.dvbt.bandwidth =
+ lookupval(kparams.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi);
+ result->feparams.u.dvbt.code_rate_HP =
+ lookupval(kparams.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi);
+ result->feparams.u.dvbt.code_rate_LP =
+ lookupval(kparams.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi);
+ result->feparams.u.dvbt.constellation =
+ lookupval(kparams.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi);
+ result->feparams.u.dvbt.transmission_mode =
+ lookupval(kparams.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi);
+ result->feparams.u.dvbt.guard_interval =
+ lookupval(kparams.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi);
+ result->feparams.u.dvbt.hierarchy_information =
+ lookupval(kparams.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi);
+ break;
+
+ case FE_ATSC:
+ result->feparams.u.atsc.modulation =
+ lookupval(kparams.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi);
+ break;
+ }
+ }
+
+ }
+ if (querymask & DVBFE_INFO_BER) {
+ if (!ioctl(fehandle->fd, FE_READ_BER, &result->ber))
+ returnval |= DVBFE_INFO_BER;
+ }
+ if (querymask & DVBFE_INFO_SIGNAL_STRENGTH) {
+ if (!ioctl(fehandle->fd, FE_READ_SIGNAL_STRENGTH, &result->signal_strength))
+ returnval |= DVBFE_INFO_SIGNAL_STRENGTH;
+ }
+ if (querymask & DVBFE_INFO_SNR) {
+ if (!ioctl(fehandle->fd, FE_READ_SNR, &result->snr))
+ returnval |= DVBFE_INFO_SNR;
+ }
+ if (querymask & DVBFE_INFO_UNCORRECTED_BLOCKS) {
+ if (!ioctl(fehandle->fd, FE_READ_UNCORRECTED_BLOCKS, &result->ucblocks))
+ returnval |= DVBFE_INFO_UNCORRECTED_BLOCKS;
+ }
+
+ // setup for next poll
+ gettimeofday(&fehandle->nextinfotime, NULL);
+ fehandle->nextinfotime.tv_usec += GET_INFO_MIN_DELAY_US;
+ if (fehandle->nextinfotime.tv_usec >= 1000000) {
+ fehandle->nextinfotime.tv_usec -= 1000000;
+ fehandle->nextinfotime.tv_sec++;
+ }
+ memcpy(&fehandle->cachedinfo, result, sizeof(struct dvbfe_info));
+ fehandle->cachedreturnval = returnval;
+
+ // done
+ return returnval;
+}
+
+int dvbfe_set(dvbfe_handle_t _fehandle, struct dvbfe_parameters *params, int timeout)
+{
+ struct dvb_frontend_parameters kparams;
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+ int res;
+ struct timeval endtime;
+ fe_status_t status;
+
+ kparams.frequency = params->frequency;
+ kparams.inversion = lookupval(params->inversion, 0, dvbfe_spectral_inversion_to_kapi);
+ switch(fehandle->type) {
+ case FE_QPSK:
+ kparams.u.qpsk.symbol_rate = params->u.dvbs.symbol_rate;
+ kparams.u.qpsk.fec_inner = lookupval(params->u.dvbs.fec_inner, 0, dvbfe_code_rate_to_kapi);
+ break;
+
+ case FE_QAM:
+ kparams.u.qam.symbol_rate = params->u.dvbc.symbol_rate;
+ kparams.u.qam.fec_inner = lookupval(params->u.dvbc.fec_inner, 0, dvbfe_code_rate_to_kapi);
+ kparams.u.qam.modulation = lookupval(params->u.dvbc.modulation, 0, dvbfe_dvbc_mod_to_kapi);
+ break;
+
+ case FE_OFDM:
+ kparams.u.ofdm.bandwidth = lookupval(params->u.dvbt.bandwidth, 0, dvbfe_dvbt_bandwidth_to_kapi);
+ kparams.u.ofdm.code_rate_HP = lookupval(params->u.dvbt.code_rate_HP, 0, dvbfe_code_rate_to_kapi);
+ kparams.u.ofdm.code_rate_LP = lookupval(params->u.dvbt.code_rate_LP, 0, dvbfe_code_rate_to_kapi);
+ kparams.u.ofdm.constellation = lookupval(params->u.dvbt.constellation, 0, dvbfe_dvbt_const_to_kapi);
+ kparams.u.ofdm.transmission_mode =
+ lookupval(params->u.dvbt.transmission_mode, 0, dvbfe_dvbt_transmit_mode_to_kapi);
+ kparams.u.ofdm.guard_interval =
+ lookupval(params->u.dvbt.guard_interval, 0, dvbfe_dvbt_guard_interval_to_kapi);
+ kparams.u.ofdm.hierarchy_information =
+ lookupval(params->u.dvbt.hierarchy_information, 0, dvbfe_dvbt_hierarchy_to_kapi);
+ break;
+
+ case FE_ATSC:
+ kparams.u.vsb.modulation = lookupval(params->u.atsc.modulation, 0, dvbfe_atsc_mod_to_kapi);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set it and check for error
+ res = ioctl(fehandle->fd, FE_SET_FRONTEND, &kparams);
+ if (res)
+ return res;
+
+ // 0 => return immediately
+ if (timeout == 0) {
+ return 0;
+ }
+
+ /* calculate timeout */
+ if (timeout > 0) {
+ gettimeofday(&endtime, NULL);
+ timeout *= 1000;
+ endtime.tv_sec += timeout / 1000000;
+ endtime.tv_usec += timeout % 1000000;
+ }
+
+ /* wait for a lock */
+ while(1) {
+ /* has it locked? */
+ if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) {
+ if (status & FE_HAS_LOCK) {
+ break;
+ }
+ }
+
+ /* check for timeout */
+ if (timeout > 0) {
+ struct timeval curtime;
+ gettimeofday(&curtime, NULL);
+ if ((curtime.tv_sec > endtime.tv_sec) ||
+ ((curtime.tv_sec == endtime.tv_sec) && (curtime.tv_usec >= endtime.tv_usec))) {
+ break;
+ }
+ }
+
+ /* delay for a bit */
+ usleep(100000);
+ }
+
+ /* exit */
+ if (status & FE_HAS_LOCK)
+ return 0;
+ return -ETIMEDOUT;
+}
+
+void dvbfe_poll(dvbfe_handle_t fehandle)
+{
+ // no implementation required yet
+}
+
+
+
+
+
+
+
+int dvbfe_diseqc_command(dvbfe_handle_t _fehandle, char *command)
+{
+ int i = 0;
+ int waittime;
+ int status;
+ struct dvb_diseqc_master_cmd master_cmd;
+ unsigned int tmpcmd[6];
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+ char value_s[20];
+ int value_i;
+ int addr;
+
+ while(command[i]) {
+ /* kill whitespace */
+ if (isspace(command[i])) {
+ i++;
+ continue;
+ }
+
+ switch(command[i]) {
+ case 't':
+ if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF)) != 0)
+ return status;
+ break;
+
+ case 'T':
+ if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON)) != 0)
+ return status;
+ break;
+
+ case '_':
+ if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF)) != 0)
+ return status;
+ break;
+
+ case 'v':
+ if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13)) != 0)
+ return status;
+ break;
+
+ case 'V':
+ if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18)) != 0)
+ return status;
+ break;
+
+ case 'A':
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A)) != 0)
+ return status;
+ break;
+
+ case 'B':
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B)) != 0)
+ return status;
+ break;
+
+ case '+':
+ ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1);
+ /* don't care if this one is not supported */
+ break;
+
+ case '-':
+ ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0);
+ /* don't care if this one is not supported */
+ break;
+
+ case 'W':
+ waittime = atoi(command + i + 1);
+ if (waittime == 0) {
+ return -EINVAL;
+ }
+ usleep(waittime * 1000);
+ while(command[i] && !isspace(command[i]))
+ i++;
+ break;
+
+ case '.': // extended command
+ {
+ i++;
+
+ if (!strncmp(command+i, "D(", 2)) {
+ i += 2;
+
+ master_cmd.msg_len =
+ sscanf(command+i, "%x %x %x %x %x %x",
+ tmpcmd, tmpcmd+1, tmpcmd+2, tmpcmd+3, tmpcmd+4, tmpcmd+5);
+ if (master_cmd.msg_len == 0)
+ return -EINVAL;
+ master_cmd.msg[0] = tmpcmd[0];
+ master_cmd.msg[1] = tmpcmd[1];
+ master_cmd.msg[2] = tmpcmd[2];
+ master_cmd.msg[3] = tmpcmd[3];
+ master_cmd.msg[4] = tmpcmd[4];
+ master_cmd.msg[5] = tmpcmd[5];
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+ } else if (!strncmp(command+i, "Dband(", 6)) {
+ if (sscanf(command+i+6, "%i %2s", &addr, value_s) != 2)
+ return -EINVAL;
+ if (!strncmp(value_s, "lo", 2)) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x20;
+ master_cmd.msg_len = 3;
+ } else if (!strncmp(value_s, "hi", 2)) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x24;
+ master_cmd.msg_len = 3;
+ } else {
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if ((!strncmp(command+i, "Dpolarisation(", 14) ||
+ (!strncmp(command+i, "Dpolarization(", 14)))) {
+ if (sscanf(command+i+14, "%i %1s", &addr, value_s) != 2)
+ return -EINVAL;
+ switch(*value_s) {
+ case 'H':
+ case 'L':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x25;
+ master_cmd.msg_len = 3;
+ break;
+
+ case 'V':
+ case 'R':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x21;
+ master_cmd.msg_len = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dsatellite_position(", 20)) {
+ if (sscanf(command+i+20, "%i %1s", &addr, value_s) != 2)
+ return -EINVAL;
+ switch(*value_s) {
+ case 'A':
+ case 'C':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x22;
+ master_cmd.msg_len = 3;
+ break;
+
+ case 'B':
+ case 'D':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x26;
+ master_cmd.msg_len = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dswitch_option(", 15)) {
+ if (sscanf(command+i+15, "%i %1s", &addr, value_s) != 2)
+ return -EINVAL;
+ switch(*value_s) {
+ case 'A':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x23;
+ master_cmd.msg_len = 3;
+ break;
+
+ case 'B':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x27;
+ master_cmd.msg_len = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dport_pins(", 11)) {
+ int mask;
+ if (sscanf(command+i+11, "%i %i %i", &addr, &mask, &value_i) != 3)
+ return -EINVAL;
+
+ if (mask & 0x0f) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x38;
+ master_cmd.msg[3] = ((mask & 0x0f) << 4) | (value_i & 0x0f);
+ master_cmd.msg_len = 4;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+ }
+ if (mask & 0xf0) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x39;
+ master_cmd.msg[3] = (mask & 0xf0) | ((value_i & 0xf0) >> 4);
+ master_cmd.msg_len = 4;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+ }
+
+ } else if (!strncmp(command+i, "Dgoto_preset(", 13)) {
+ if (sscanf(command+i+13, "%i %i", &addr, &value_i) != 2)
+ return -EINVAL;
+
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x3b;
+ master_cmd.msg[3] = value_i;
+ master_cmd.msg_len = 4;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dgoto_angle(", 12)) {
+ int integer = 0;
+ int fraction = 0;
+ char *tmp;
+
+ if (sscanf(command+i+12, "%i %s", &addr, value_s) != 2)
+ return -EINVAL;
+
+ // parse the integer and fractional parts using fixed point
+ integer = atoi(value_s);
+ tmp = strchr(value_s, '.');
+ if (tmp != NULL) {
+ tmp++;
+ tmp[3] = 0;
+ fraction = ((atoi(tmp) * 16000) / 1000000) & 0xf;
+ }
+
+ // generate the command
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x6e;
+ if (integer < -256) {
+ return -EINVAL;
+ } else if (integer < 0) {
+ integer = -integer;
+ master_cmd.msg[3] = 0xf0;
+ } else if (integer < 256) {
+ master_cmd.msg[3] = 0x00;
+ } else if (integer < 512) {
+ integer -= 256;
+ master_cmd.msg[3] = 0x10;
+ } else {
+ return -EINVAL;
+ }
+ master_cmd.msg[3] |= ((integer / 16) & 0x0f);
+ integer = integer % 16;
+ master_cmd.msg[4] |= ((integer & 0x0f) << 4) | fraction;
+ master_cmd.msg_len = 5;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "dishnetworks(", 13)) {
+ if (sscanf(command+i+13, "%i", tmpcmd) != 1)
+ return -EINVAL;
+
+ if ((status = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, tmpcmd)) != 0)
+ return status;
+ }
+
+ /* skip to the end... */
+ while(command[i] && (command[i] != ')'))
+ i++;
+ break;
+ }
+
+
+ default:
+ return -EINVAL;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+int dvbfe_diseqc_read(dvbfe_handle_t _fehandle, int timeout, unsigned char *buf, unsigned int len)
+{
+ struct dvb_diseqc_slave_reply reply;
+ int result;
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+
+ if (len > 4)
+ len = 4;
+
+ reply.timeout = timeout;
+ reply.msg_len = len;
+
+ if ((result = ioctl(fehandle->fd, FE_DISEQC_RECV_SLAVE_REPLY, reply)) != 0)
+ return result;
+
+ if (reply.msg_len < len)
+ len = reply.msg_len;
+ memcpy(buf, reply.msg, len);
+
+ return len;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h
new file mode 100644
index 0000000..9eb03b7
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.h
@@ -0,0 +1,308 @@
+/*
+ * libdvbfe - a DVB frontend library
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef LIBDVBFE_H
+#define LIBDVBFE_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+/**
+ * The types of frontend we support.
+ */
+typedef enum dvbfe_type {
+ DVBFE_TYPE_DVBS,
+ DVBFE_TYPE_DVBC,
+ DVBFE_TYPE_DVBT,
+ DVBFE_TYPE_ATSC,
+} dvbfe_type_t;
+
+typedef enum dvbfe_polarization {
+ DVBFE_POLARIZATION_H,
+ DVBFE_POLARIZATION_V,
+ DVBFE_POLARIZATION_L,
+ DVBFE_POLARIZATION_R,
+} dvbfe_polarization_t;
+
+typedef enum dvbfe_spectral_inversion {
+ DVBFE_INVERSION_OFF,
+ DVBFE_INVERSION_ON,
+ DVBFE_INVERSION_AUTO
+} dvbfe_spectral_inversion_t;
+
+typedef enum dvbfe_code_rate {
+ DVBFE_FEC_NONE,
+ DVBFE_FEC_1_2,
+ DVBFE_FEC_2_3,
+ DVBFE_FEC_3_4,
+ DVBFE_FEC_4_5,
+ DVBFE_FEC_5_6,
+ DVBFE_FEC_6_7,
+ DVBFE_FEC_7_8,
+ DVBFE_FEC_8_9,
+ DVBFE_FEC_AUTO
+} dvbfe_code_rate_t;
+
+typedef enum dvbfe_dvbt_const {
+ DVBFE_DVBT_CONST_QPSK,
+ DVBFE_DVBT_CONST_QAM_16,
+ DVBFE_DVBT_CONST_QAM_32,
+ DVBFE_DVBT_CONST_QAM_64,
+ DVBFE_DVBT_CONST_QAM_128,
+ DVBFE_DVBT_CONST_QAM_256,
+ DVBFE_DVBT_CONST_AUTO
+} dvbfe_dvbt_const_t;
+
+typedef enum dvbfe_dvbc_mod {
+ DVBFE_DVBC_MOD_QAM_16,
+ DVBFE_DVBC_MOD_QAM_32,
+ DVBFE_DVBC_MOD_QAM_64,
+ DVBFE_DVBC_MOD_QAM_128,
+ DVBFE_DVBC_MOD_QAM_256,
+ DVBFE_DVBC_MOD_AUTO,
+} dvbfe_dvbc_mod_t;
+
+typedef enum dvbfe_atsc_mod {
+ DVBFE_ATSC_MOD_QAM_64,
+ DVBFE_ATSC_MOD_QAM_256,
+ DVBFE_ATSC_MOD_VSB_8,
+ DVBFE_ATSC_MOD_VSB_16,
+ DVBFE_ATSC_MOD_AUTO
+} dvbfe_atsc_mod_t;
+
+typedef enum dvbfe_dvbt_transmit_mode {
+ DVBFE_DVBT_TRANSMISSION_MODE_2K,
+ DVBFE_DVBT_TRANSMISSION_MODE_8K,
+ DVBFE_DVBT_TRANSMISSION_MODE_AUTO
+} dvbfe_dvbt_transmit_mode_t;
+
+typedef enum dvbfe_dvbt_bandwidth {
+ DVBFE_DVBT_BANDWIDTH_8_MHZ,
+ DVBFE_DVBT_BANDWIDTH_7_MHZ,
+ DVBFE_DVBT_BANDWIDTH_6_MHZ,
+ DVBFE_DVBT_BANDWIDTH_AUTO
+} dvbfe_dvbt_bandwidth_t;
+
+typedef enum dvbfe_dvbt_guard_interval {
+ DVBFE_DVBT_GUARD_INTERVAL_1_32,
+ DVBFE_DVBT_GUARD_INTERVAL_1_16,
+ DVBFE_DVBT_GUARD_INTERVAL_1_8,
+ DVBFE_DVBT_GUARD_INTERVAL_1_4,
+ DVBFE_DVBT_GUARD_INTERVAL_AUTO
+} dvbfe_dvbt_guard_interval_t;
+
+typedef enum dvbfe_dvbt_hierarchy {
+ DVBFE_DVBT_HIERARCHY_NONE,
+ DVBFE_DVBT_HIERARCHY_1,
+ DVBFE_DVBT_HIERARCHY_2,
+ DVBFE_DVBT_HIERARCHY_4,
+ DVBFE_DVBT_HIERARCHY_AUTO
+} dvbfe_dvbt_hierarchy_t;
+
+/**
+ * Structure used to store and communicate frontend parameters.
+ */
+struct dvbfe_parameters {
+ uint32_t frequency;
+ dvbfe_spectral_inversion_t inversion;
+ union {
+ struct {
+ uint32_t symbol_rate;
+ dvbfe_code_rate_t fec_inner;
+ dvbfe_polarization_t polarization;
+ } dvbs;
+
+ struct {
+ uint32_t symbol_rate;
+ dvbfe_code_rate_t fec_inner;
+ dvbfe_dvbc_mod_t modulation;
+ } dvbc;
+
+ struct {
+ dvbfe_dvbt_bandwidth_t bandwidth;
+ dvbfe_code_rate_t code_rate_HP;
+ dvbfe_code_rate_t code_rate_LP;
+ dvbfe_dvbt_const_t constellation;
+ dvbfe_dvbt_transmit_mode_t transmission_mode;
+ dvbfe_dvbt_guard_interval_t guard_interval;
+ dvbfe_dvbt_hierarchy_t hierarchy_information;
+ } dvbt;
+
+ struct {
+ dvbfe_atsc_mod_t modulation;
+ } atsc;
+ } u;
+};
+
+/**
+ * Mask of values used in the dvbfe_get_info() call.
+ */
+typedef enum dvbfe_info_mask {
+ DVBFE_INFO_LOCKSTATUS = 0x01,
+ DVBFE_INFO_FEPARAMS = 0x02,
+ DVBFE_INFO_BER = 0x04,
+ DVBFE_INFO_SIGNAL_STRENGTH = 0x08,
+ DVBFE_INFO_SNR = 0x10,
+ DVBFE_INFO_UNCORRECTED_BLOCKS = 0x20,
+} dvbfe_info_mask_t;
+
+/**
+ * Structure containing values used by the dvbfe_get_info() call.
+ */
+struct dvbfe_info {
+ dvbfe_type_t type; /* always retrieved */
+ const char *name; /* always retrieved */
+ unsigned int signal : 1; /* } DVBFE_INFO_LOCKSTATUS */
+ unsigned int carrier : 1; /* } */
+ unsigned int viterbi : 1; /* } */
+ unsigned int sync : 1; /* } */
+ unsigned int lock : 1; /* } */
+ struct dvbfe_parameters feparams; /* DVBFE_INFO_FEPARAMS */
+ uint32_t ber; /* DVBFE_INFO_BER */
+ uint16_t signal_strength; /* DVBFE_INFO_SIGNAL_STRENGTH */
+ uint16_t snr; /* DVBFE_INFO_SNR */
+ uint32_t ucblocks; /* DVBFE_INFO_UNCORRECTED_BLOCKS */
+};
+
+/**
+ * Frontend handle datatype.
+ */
+typedef void *dvbfe_handle_t;
+
+/**
+ * Open a DVB frontend.
+ *
+ * @param adapter DVB adapter ID.
+ * @param frontend Frontend ID of that adapter to open.
+ * @param readonly If 1, frontend will be opened in readonly mode only.
+ * @return A handle on success, or NULL on failure.
+ */
+extern dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly);
+
+/**
+ * Close a DVB frontend.
+ *
+ * @param fehandle Handle opened with dvbfe_open().
+ */
+extern void dvbfe_close(dvbfe_handle_t handle);
+
+/**
+ * Set the frontend tuning parameters.
+ *
+ * @param fehandle Handle opened with dvbfe_open().
+ * @param params Params to set.
+ * @param timeout <0 => wait forever for lock. 0=>return immediately, >0=>
+ * number of milliseconds to wait for a lock.
+ * @return 0 on locked (or if timeout==0 and everything else worked), or
+ * nonzero on failure (including no lock).
+ */
+extern int dvbfe_set(dvbfe_handle_t fehandle, struct dvbfe_parameters *params, int timeout);
+
+/**
+ * Call this function regularly from a loop to maintain the frontend lock.
+ *
+ * @param fehandle Handle opened with dvbfe_open().
+ */
+extern void dvbfe_poll(dvbfe_handle_t fehandle);
+
+/**
+ * Retrieve information about the frontend.
+ *
+ * @param fehandle Handle opened with dvbfe_open().
+ * @param querymask ORed bitmask of desired DVBFE_INFO_* values.
+ * @param result Where to put the retrieved results.
+ * @return ORed bitmask of DVBFE_INFO_* indicating which values were read successfully.
+ */
+extern int dvbfe_get_info(dvbfe_handle_t fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result);
+
+/**
+ * Execute a DISEQC command string.
+ *
+ * A diseqc command consists of a sequence of the following codes, separated by
+ * whitespace:
+ * Simple commands:
+ * t - turn 22kHz tone off.
+ * T - turn 22kHz tone on.
+ * _ - set voltage to 0v (i.e. off).
+ * v - set voltage to 13v.
+ * V - set voltage to 18v.
+ * + - Enable high LNB voltage.
+ * - - Disable high LNB voltage.
+ * A - send DISEQC mini command A.
+ * B - send DISEQC mini command B.
+ * Wii - Delay for ii milliseconds.
+ *
+ * Extended commands:
+ * .dishnetworks(<value>) - Send a dish networks legacy command <value>
+ * .D(<value> ...) - Send a raw diseqc master command. The command may be up
+ * to 6 bytes long.
+ * .Dband(<addr> <lo|hi>) - Set frequency band hi or lo.
+ * .Dpolarisation(<addr> <V|H|L|R>) - Set polarisation.
+ * .Dsatellite_position(<addr> <A|B>) - Set "satellite position" input switch.
+ * .Dswitch_option(<addr> <A|B>) - Set "switch option" input switch.
+ * .Dport_pins(<addr> <mask> <value>) - Set all input switches. Mask and value
+ * are hex-ascii 8 bit bytes. Only bits with a corresponding '1' in mask
+ * will be changed.
+ * .Dgoto_preset(<addr> <index>) - Set a positioner to a preset index (integer)
+ * .Dgoto_angle(<addr> <angle>) - Set a positioner to a given angle
+ * (e.g. 49.6). The angle may range between -180 to 496. It may include a
+ * fractional part.
+ *
+ * All integer values use standard notation - no prefix=>decimal, 0x=>hex etc.
+ *
+ * Set <addr> to 0 if you just have a simple DISEQC setup (e.g. one switch). See
+ * the DISEQC specification at http://www.eutelsat.org/ for full information.
+ *
+ * Comments begin with '#' - any characters after this will be ignored
+ * to the end of the line.
+ *
+ * Examples:
+ * S-19.2E 11700000 V 9750000 t v W15 .D(E0 10 38 F0) W15 A W15 t
+ * S-19.2E 99999999 V 10600000 t v W15 .D(E0 10 38 F1) W15 A W15 T
+ * S-19.2E 11700000 H 9750000 t V W15 .D(E0 10 38 F2) W15 A W15 t
+ * S-19.2E 99999999 H 10600000 t V W15 .D(E0 10 38 F3) W15 A W15 T
+ *
+ * @param fehandle Handle opened with dvbfe_open().
+ * @param command Command to execute.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbfe_diseqc_command(dvbfe_handle_t fehandle, char *command);
+
+/**
+ * Read a DISEQC response from the frontend.
+ *
+ * @param fehandle Handle opened with dvbfe_open().
+ * @param timeout Timeout for DISEQC response.
+ * @param buf Buffer to store response in.
+ * @param len Number of bytes in buffer.
+ * @return >= 0 on success (number of received bytes), <0 on failure.
+ */
+extern int dvbfe_diseqc_read(dvbfe_handle_t fehandle, int timeout, unsigned char *buf, unsigned int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBDVBFE_H
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c
new file mode 100644
index 0000000..d6ee632
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.c
@@ -0,0 +1,99 @@
+/*
+ * libdvbnet - a DVB network support library
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/dvb/net.h>
+#include <errno.h>
+#include "dvbnet.h"
+
+int dvbnet_open(int adapter, int netdeviceid)
+{
+ char filename[PATH_MAX+1];
+ int fd;
+
+ sprintf(filename, "/dev/dvb/adapter%i/net%i", adapter, netdeviceid);
+ if ((fd = open(filename, O_RDWR)) < 0) {
+ // if that failed, try a flat /dev structure
+ sprintf(filename, "/dev/dvb%i.net%i", adapter, netdeviceid);
+ fd = open(filename, O_RDWR);
+ }
+
+ return fd;
+}
+
+int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation)
+{
+ struct dvb_net_if params;
+
+ memset(&params, 0, sizeof(params));
+ params.pid = pid;
+
+ switch(encapsulation) {
+ case DVBNET_ENCAP_MPE:
+ params.feedtype = DVB_NET_FEEDTYPE_MPE;
+ break;
+
+ case DVBNET_ENCAP_ULE:
+ params.feedtype = DVB_NET_FEEDTYPE_ULE;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return ioctl(fd, NET_ADD_IF, &params);
+}
+
+int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation)
+{
+ struct dvb_net_if info;
+ int res;
+
+ memset(&info, 0, sizeof(struct dvb_net_if));
+ info.if_num = ifnum;
+
+ if ((res = ioctl(fd, NET_GET_IF, &info)) < 0)
+ return res;
+
+ *pid = info.pid;
+ switch(info.feedtype) {
+ case DVB_NET_FEEDTYPE_MPE:
+ *encapsulation = DVBNET_ENCAP_MPE;
+ break;
+
+ case DVB_NET_FEEDTYPE_ULE:
+ *encapsulation = DVBNET_ENCAP_ULE;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int dvbnet_remove_interface(int fd, int ifnum)
+{
+ return ioctl(fd, NET_REMOVE_IF, ifnum);
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h
new file mode 100644
index 0000000..426e540
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbnet.h
@@ -0,0 +1,87 @@
+/*
+ * libdvbnet - a DVB network support library
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef LIBDVBNET_H
+#define LIBDVBNET_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+/**
+ * Possible encapsulations of data.
+ */
+typedef enum dvbnet_encap {
+ DVBNET_ENCAP_MPE,
+ DVBNET_ENCAP_ULE,
+} dvbnet_encap_t;
+
+/**
+ * The maximum allowed number of dvb network devices per adapter netdevice.
+ */
+#define DVBNET_MAX_INTERFACES 10
+
+/**
+ * Open a DVB net interface.
+ *
+ * @param adapter DVB adapter ID.
+ * @param netdeviceid Network control interface of that adapter to open.
+ * @return A unix file descriptor on success, or -1 on failure.
+ */
+extern int dvbnet_open(int adapter, int netdeviceid);
+
+/**
+ * Create a new DVBNET interface.
+ *
+ * @param fd FD opened with libdvbnet_open().
+ * @param pid PID of the stream containing the network data.
+ * @param encapsulation Encapsulation type of the stream (one of DVBNET_ENCAP_*).
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation);
+
+/**
+ * Get details of a DVBNET interface.
+ *
+ * @param fd FD opened with libdvbnet_open().
+ * @param ifnum Index of interface to retrieve.
+ * @param pid The PID of the interface.
+ * @param encapsulation The encapsulation of the interface (DVBNET_ENCAP_*).
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation);
+
+/**
+ * Remove a DVBNET interface.
+ *
+ * @param fd FD opened with libdvbnet_open().
+ * @param ifnum Index of interface to remove.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvbnet_remove_interface(int fd, int ifnum);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LIBDVBNET_H
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am b/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am
new file mode 100644
index 0000000..7c9764a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/Makefile.am
@@ -0,0 +1,21 @@
+noinst_LTLIBRARIES = libdvben50221.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib
+
+libdvben50221_la_SOURCES = asn_1.c \
+ en50221_app_ai.c \
+ en50221_app_auth.c \
+ en50221_app_ca.c \
+ en50221_app_datetime.c \
+ en50221_app_dvb.c \
+ en50221_app_epg.c \
+ en50221_app_lowspeed.c \
+ en50221_app_mmi.c \
+ en50221_app_rm.c \
+ en50221_app_smartcard.c \
+ en50221_app_teletext.c \
+ en50221_app_utils.c \
+ en50221_session.c \
+ en50221_transport.c
+
+CFLAGS = -g -O2 -DLOG_LEVEL=1 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c
new file mode 100644
index 0000000..8cc528f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.c
@@ -0,0 +1,81 @@
+/*
+ ASN.1 routines, implementation for libdvben50221
+ an implementation for the High Level Common Interface
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include "asn_1.h"
+
+int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len)
+{
+ uint8_t length_field;
+
+ if (asn_1_array_len < 1)
+ return -1;
+ length_field = asn_1_array[0];
+
+ if (length_field < 0x80) {
+ // there is only one word
+ *length = length_field & 0x7f;
+ return 1;
+ } else if (length_field == 0x81) {
+ if (asn_1_array_len < 2)
+ return -1;
+
+ *length = asn_1_array[1];
+ return 2;
+ } else if (length_field == 0x82) {
+ if (asn_1_array_len < 3)
+ return -1;
+
+ *length = (asn_1_array[1] << 8) | asn_1_array[2];
+ return 3;
+ }
+
+ return -1;
+}
+
+int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len)
+{
+ if (length < 0x80) {
+ if (asn_1_array_len < 1)
+ return -1;
+
+ asn_1_array[0] = length & 0x7f;
+ return 1;
+ } else if (length < 0x100) {
+ if (asn_1_array_len < 2)
+ return -1;
+
+ asn_1_array[0] = 0x81;
+ asn_1_array[1] = length;
+ return 2;
+ } else {
+ if (asn_1_array_len < 3)
+ return -1;
+
+ asn_1_array[0] = 0x82;
+ asn_1_array[1] = length >> 8;
+ asn_1_array[2] = length;
+ return 3;
+ }
+
+ // never reached
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h
new file mode 100644
index 0000000..00d636b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/asn_1.h
@@ -0,0 +1,41 @@
+/*
+ ASN.1 routines, implementation for libdvben50221
+ an implementation for the High Level Common Interface
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __ASN_1_H__
+#define __ASN_1_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+
+int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len);
+int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c
new file mode 100644
index 0000000..6facef0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.c
@@ -0,0 +1,185 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include "en50221_app_ai.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_ai_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_ai_callback callback;
+ void *callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_ai_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_ai_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_ai_destroy(en50221_app_ai ai)
+{
+ struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback callback, void *arg)
+{
+ struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
+
+ pthread_mutex_lock(&private->lock);
+ private->callback = callback;
+ private->callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number)
+{
+ struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
+ uint8_t data[4];
+
+ data[0] = (TAG_APP_INFO_ENQUIRY >> 16) & 0xFF;
+ data[1] = (TAG_APP_INFO_ENQUIRY >> 8) & 0xFF;
+ data[2] = TAG_APP_INFO_ENQUIRY & 0xFF;
+ data[3] = 0;
+
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 4);
+}
+
+int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number)
+{
+ struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
+ uint8_t data[4];
+
+ data[0] = (TAG_ENTER_MENU >> 16) & 0xFF;
+ data[1] = (TAG_ENTER_MENU >> 8) & 0xFF;
+ data[2] = TAG_ENTER_MENU & 0xFF;
+ data[3] = 0;
+
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 4);
+}
+
+int en50221_app_ai_message(en50221_app_ai ai,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_APP_INFO:
+ return en50221_app_ai_parse_app_info(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+
+
+
+
+static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // parse the length field
+ int length_field_len;
+ uint16_t asn_data_length;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length < 6) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length > (data_length - length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t *app_info = data + length_field_len;
+
+ // parse the fields
+ uint8_t application_type = app_info[0];
+ uint16_t application_manufacturer = (app_info[1] << 8) | app_info[2];
+ uint16_t manufacturer_code = (app_info[3] << 8) | app_info[4];
+ uint8_t menu_string_length = app_info[5];
+ uint8_t *menu_string = app_info + 6;
+
+ // check the menu_string_length
+ if (menu_string_length > (asn_data_length-6)) {
+ print(LOG_LEVEL, ERROR, 1, "Received bad menu string length - adjusting\n");
+ menu_string_length = asn_data_length-6;
+ }
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_ai_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, application_type,
+ application_manufacturer, manufacturer_code, menu_string_length, menu_string);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h
new file mode 100644
index 0000000..4def877
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ai.h
@@ -0,0 +1,129 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_AI_H__
+#define __EN50221_APPLICATION_AI_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EN50221_APP_AI_RESOURCEID MKRID(2,1,1)
+
+#define APPLICATION_TYPE_CA 0x01
+#define APPLICATION_TYPE_EPG 0x02
+
+/**
+ * Type definition for application callback function - called when we receive
+ * an application info object.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Resource id concerned.
+ * @param application_type Type of application.
+ * @param application_manufacturer Manufacturer of application.
+ * @param manufacturer_code Manufacturer specific code.
+ * @param menu_string_length Length of menu string.
+ * @param menu_string The menu string itself.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_ai_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t application_type, uint16_t application_manufacturer,
+ uint16_t manufacturer_code, uint8_t menu_string_length,
+ uint8_t *menu_string);
+
+/**
+ * Opaque type representing an application information resource.
+ */
+typedef void *en50221_app_ai;
+
+/**
+ * Create an instance of an application information resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of an application information resource.
+ *
+ * @param ai Instance to destroy.
+ */
+extern void en50221_app_ai_destroy(en50221_app_ai ai);
+
+/**
+ * Register a callback for reception of application_info objects.
+ *
+ * @param ai Application information instance.
+ * @param callback Callback function.
+ * @param arg Private argument passed during calls to the callback.
+ */
+extern void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback, void *arg);
+
+/**
+ * send a enquiry for the app_info provided by a module
+ *
+ * @param ai Application information instance.
+ * @param session_number Session to send on.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number);
+
+/**
+ * send a enter_menu tag, this will make the application
+ * open a new MMI session to provide a Menu, or so.
+ *
+ * @param ai Application information instance.
+ * @param session_number Session to send on.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param ai Application information instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_ai_message(en50221_app_ai ai,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c
new file mode 100644
index 0000000..b062e3e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.c
@@ -0,0 +1,179 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include "en50221_app_auth.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_auth_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_auth_request_callback callback;
+ void *callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_auth_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_auth_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_auth_destroy(en50221_app_auth auth)
+{
+ struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_auth_register_request_callback(en50221_app_auth auth,
+ en50221_app_auth_request_callback callback, void *arg)
+{
+ struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
+
+ pthread_mutex_lock(&private->lock);
+ private->callback = callback;
+ private->callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_auth_send(en50221_app_auth auth,
+ uint16_t session_number,
+ uint16_t auth_protocol_id, uint8_t *auth_data,
+ uint32_t auth_data_length)
+{
+ struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
+ uint8_t buf[10];
+
+ // the header
+ buf[0] = (TAG_AUTH_RESP >> 16) & 0xFF;
+ buf[1] = (TAG_AUTH_RESP >> 8) & 0xFF;
+ buf[2] = TAG_AUTH_RESP & 0xFF;
+
+ // encode the length field
+ int length_field_len;
+ if ((length_field_len = asn_1_encode(auth_data_length+2, buf+3, 3)) < 0) {
+ return -1;
+ }
+
+ // the phase_id
+ buf[3+length_field_len] = auth_protocol_id>>8;
+ buf[3+length_field_len+1] = auth_protocol_id;
+
+ // build the iovecs
+ struct iovec iov[2];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 3+length_field_len+2;
+ iov[1].iov_base = auth_data;
+ iov[1].iov_len = auth_data_length;
+
+ // sendit
+ return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2);
+}
+
+int en50221_app_auth_message(en50221_app_auth auth,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_AUTH_REQ:
+ return en50221_app_auth_parse_request(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length < 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t *auth_data = data + length_field_len;
+
+ // process it
+ uint16_t auth_protocol_id = (auth_data[0]<<8) | auth_data[1];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_auth_request_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, auth_protocol_id, auth_data+2, asn_data_length-2);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h
new file mode 100644
index 0000000..30d9c55
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_auth.h
@@ -0,0 +1,119 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_auth_H__
+#define __EN50221_APPLICATION_auth_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EN50221_APP_AUTH_RESOURCEID MKRID(16,1,1)
+
+/**
+ * Type definition for request - called when we receive a auth request from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param auth_protocol_id Auth protocol id.
+ * @param auth_data Data for the request.
+ * @param auth_data_lenghth Number of bytes.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_auth_request_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint16_t auth_protcol_id, uint8_t *auth_data,
+ uint32_t auth_data_length);
+
+/**
+ * Opaque type representing a auth resource.
+ */
+typedef void *en50221_app_auth;
+
+/**
+ * Create an instance of the auth resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the auth resource.
+ *
+ * @param auth Instance to destroy.
+ */
+extern void en50221_app_auth_destroy(en50221_app_auth auth);
+
+/**
+ * Register the callback for when we receive a request.
+ *
+ * @param auth auth resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_auth_register_request_callback(en50221_app_auth auth,
+ en50221_app_auth_request_callback callback, void *arg);
+
+/**
+ * Send an auth response to the CAM.
+ *
+ * @param auth auth resource instance.
+ * @param session_number Session number to send it on.
+ * @param auth_protocol_id Auth protocol id.
+ * @param auth_data Auth data.
+ * @param auth_data_length Number of bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_auth_send(en50221_app_auth auth,
+ uint16_t session_number,
+ uint16_t auth_protocol_id, uint8_t *auth_data,
+ uint32_t auth_data_length);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param auth Authentication instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_auth_message(en50221_app_auth auth,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c
new file mode 100644
index 0000000..a1206fb
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.c
@@ -0,0 +1,615 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include <libucsi/mpeg/descriptor.h>
+#include "en50221_app_ca.h"
+#include "asn_1.h"
+
+// tags supported by this resource
+#define TAG_CA_INFO_ENQUIRY 0x9f8030
+#define TAG_CA_INFO 0x9f8031
+#define TAG_CA_PMT 0x9f8032
+#define TAG_CA_PMT_REPLY 0x9f8033
+
+struct en50221_app_ca_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_ca_info_callback ca_info_callback;
+ void *ca_info_callback_arg;
+
+ en50221_app_ca_pmt_reply_callback ca_pmt_reply_callback;
+ void *ca_pmt_reply_callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+struct ca_pmt_descriptor {
+ uint8_t *descriptor;
+ uint16_t length;
+
+ struct ca_pmt_descriptor *next;
+};
+
+struct ca_pmt_stream {
+ uint8_t stream_type;
+ uint16_t pid;
+ struct ca_pmt_descriptor *descriptors;
+ uint32_t descriptors_length;
+ uint32_t descriptors_count;
+
+ struct ca_pmt_stream *next;
+};
+
+static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, struct ca_pmt_descriptor **outdescriptors);
+static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, struct ca_pmt_stream **outstreams);
+static void en50221_ca_try_move_pmt_descriptors(struct ca_pmt_descriptor **pmt_descriptors,
+ struct ca_pmt_stream **pmt_streams);
+static uint32_t en50221_ca_calculate_length(struct ca_pmt_descriptor *pmt_descriptors,
+ uint32_t *pmt_descriptors_length,
+ struct ca_pmt_stream *pmt_streams);
+static int en50221_app_ca_parse_info(struct en50221_app_ca_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_ca_parse_reply(struct en50221_app_ca_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+
+en50221_app_ca en50221_app_ca_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_ca_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_ca_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->ca_info_callback = NULL;
+ private->ca_pmt_reply_callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_ca_destroy(en50221_app_ca ca)
+{
+ struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_ca_register_info_callback(en50221_app_ca ca,
+ en50221_app_ca_info_callback callback, void *arg)
+{
+ struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca;
+
+ pthread_mutex_lock(&private->lock);
+ private->ca_info_callback = callback;
+ private->ca_info_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca,
+ en50221_app_ca_pmt_reply_callback callback, void *arg)
+{
+ struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca;
+
+ pthread_mutex_lock(&private->lock);
+ private->ca_pmt_reply_callback = callback;
+ private->ca_pmt_reply_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_ca_info_enq(en50221_app_ca ca,
+ uint16_t session_number)
+{
+ struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca;
+ uint8_t data[4];
+
+ data[0] = (TAG_CA_INFO_ENQUIRY >> 16) & 0xFF;
+ data[1] = (TAG_CA_INFO_ENQUIRY >> 8) & 0xFF;
+ data[2] = TAG_CA_INFO_ENQUIRY & 0xFF;
+ data[3] = 0;
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 4);
+}
+
+int en50221_app_ca_pmt(en50221_app_ca ca,
+ uint16_t session_number,
+ uint8_t *ca_pmt,
+ uint32_t ca_pmt_length)
+{
+ struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca;
+ uint8_t buf[10];
+
+ // set up the tag
+ buf[0] = (TAG_CA_PMT >> 16) & 0xFF;
+ buf[1] = (TAG_CA_PMT >> 8) & 0xFF;
+ buf[2] = TAG_CA_PMT & 0xFF;
+
+ // encode the length field
+ int length_field_len;
+ if ((length_field_len = asn_1_encode(ca_pmt_length, buf+3, 3)) < 0) {
+ return -1;
+ }
+
+ // build the iovecs
+ struct iovec iov[2];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 3+length_field_len;
+ iov[1].iov_base = ca_pmt;
+ iov[1].iov_len = ca_pmt_length;
+
+ // create the data and send it
+ return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2);
+}
+
+int en50221_app_ca_message(en50221_app_ca ca,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_ca_private *private = (struct en50221_app_ca_private *) ca;
+ (void)resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_CA_INFO:
+ return en50221_app_ca_parse_info(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_CA_PMT_REPLY:
+ return en50221_app_ca_parse_reply(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt, uint8_t *data, uint32_t data_length,
+ int move_ca_descriptors,
+ uint8_t ca_pmt_list_management, uint8_t ca_pmt_cmd_id)
+{
+ struct ca_pmt_descriptor *pmt_descriptors = NULL;
+ uint32_t pmt_descriptors_length = 0;
+ struct ca_pmt_stream *pmt_streams = NULL;
+ uint32_t total_required_length = 0;
+ struct ca_pmt_descriptor *cur_d;
+ struct ca_pmt_stream *cur_s;
+ int result = -1;
+
+ // extract the descriptors and streams
+ if (en50221_ca_extract_pmt_descriptors(pmt, &pmt_descriptors))
+ goto cleanup;
+ if (en50221_ca_extract_streams(pmt, &pmt_streams))
+ goto cleanup;
+
+ // try and merge them if we have no PMT descriptors
+ if ((pmt_descriptors == NULL) && move_ca_descriptors) {
+ en50221_ca_try_move_pmt_descriptors(&pmt_descriptors, &pmt_streams);
+ }
+
+ // calculate the length of all descriptors/streams and the total length required
+ total_required_length = en50221_ca_calculate_length(pmt_descriptors, &pmt_descriptors_length, pmt_streams);
+
+ // ensure we were supplied with enough data
+ if (total_required_length > data_length) {
+ goto cleanup;
+ }
+
+ // format the start of the PMT
+ uint32_t data_pos = 0;
+ data[data_pos++] = ca_pmt_list_management;
+ data[data_pos++] = mpeg_pmt_section_program_number(pmt) >> 8;
+ data[data_pos++] = mpeg_pmt_section_program_number(pmt);
+ data[data_pos++] = (pmt->head.version_number << 1) | pmt->head.current_next_indicator;
+ data[data_pos++] = (pmt_descriptors_length >> 8) & 0x0f;
+ data[data_pos++] = pmt_descriptors_length;
+
+ // append the PMT descriptors
+ if (pmt_descriptors_length) {
+ data[data_pos++] = ca_pmt_cmd_id;
+ struct ca_pmt_descriptor *cur_d = pmt_descriptors;
+ while(cur_d) {
+ memcpy(data+data_pos, cur_d->descriptor, cur_d->length);
+ data_pos += cur_d->length;
+ cur_d = cur_d->next;
+ }
+ }
+
+ // now, append the streams
+ cur_s = pmt_streams;
+ while(cur_s) {
+ data[data_pos++] = cur_s->stream_type;
+ data[data_pos++] = (cur_s->pid >> 8) & 0x1f;
+ data[data_pos++] = cur_s->pid;
+ data[data_pos++] = (cur_s->descriptors_length >> 8) & 0x0f;
+ data[data_pos++] = cur_s->descriptors_length;
+
+ // append the stream descriptors
+ if (cur_s->descriptors_length) {
+ data[data_pos++] = ca_pmt_cmd_id;
+ struct ca_pmt_descriptor *cur_d = cur_s->descriptors;
+ while(cur_d) {
+ memcpy(data+data_pos, cur_d->descriptor, cur_d->length);
+ data_pos += cur_d->length;
+ cur_d = cur_d->next;
+ }
+ }
+ cur_s = cur_s->next;
+ }
+ result = data_pos;
+
+
+cleanup:
+ // free the PMT descriptors
+ cur_d = pmt_descriptors;
+ while(cur_d) {
+ struct ca_pmt_descriptor *next = cur_d->next;
+ free(cur_d);
+ cur_d = next;
+ }
+
+ // free the streams
+ cur_s = pmt_streams;
+ while(cur_s) {
+ struct ca_pmt_stream *next_s = cur_s->next;
+
+ // free the stream descriptors
+ cur_d = cur_s->descriptors;
+ while(cur_d) {
+ struct ca_pmt_descriptor *next_d = cur_d->next;
+ free(cur_d);
+ cur_d = next_d;
+ }
+
+ free(cur_s);
+ cur_s = next_s;
+ }
+ return result;
+}
+
+
+
+
+
+
+
+static int en50221_ca_extract_pmt_descriptors(struct mpeg_pmt_section *pmt, struct ca_pmt_descriptor **outdescriptors)
+{
+ struct ca_pmt_descriptor *descriptors = NULL;
+ struct ca_pmt_descriptor *descriptors_tail = NULL;
+ struct ca_pmt_descriptor *cur_d;
+
+ struct descriptor *cur_descriptor;
+ mpeg_pmt_section_descriptors_for_each(pmt, cur_descriptor) {
+ if (cur_descriptor->tag == dtag_mpeg_ca) {
+ // create a new structure for this one
+ struct ca_pmt_descriptor *new_d = malloc(sizeof(struct ca_pmt_descriptor));
+ if (new_d == NULL) {
+ goto error_exit;
+ }
+ new_d->descriptor = (uint8_t*) cur_descriptor;
+ new_d->length = cur_descriptor->len+2;
+ new_d->next = NULL;
+
+ // append it to the list
+ if (descriptors == NULL) {
+ descriptors = new_d;
+ } else {
+ descriptors_tail->next = new_d;
+ }
+ descriptors_tail = new_d;
+ }
+ }
+ *outdescriptors = descriptors;
+ return 0;
+
+error_exit:
+ cur_d = descriptors;
+ while(cur_d) {
+ struct ca_pmt_descriptor *next = cur_d->next;
+ free(cur_d);
+ cur_d = next;
+ }
+ return -1;
+}
+
+static int en50221_ca_extract_streams(struct mpeg_pmt_section *pmt, struct ca_pmt_stream **outstreams)
+{
+ struct ca_pmt_stream *streams = NULL;
+ struct ca_pmt_stream *streams_tail = NULL;
+ struct mpeg_pmt_stream *cur_stream;
+ struct descriptor *cur_descriptor;
+ struct ca_pmt_stream *cur_s;
+
+ mpeg_pmt_section_streams_for_each(pmt, cur_stream) {
+ struct ca_pmt_descriptor *descriptors_tail = NULL;
+
+ // create a new structure
+ struct ca_pmt_stream *new_s = malloc(sizeof(struct ca_pmt_stream));
+ if (new_s == NULL) {
+ goto exit_cleanup;
+ }
+ new_s->stream_type = cur_stream->stream_type;
+ new_s->pid = cur_stream->pid;
+ new_s->descriptors = NULL;
+ new_s->next = NULL;
+ new_s->descriptors_count = 0;
+
+ // append it to the list
+ if (streams == NULL) {
+ streams = new_s;
+ } else {
+ streams_tail->next = new_s;
+ }
+ streams_tail = new_s;
+
+ // now process the descriptors
+ mpeg_pmt_stream_descriptors_for_each(cur_stream, cur_descriptor) {
+ if (cur_descriptor->tag == dtag_mpeg_ca) {
+ // create a new structure
+ struct ca_pmt_descriptor *new_d = malloc(sizeof(struct ca_pmt_descriptor));
+ if (new_d == NULL) {
+ goto exit_cleanup;
+ }
+ new_d->descriptor = (uint8_t*) cur_descriptor;
+ new_d->length = cur_descriptor->len+2;
+ new_d->next = NULL;
+
+ // append it to the list
+ if (new_s->descriptors == NULL) {
+ new_s->descriptors = new_d;
+ } else {
+ descriptors_tail->next = new_d;
+ }
+ descriptors_tail = new_d;
+ new_s->descriptors_count++;
+ }
+ }
+ }
+ *outstreams = streams;
+ return 0;
+
+exit_cleanup:
+ // free the streams
+ cur_s = streams;
+ while(cur_s) {
+ struct ca_pmt_stream *next_s = cur_s->next;
+
+ // free the stream descriptors
+ struct ca_pmt_descriptor *cur_d = cur_s->descriptors;
+ while(cur_d) {
+ struct ca_pmt_descriptor *next_d = cur_d->next;
+ free(cur_d);
+ cur_d = next_d;
+ }
+
+ free(cur_s);
+ cur_s = next_s;
+ }
+ return -1;
+}
+
+static void en50221_ca_try_move_pmt_descriptors(struct ca_pmt_descriptor **pmt_descriptors,
+ struct ca_pmt_stream **pmt_streams)
+{
+ // get the first stream
+ struct ca_pmt_stream *first_stream = *pmt_streams;
+ if (first_stream == NULL)
+ return;
+
+ // Check that all the other streams with CA descriptors have exactly the same CA descriptors
+ struct ca_pmt_stream *cur_stream = first_stream->next;
+ while(cur_stream) {
+ // if there are differing numbers of descriptors, exit right now
+ if (cur_stream->descriptors_count != first_stream->descriptors_count)
+ return;
+
+ // now verify the descriptors match
+ struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors;
+ struct ca_pmt_descriptor *first_cur_descriptor = first_stream->descriptors;
+ while(cur_descriptor) {
+ // check the descriptors are the same length
+ if (cur_descriptor->length != first_cur_descriptor->length)
+ return;
+
+ // check their contents match
+ if (memcmp(cur_descriptor->descriptor, first_cur_descriptor->descriptor, cur_descriptor->length)) {
+ return;
+ }
+
+ // move to next
+ cur_descriptor = cur_descriptor->next;
+ first_cur_descriptor = first_cur_descriptor->next;
+ }
+
+ // move to next
+ cur_stream = cur_stream->next;
+ }
+
+ // if we end up here, all descriptors in all streams matched
+
+ // hook the first stream's descriptors into the PMT's
+ *pmt_descriptors = first_stream->descriptors;
+ first_stream->descriptors = NULL;
+ first_stream->descriptors_count = 0;
+
+ // now free up all the descriptors in the other streams
+ cur_stream = first_stream->next;
+ while(cur_stream) {
+ struct ca_pmt_descriptor *cur_descriptor = cur_stream->descriptors;
+ while(cur_descriptor) {
+ struct ca_pmt_descriptor *next = cur_descriptor->next;
+ free(cur_descriptor);
+ cur_descriptor=next;
+ }
+ cur_stream->descriptors = NULL;
+ cur_stream->descriptors_count = 0;
+ cur_stream = cur_stream->next;
+ }
+}
+
+static uint32_t en50221_ca_calculate_length(struct ca_pmt_descriptor *pmt_descriptors,
+ uint32_t *pmt_descriptors_length,
+ struct ca_pmt_stream *pmt_streams)
+{
+ uint32_t total_required_length = 6; // header
+ struct ca_pmt_stream *cur_s;
+
+ // calcuate the PMT descriptors length
+ (*pmt_descriptors_length) = 0;
+ struct ca_pmt_descriptor *cur_d = pmt_descriptors;
+ while(cur_d) {
+ (*pmt_descriptors_length) += cur_d->length;
+ cur_d = cur_d->next;
+ }
+
+ // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors.
+ if (*pmt_descriptors_length)
+ (*pmt_descriptors_length)++;
+
+ // update the total required length
+ total_required_length += *pmt_descriptors_length;
+
+ // calculate the length of descriptors in the streams
+ cur_s = pmt_streams;
+ while(cur_s) {
+ // calculate the size of descriptors in this stream
+ cur_s->descriptors_length = 0;
+ cur_d = cur_s->descriptors;
+ while(cur_d) {
+ cur_s->descriptors_length += cur_d->length;
+ cur_d = cur_d->next;
+ }
+
+ // add on 1 byte for the ca_pmt_cmd_id if we have some descriptors.
+ if (cur_s->descriptors_length)
+ cur_s->descriptors_length++;
+
+ // update the total required length;
+ total_required_length += 5 + cur_s->descriptors_length;
+
+ cur_s = cur_s->next;
+ }
+
+ // done
+ return total_required_length;
+}
+
+static int en50221_app_ca_parse_info(struct en50221_app_ca_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ data+=length_field_len;
+
+ // parse
+ uint32_t ca_id_count = asn_data_length / 2;
+
+ // byteswap the IDs
+ uint16_t *ids = (uint16_t*) data;
+ uint32_t i;
+ for(i=0; i<ca_id_count; i++) {
+ bswap16(data);
+ data+=2;
+ }
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_ca_info_callback cb = private->ca_info_callback;
+ void *cb_arg = private->ca_info_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, ca_id_count, ids);
+ }
+ return 0;
+}
+
+static int en50221_app_ca_parse_reply(struct en50221_app_ca_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length < 4) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ data += length_field_len;
+ data_length -= length_field_len;
+
+ // process the reply table to fix endian issues
+ uint32_t pos = 4;
+ bswap16(data);
+ while(pos < asn_data_length) {
+ bswap16(data+pos);
+ pos+= 3;
+ }
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_ca_pmt_reply_callback cb = private->ca_pmt_reply_callback;
+ void *cb_arg = private->ca_pmt_reply_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, (struct en50221_app_pmt_reply*) data, asn_data_length);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h
new file mode 100644
index 0000000..ab29649
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_ca.h
@@ -0,0 +1,254 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_ca_H__
+#define __EN50221_APPLICATION_ca_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+#include <libucsi/mpeg/pmt_section.h>
+#include <libucsi/dvb/descriptor.h>
+
+#define CA_LIST_MANAGEMENT_MORE 0x00
+#define CA_LIST_MANAGEMENT_FIRST 0x01
+#define CA_LIST_MANAGEMENT_LAST 0x02
+#define CA_LIST_MANAGEMENT_ONLY 0x03
+#define CA_LIST_MANAGEMENT_ADD 0x04
+#define CA_LIST_MANAGEMENT_UPDATE 0x05
+
+#define CA_PMT_CMD_ID_OK_DESCRAMBLING 0x01
+#define CA_PMT_CMD_ID_OK_MMI 0x02
+#define CA_PMT_CMD_ID_QUERY 0x03
+#define CA_PMT_CMD_ID_NOT_SELECTED 0x04
+
+#define CA_ENABLE_DESCRAMBLING_POSSIBLE 0x01
+#define CA_ENABLE_DESCRAMBLING_POSSIBLE_PURCHASE 0x02
+#define CA_ENABLE_DESCRAMBLING_POSSIBLE_TECHNICAL 0x03
+#define CA_ENABLE_DESCRAMBLING_NOT_POSSIBLE_NO_ENTITLEMENT 0x71
+#define CA_ENABLE_DESCRAMBLING_NOT_POSSIBLE_TECHNICAL 0x73
+
+
+#define EN50221_APP_CA_RESOURCEID MKRID(3,1,1)
+
+/**
+ * PMT reply structure.
+ */
+struct en50221_app_pmt_reply {
+ uint16_t program_number;
+ EBIT3(uint8_t reserved_1 : 2; ,
+ uint8_t version_number : 5; ,
+ uint8_t current_next_indicator : 1; )
+ EBIT2(uint8_t CA_enable_flag : 1; ,
+ uint8_t CA_enable : 7; )
+ /* struct en50221_app_pmt_stream streams[] */
+} __attribute__((packed));
+
+/**
+ * A stream within a pmt reply structure.
+ */
+struct en50221_app_pmt_stream {
+ EBIT2(uint16_t reserved_1 : 3; ,
+ uint16_t es_pid :13; )
+ EBIT2(uint8_t CA_enable_flag : 1; ,
+ uint8_t CA_enable : 7; )
+} __attribute__((packed));
+
+/**
+ * Convenience iterator for the streams field of the en50221_app_pmt_reply structure.
+ *
+ * @param pmt Pointer to the en50221_app_pmt_reply structure.
+ * @param pos Variable holding a pointer to the current en50221_app_pmt_stream.
+ * @param size Total size of the PMT reply.
+ */
+#define en50221_app_pmt_reply_streams_for_each(pmt, pos, size) \
+ for ((pos) = en50221_app_pmt_reply_streams_first(pmt, size); \
+ (pos); \
+ (pos) = en50221_app_pmt_reply_streams_next(pmt, pos, size))
+
+
+/**
+ * Type definition for command - called when we receive a ca info response.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param ca_id_count Number of ca_system_ids.
+ * @param ca_ids Pointer to list of ca_system_ids.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_ca_info_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint32_t ca_id_count,
+ uint16_t *ca_ids);
+
+/**
+ * Type definition for pmt_reply - called when we receive a pmt_reply.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param reply Pointer to a struct en50221_app_pmt_reply.
+ * @param reply_size Total size of the struct en50221_app_pmt_reply in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_ca_pmt_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ struct en50221_app_pmt_reply *reply,
+ uint32_t reply_size);
+
+/**
+ * Opaque type representing a ca resource.
+ */
+typedef void *en50221_app_ca;
+
+/**
+ * Create an instance of the ca resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_ca en50221_app_ca_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the ca resource.
+ *
+ * @param ca Instance to destroy.
+ */
+extern void en50221_app_ca_destroy(en50221_app_ca ca);
+
+/**
+ * Register the callback for when we receive a ca info.
+ *
+ * @param ca ca resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_ca_register_info_callback(en50221_app_ca ca,
+ en50221_app_ca_info_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a pmt_reply.
+ *
+ * @param ca ca resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca,
+ en50221_app_ca_pmt_reply_callback callback, void *arg);
+
+/**
+ * Send a ca_info_req to the CAM.
+ *
+ * @param ca ca resource instance.
+ * @param session_number Session number to send it on.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_ca_info_enq(en50221_app_ca ca,
+ uint16_t session_number);
+
+/**
+ * Send a ca_pmt structure to the CAM.
+ *
+ * @param ca ca resource instance.
+ * @param session_number Session number to send it on.
+ * @param ca_pmt A ca_pmt structure formatted with the en50221_ca_format_pmt() function.
+ * @param ca_pmt_length Length of ca_pmt structure in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_ca_pmt(en50221_app_ca ca,
+ uint16_t session_number,
+ uint8_t *ca_pmt,
+ uint32_t ca_pmt_length);
+
+/**
+ * Transform a libucsi PMT into a binary structure for sending to a CAM.
+ *
+ * @param pmt The source PMT structure.
+ * @param data Pointer to data buffer to write it to.
+ * @param data_length Number of bytes available in data buffer.
+ * @param move_ca_descriptors If non-zero, will attempt to move CA descriptors
+ * in order to reduce the size of the formatted CAPMT.
+ * @param ca_pmt_list_management One of the CA_LIST_MANAGEMENT_*.
+ * @param ca_pmt_cmd_id One of the CA_PMT_CMD_ID_*.
+ * @return Number of bytes used, or -1 on error.
+ */
+extern int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt,
+ uint8_t *data,
+ uint32_t data_length,
+ int move_ca_descriptors,
+ uint8_t ca_pmt_list_management, uint8_t ca_pmt_cmd_id);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param ca CA instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_ca_message(en50221_app_ca ca,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+
+
+
+static inline struct en50221_app_pmt_stream *
+ en50221_app_pmt_reply_streams_first(struct en50221_app_pmt_reply *reply, uint32_t reply_size)
+{
+ uint32_t pos = sizeof(struct en50221_app_pmt_reply);
+
+ if (pos >= reply_size)
+ return NULL;
+
+ return (struct en50221_app_pmt_stream *)((uint8_t *)reply+ pos);
+}
+
+static inline struct en50221_app_pmt_stream *
+ en50221_app_pmt_reply_streams_next(struct en50221_app_pmt_reply * reply,
+ struct en50221_app_pmt_stream * pos,
+ uint32_t reply_size)
+{
+ uint8_t *end = (uint8_t*) reply + reply_size;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct en50221_app_pmt_stream);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct en50221_app_pmt_stream *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c
new file mode 100644
index 0000000..5686443
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.c
@@ -0,0 +1,169 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include <libucsi/dvb/types.h>
+#include "en50221_app_datetime.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_datetime_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_datetime_enquiry_callback callback;
+ void *callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+
+en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_datetime_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_datetime_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_datetime_destroy(en50221_app_datetime datetime)
+{
+ struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime,
+ en50221_app_datetime_enquiry_callback callback, void *arg)
+{
+ struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
+
+ pthread_mutex_lock(&private->lock);
+ private->callback = callback;
+ private->callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_datetime_send(en50221_app_datetime datetime,
+ uint16_t session_number,
+ time_t utc_time,
+ int time_offset)
+{
+ struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
+ uint8_t data[11];
+ int data_length;
+
+ data[0] = (TAG_DATE_TIME >> 16) & 0xFF;
+ data[1] = (TAG_DATE_TIME >> 8) & 0xFF;
+ data[2] = TAG_DATE_TIME & 0xFF;
+ if (time_offset != -1) {
+ data[3] = 7;
+ unixtime_to_dvbdate(utc_time, data+4);
+ data[9] = time_offset >> 8;
+ data[10] = time_offset;
+ data_length = 11;
+ } else {
+ data[3] = 5;
+ unixtime_to_dvbdate(utc_time, data+4);
+ data_length = 9;
+ }
+ return private->funcs->send_data(private->funcs->arg, session_number, data, data_length);
+}
+
+int en50221_app_datetime_message(en50221_app_datetime datetime,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_DATE_TIME_ENQUIRY:
+ return en50221_app_datetime_parse_enquiry(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+
+
+
+
+
+
+
+static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t response_interval = data[1];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_datetime_enquiry_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, response_interval);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h
new file mode 100644
index 0000000..5819fb4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_datetime.h
@@ -0,0 +1,116 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_DATETIME_H__
+#define __EN50221_APPLICATION_DATETIME_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EN50221_APP_DATETIME_RESOURCEID MKRID(36,1,1)
+
+/**
+ * Type definition for enquiry - called when we receive a date/time enquiry from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param response_interval Response interval requested by CAM.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_datetime_enquiry_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t response_interval);
+
+/**
+ * Opaque type representing a datetime resource.
+ */
+typedef void *en50221_app_datetime;
+
+/**
+ * Create an instance of the datetime resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the datetime resource.
+ *
+ * @param datetime Instance to destroy.
+ */
+extern void en50221_app_datetime_destroy(en50221_app_datetime datetime);
+
+/**
+ * Register the callback for when we receive a enquiry request.
+ *
+ * @param datetime datetime resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime,
+ en50221_app_datetime_enquiry_callback callback, void *arg);
+
+/**
+ * Send the time to the CAM.
+ *
+ * @param datetime datetime resource instance.
+ * @param session_number Session number to send it on.
+ * @param utc_time UTC time in unix time format.
+ * @param time_offset If -1, the field will not be transmitted, otherwise it is the offset between
+ * UTC and local time in minutes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_datetime_send(en50221_app_datetime datetime,
+ uint16_t session_number,
+ time_t utc_time,
+ int time_offset);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param datetime datetime instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_datetime_message(en50221_app_datetime datetime,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c
new file mode 100644
index 0000000..82da884
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.c
@@ -0,0 +1,263 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include "en50221_app_dvb.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_dvb_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_dvb_tune_callback tune_callback;
+ void *tune_callback_arg;
+
+ en50221_app_dvb_replace_callback replace_callback;
+ void *replace_callback_arg;
+
+ en50221_app_dvb_clear_replace_callback clear_replace_callback;
+ void *clear_replace_callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+
+en50221_app_dvb en50221_app_dvb_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_dvb_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_dvb_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->tune_callback = NULL;
+ private->replace_callback = NULL;
+ private->clear_replace_callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_dvb_destroy(en50221_app_dvb dvb)
+{
+ struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb,
+ en50221_app_dvb_tune_callback callback, void *arg)
+{
+ struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
+
+ pthread_mutex_lock(&private->lock);
+ private->tune_callback = callback;
+ private->tune_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb,
+ en50221_app_dvb_replace_callback callback, void *arg)
+{
+ struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
+
+ pthread_mutex_lock(&private->lock);
+ private->replace_callback = callback;
+ private->replace_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb,
+ en50221_app_dvb_clear_replace_callback callback, void *arg)
+{
+ struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
+
+ pthread_mutex_lock(&private->lock);
+ private->clear_replace_callback = callback;
+ private->clear_replace_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_number)
+{
+ struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
+ uint8_t data[4];
+
+ data[0] = (TAG_ASK_RELEASE >> 16) & 0xFF;
+ data[1] = (TAG_ASK_RELEASE >> 8) & 0xFF;
+ data[2] = TAG_ASK_RELEASE & 0xFF;
+ data[3] = 0;
+
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 4);
+}
+
+int en50221_app_dvb_message(en50221_app_dvb dvb,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_TUNE:
+ return en50221_app_dvb_parse_tune(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_REPLACE:
+ return en50221_app_dvb_parse_replace(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_CLEAR_REPLACE:
+ return en50221_app_dvb_parse_clear_replace(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+
+
+
+
+
+
+
+static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length < 9) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 8) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t *tune_data = data+1;
+
+ // parse it
+ uint16_t network_id = (tune_data[0] << 8) | tune_data[1];
+ uint16_t original_network_id = (tune_data[2] << 8) | tune_data[3];
+ uint16_t transport_stream_id = (tune_data[4] << 8) | tune_data[5];
+ uint16_t service_id = (tune_data[6] << 8) | tune_data[7];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_dvb_tune_callback cb = private->tune_callback;
+ void *cb_arg = private->tune_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, network_id, original_network_id, transport_stream_id, service_id);
+ }
+ return 0;
+}
+
+static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length < 6) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 5) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t *replace_data = data+1;
+
+ // parse it
+ uint8_t replacement_ref = replace_data[0];
+ uint16_t replace_pid = ((replace_data[1] & 0x1f)<<8) | replace_data[2];
+ uint16_t replacement_pid = ((replace_data[3] & 0x1f)<<8) | replace_data[4];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_dvb_replace_callback cb = private->replace_callback;
+ void *cb_arg = private->replace_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, replacement_ref, replace_pid, replacement_pid);
+ }
+ return 0;
+}
+
+static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length < 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t *replace_data = data+1;
+
+ // parse it
+ uint8_t replacement_ref = replace_data[0];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_dvb_clear_replace_callback cb = private->clear_replace_callback;
+ void *cb_arg = private->clear_replace_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, replacement_ref);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h
new file mode 100644
index 0000000..221f58a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_dvb.h
@@ -0,0 +1,164 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_DVB_H__
+#define __EN50221_APPLICATION_DVB_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EN50221_APP_DVB_RESOURCEID MKRID(32,1,1)
+
+
+/**
+ * Type definition for tune - called when we receive a tune request from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param network_id Network id requested by CAM.
+ * @param original_network_id Original Network id requested by CAM.
+ * @param transport_stream_id Transport stream id requested by CAM.
+ * @param service_id Service id requested by CAM.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_dvb_tune_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint16_t network_id, uint32_t original_network_id,
+ uint16_t transport_stream_id, uint16_t service_id);
+
+/**
+ * Type definition for replace - called when we receive a replace request from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param replacement_ref Replacement ref.
+ * @param replaced_pid PID to replace.
+ * @param replacement_pid PID to replace it with.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_dvb_replace_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t replacement_ref,
+ uint16_t replaced_pid, uint16_t replacement_pid);
+
+
+/**
+ * Type definition for clear_replace - called when we receive a clear_replace request from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param replacement_ref Replacement ref.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_dvb_clear_replace_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t replacement_ref);
+
+
+/**
+ * Opaque type representing a dvb resource.
+ */
+typedef void *en50221_app_dvb;
+
+/**
+ * Create an instance of the dvb resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_dvb en50221_app_dvb_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the dvb resource.
+ *
+ * @param dvb Instance to destroy.
+ */
+extern void en50221_app_dvb_destroy(en50221_app_dvb dvb);
+
+/**
+ * Register the callback for when we receive a tune request.
+ *
+ * @param dvb DVB resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb,
+ en50221_app_dvb_tune_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a replace request.
+ *
+ * @param dvb DVB resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb,
+ en50221_app_dvb_replace_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a clear replace request.
+ *
+ * @param dvb DVB resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb,
+ en50221_app_dvb_clear_replace_callback callback, void *arg);
+
+/**
+ * Send an ask release request to the CAM.
+ *
+ * @param dvb DVB resource instance.
+ * @param session_number Session number to send it on.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_number);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param dvb dvb instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_dvb_message(en50221_app_dvb dvb,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c
new file mode 100644
index 0000000..dba09b0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.c
@@ -0,0 +1,166 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include <libucsi/dvb/types.h>
+#include "en50221_app_epg.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_epg_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_epg_reply_callback callback;
+ void *callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_epg_parse_reply(struct en50221_app_epg_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+
+en50221_app_epg en50221_app_epg_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_epg_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_epg_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_epg_destroy(en50221_app_epg epg)
+{
+ struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_epg_register_enquiry_callback(en50221_app_epg epg,
+ en50221_app_epg_reply_callback callback, void *arg)
+{
+ struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg;
+
+ pthread_mutex_lock(&private->lock);
+ private->callback = callback;
+ private->callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_epg_enquire(en50221_app_epg epg,
+ uint16_t session_number,
+ uint8_t command_id,
+ uint16_t network_id,
+ uint16_t original_network_id,
+ uint16_t transport_stream_id,
+ uint16_t service_id,
+ uint16_t event_id)
+{
+ struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg;
+ uint8_t data[15];
+
+ data[0] = (TAG_EPG_ENQUIRY >> 16) & 0xFF;
+ data[1] = (TAG_EPG_ENQUIRY >> 8) & 0xFF;
+ data[2] = TAG_EPG_ENQUIRY & 0xFF;
+ data[3] = 11;
+ data[4] = command_id;
+ data[5] = network_id >> 8;
+ data[6] = network_id;
+ data[7] = original_network_id >> 8;
+ data[8] = original_network_id;
+ data[9] = transport_stream_id >> 8;
+ data[10] = transport_stream_id;
+ data[11] = service_id >> 8;
+ data[12] = service_id;
+ data[13] = event_id >> 8;
+ data[14] = event_id;
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 15);
+}
+
+int en50221_app_epg_message(en50221_app_epg epg,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_epg_private *private = (struct en50221_app_epg_private *) epg;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_EPG_REPLY:
+ return en50221_app_epg_parse_reply(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+static int en50221_app_epg_parse_reply(struct en50221_app_epg_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t event_status = data[1];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_epg_reply_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, event_status);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h
new file mode 100644
index 0000000..c3c4c59
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_epg.h
@@ -0,0 +1,136 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_epg_H__
+#define __EN50221_APPLICATION_epg_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EPG_COMMAND_ID_MMI 0x02
+#define EPG_COMMAND_ID_QUERY 0x03
+
+#define EPG_EVENTSTATUS_ENTITLEMENT_UNKNOWN 0x00
+#define EPG_EVENTSTATUS_ENTITLEMENT_AVAILABLE 0x01
+#define EPG_EVENTSTATUS_ENTITLEMENT_NOT_AVAILABLE 0x02
+#define EPG_EVENTSTATUS_MMI_DIALOGUE_REQUIRED 0x03
+#define EPG_EVENTSTATUS_MMI_COMPLETE_UNKNOWN 0x04
+#define EPG_EVENTSTATUS_MMI_COMPLETE_AVAILABLE 0x05
+#define EPG_EVENTSTATUS_MMI_COMPLETE_NOT_AVAILABLE 0x06
+
+#define EN50221_APP_EPG_RESOURCEID(INSTANCE_NUM) MKRID(120,(INSTANCE_NUM),1)
+
+
+
+/**
+ * Type definition for reply - called when we receive an EPG reply from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param event_status One of the EPG_EVENTSTATUS_* values.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_epg_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t event_status);
+
+/**
+ * Opaque type representing a epg resource.
+ */
+typedef void *en50221_app_epg;
+
+/**
+ * Create an instance of the epg resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_epg en50221_app_epg_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the epg resource.
+ *
+ * @param epg Instance to destroy.
+ */
+extern void en50221_app_epg_destroy(en50221_app_epg epg);
+
+/**
+ * Register the callback for when we receive a enquiry response.
+ *
+ * @param epg epg resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_epg_register_reply_callback(en50221_app_epg epg,
+ en50221_app_epg_reply_callback callback, void *arg);
+
+/**
+ * Enquire about the entitlement status for an EPG entry.
+ *
+ * @param epg epg resource instance.
+ * @param session_number Session number to send it on.
+ * @param command_id One of the EPG_COMMAND_ID_* fields.
+ * @param network_id Network ID concerned.
+ * @param original_network_id Original network ID concerned.
+ * @param transport_stream_id Transport stream ID concerned.
+ * @param service_id Service ID concerned.
+ * @param event_id Event ID concerned.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_epg_enquire(en50221_app_epg epg,
+ uint16_t session_number,
+ uint8_t command_id,
+ uint16_t network_id,
+ uint16_t original_network_id,
+ uint16_t transport_stream_id,
+ uint16_t service_id,
+ uint16_t event_id);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param epg epg instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_epg_message(en50221_app_epg epg,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c
new file mode 100644
index 0000000..25d088f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.c
@@ -0,0 +1,514 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include "en50221_app_lowspeed.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_lowspeed_session {
+ uint16_t session_number;
+ uint8_t *block_chain;
+ uint32_t block_length;
+
+ struct en50221_app_lowspeed_session *next;
+};
+
+struct en50221_app_lowspeed_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_lowspeed_command_callback command_callback;
+ void *command_callback_arg;
+
+ en50221_app_lowspeed_send_callback send_callback;
+ void *send_callback_arg;
+
+ struct en50221_app_lowspeed_session *sessions;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command,
+ uint8_t *data,
+ int data_length);
+static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed_private *private,
+ uint8_t slot_id, uint16_t session_number, int more_last,
+ uint8_t *data, uint32_t data_length);
+
+
+
+en50221_app_lowspeed en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_lowspeed_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_lowspeed_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->command_callback = NULL;
+ private->send_callback = NULL;
+ private->sessions = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_lowspeed_destroy(en50221_app_lowspeed lowspeed)
+{
+ struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed;
+
+ struct en50221_app_lowspeed_session *cur_s = private->sessions;
+ while(cur_s) {
+ struct en50221_app_lowspeed_session *next = cur_s->next;
+ if (cur_s->block_chain)
+ free(cur_s->block_chain);
+ free(cur_s);
+ cur_s = next;
+ }
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_lowspeed_clear_session(en50221_app_lowspeed lowspeed, uint16_t session_number)
+{
+ struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed;
+
+ pthread_mutex_lock(&private->lock);
+ struct en50221_app_lowspeed_session *cur_s = private->sessions;
+ struct en50221_app_lowspeed_session *prev_s = NULL;
+ while(cur_s) {
+ if (cur_s->session_number == session_number) {
+ if (cur_s->block_chain)
+ free(cur_s->block_chain);
+ if (prev_s) {
+ prev_s->next = cur_s->next;
+ } else {
+ private->sessions = cur_s->next;
+ }
+ free(cur_s);
+ return;
+ }
+
+ prev_s = cur_s;
+ cur_s=cur_s->next;
+ }
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_lowspeed_register_command_callback(en50221_app_lowspeed lowspeed,
+ en50221_app_lowspeed_command_callback callback, void *arg)
+{
+ struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed;
+
+ pthread_mutex_lock(&private->lock);
+ private->command_callback = callback;
+ private->command_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_lowspeed_register_send_callback(en50221_app_lowspeed lowspeed,
+ en50221_app_lowspeed_send_callback callback, void *arg)
+{
+ struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed;
+
+ pthread_mutex_lock(&private->lock);
+ private->send_callback = callback;
+ private->send_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_lowspeed_send_comms_reply(en50221_app_lowspeed lowspeed,
+ uint16_t session_number,
+ uint8_t comms_reply_id,
+ uint8_t return_value)
+{
+ struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed;
+ uint8_t data[6];
+
+ data[0] = (TAG_COMMS_REPLY >> 16) & 0xFF;
+ data[1] = (TAG_COMMS_REPLY >> 8) & 0xFF;
+ data[2] = TAG_COMMS_REPLY & 0xFF;
+ data[3] = 2;
+ data[4] = comms_reply_id;
+ data[5] = return_value;
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 6);
+}
+
+int en50221_app_lowspeed_send_comms_data(en50221_app_lowspeed lowspeed,
+ uint16_t session_number,
+ uint8_t phase_id,
+ uint32_t tx_data_length,
+ uint8_t *tx_data)
+{
+ struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed;
+ uint8_t buf[10];
+
+ // the spec defines this limit
+ if (tx_data_length > 254) {
+ return -1;
+ }
+
+ // set up the tag
+ buf[0] = (TAG_COMMS_RECV_LAST >> 16) & 0xFF;
+ buf[1] = (TAG_COMMS_RECV_LAST >> 8) & 0xFF;
+ buf[2] = TAG_COMMS_RECV_LAST & 0xFF;
+
+ // encode the length field
+ int length_field_len;
+ if ((length_field_len = asn_1_encode(tx_data_length+1, buf+3, 3)) < 0) {
+ return -1;
+ }
+
+ // the phase_id
+ buf[3+length_field_len] = phase_id;
+
+ // build the iovecs
+ struct iovec iov[2];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 3+length_field_len+1;
+ iov[1].iov_base = tx_data;
+ iov[1].iov_len = tx_data_length;
+
+ // create the data and send it
+ return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2);
+}
+
+int en50221_app_lowspeed_message(en50221_app_lowspeed lowspeed,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_lowspeed_private *private = (struct en50221_app_lowspeed_private *) lowspeed;
+ (void)resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_COMMS_COMMAND:
+ return en50221_app_lowspeed_parse_command(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_COMMS_SEND_LAST:
+ return en50221_app_lowspeed_parse_send(private, slot_id, session_number, 1, data+3, data_length-3);
+ case TAG_COMMS_SEND_MORE:
+ return en50221_app_lowspeed_parse_send(private, slot_id, session_number, 0, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+static int en50221_app_lowspeed_parse_connect_on_channel(struct en50221_app_lowspeed_command *command,
+ uint8_t *data,
+ int data_length)
+{
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // check the tag
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+ if (tag != TAG_CONNECTION_DESCRIPTOR) {
+ print(LOG_LEVEL, ERROR, 1, "Received bad CONNECT_ON_CHANNEL\n");
+ return -1;
+ }
+ data+=3;
+ data_length-=3;
+
+ // parse the descriptor-length-field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+ data+=length_field_len;
+ data_length-=length_field_len;
+
+ // check length field
+ if (asn_data_length > data_length) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length < 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // get the descriptor type
+ command->u.connect_on_channel.descriptor_type = data[0];
+ data++;
+ data_length--;
+ asn_data_length--;
+
+ // deal with the descriptor itself
+ switch(command->u.connect_on_channel.descriptor_type) {
+ case CONNECTION_DESCRIPTOR_TYPE_TELEPHONE:
+ {
+ // get the raw descriptor and validate length
+ struct descriptor *d = (struct descriptor*) data;
+ if (asn_data_length < 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length != (2 + d->len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (d->tag != dtag_dvb_telephone) {
+ print(LOG_LEVEL, ERROR, 1, "Received invalid telephone descriptor\n");
+ return -1;
+ }
+
+ // parse the telephone descriptor
+ command->u.connect_on_channel.descriptor.telephone = dvb_telephone_descriptor_codec(d);
+ if (command->u.connect_on_channel.descriptor.telephone == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Received invalid telephone descriptor\n");
+ return -1;
+ }
+ data += 2 + d->len;
+ data_length -= 2 + d->len;
+ break;
+ }
+ case CONNECTION_DESCRIPTOR_TYPE_CABLE:
+ if (asn_data_length != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ command->u.connect_on_channel.descriptor.cable_channel_id = data[0];
+ data++;
+ data_length--;
+ break;
+ default:
+ print(LOG_LEVEL, ERROR, 1, "Received unknown connection descriptor %02x\n",
+ command->u.connect_on_channel.descriptor_type);
+ return -1;
+ }
+
+ // parse the last bit
+ if (data_length != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ command->u.connect_on_channel.retry_count = data[0];
+ command->u.connect_on_channel.timeout = data[1];
+
+ // ok
+ return 0;
+}
+
+static int en50221_app_lowspeed_parse_command(struct en50221_app_lowspeed_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length < 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ data+=length_field_len;
+
+ // get command id
+ uint8_t command_id = data[0];
+ data++;
+ asn_data_length--;
+
+ // parse the command
+ struct en50221_app_lowspeed_command command;
+ switch(command_id) {
+ case COMMS_COMMAND_ID_CONNECT_ON_CHANNEL:
+ if (en50221_app_lowspeed_parse_connect_on_channel(&command, data, asn_data_length)) {
+ return -1;
+ }
+ break;
+ case COMMS_COMMAND_ID_SET_PARAMS:
+ if (asn_data_length != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ command.u.set_params.buffer_size = data[0];
+ command.u.set_params.timeout = data[1];
+ break;
+ case COMMS_COMMAND_ID_GET_NEXT_BUFFER:
+ if (asn_data_length != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ command.u.get_next_buffer.phase_id = data[0];
+ break;
+
+ case COMMS_COMMAND_ID_DISCONNECT_ON_CHANNEL:
+ case COMMS_COMMAND_ID_ENQUIRE_STATUS:
+ break;
+
+ default:
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected command_id %02x\n", command_id);
+ return -1;
+ }
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_lowspeed_command_callback cb = private->command_callback;
+ void *cb_arg = private->command_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, command_id, &command);
+ }
+ return 0;
+}
+
+static int en50221_app_lowspeed_parse_send(struct en50221_app_lowspeed_private *private,
+ uint8_t slot_id, uint16_t session_number, int more_last,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // skip over the length field
+ data += length_field_len;
+
+ // find previous session
+ pthread_mutex_lock(&private->lock);
+ struct en50221_app_lowspeed_session *cur_s = private->sessions;
+ while(cur_s) {
+ if (cur_s->session_number == session_number)
+ break;
+ cur_s=cur_s->next;
+ }
+
+ // more data is still to come
+ if (!more_last) {
+ // if there was no previous session, create one
+ if (cur_s == NULL) {
+ cur_s = malloc(sizeof(struct en50221_app_lowspeed_session));
+ if (cur_s == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ pthread_mutex_unlock(&private->lock);
+ return -1;
+ }
+ cur_s->session_number = session_number;
+ cur_s->block_chain = NULL;
+ cur_s->block_length = 0;
+ cur_s->next = private->sessions;
+ private->sessions = cur_s;
+ }
+
+ // append the data
+ uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length);
+ if (new_data == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ pthread_mutex_unlock(&private->lock);
+ return -1;
+ }
+ memcpy(new_data + cur_s->block_length, data, asn_data_length);
+ cur_s->block_chain = new_data;
+ cur_s->block_length += asn_data_length;
+
+ // done
+ pthread_mutex_unlock(&private->lock);
+ return 0;
+ }
+
+ // we hit the last of a possible chain of fragments
+ int do_free = 0;
+ if (cur_s != NULL) {
+ // we have a preceding fragment - need to append
+ uint8_t *new_data = realloc(cur_s->block_chain, cur_s->block_length + asn_data_length);
+ if (new_data == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ pthread_mutex_unlock(&private->lock);
+ return -1;
+ }
+ memcpy(new_data + cur_s->block_length, data, asn_data_length);
+ asn_data_length = cur_s->block_length + asn_data_length;
+ data = new_data;
+ cur_s->block_chain = NULL;
+ cur_s->block_length = 0;
+ do_free = 1;
+ }
+
+ // check the reassembled data length
+ if (asn_data_length < 1) {
+ pthread_mutex_unlock(&private->lock);
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ if (do_free) free(data);
+ return -1;
+ }
+
+ // now, parse the data
+ uint8_t phase_id = data[0];
+
+ // tell the app
+ en50221_app_lowspeed_send_callback cb = private->send_callback;
+ void *cb_arg = private->send_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ int cbstatus = 0;
+ if (cb) {
+ cbstatus = cb(cb_arg, slot_id, session_number, phase_id, data+1, asn_data_length-1);
+ }
+
+ // done
+ if (do_free) free(data);
+ return cbstatus;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h
new file mode 100644
index 0000000..9f58ad9
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_lowspeed.h
@@ -0,0 +1,210 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_LOWSPEED_H__
+#define __EN50221_APPLICATION_LOWSPEED_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+#include <libucsi/dvb/descriptor.h>
+
+#define COMMS_COMMAND_ID_CONNECT_ON_CHANNEL 0x01
+#define COMMS_COMMAND_ID_DISCONNECT_ON_CHANNEL 0x02
+#define COMMS_COMMAND_ID_SET_PARAMS 0x03
+#define COMMS_COMMAND_ID_ENQUIRE_STATUS 0x04
+#define COMMS_COMMAND_ID_GET_NEXT_BUFFER 0x05
+
+#define CONNECTION_DESCRIPTOR_TYPE_TELEPHONE 0x01
+#define CONNECTION_DESCRIPTOR_TYPE_CABLE 0x02
+
+#define COMMS_REPLY_ID_CONNECT_ACK 0x01
+#define COMMS_REPLY_ID_DISCONNECT_ACK 0x02
+#define COMMS_REPLY_ID_SET_PARAMS_ACK 0x03
+#define COMMS_REPLY_ID_STATUS_REPLY 0x04
+#define COMMS_REPLY_ID_GET_NEXT_BUFFER_ACK 0x05
+#define COMMS_REPLY_ID_SEND_ACK 0x06
+
+#define EN50221_APP_LOWSPEED_RESOURCEID(DEVICE_TYPE, DEVICE_NUMBER) MKRID(96,((DEVICE_TYPE)<<2)|((DEVICE_NUMBER) & 0x03),1)
+
+
+/**
+ * Structure holding information on a received comms command.
+ */
+struct en50221_app_lowspeed_command {
+ union {
+ struct {
+ uint8_t descriptor_type; // CONNECTION_DESCRIPTOR_TYPE_*
+ uint8_t retry_count;
+ uint8_t timeout;
+ union {
+ struct dvb_telephone_descriptor *telephone;
+ uint8_t cable_channel_id;
+ } descriptor;
+ } connect_on_channel;
+
+ struct {
+ uint8_t buffer_size;
+ uint8_t timeout;
+ } set_params;
+
+ struct {
+ uint8_t phase_id;
+ } get_next_buffer;
+ } u;
+};
+
+/**
+ * Type definition for command - called when we receive a comms command.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param command_id One of the COMMS_COMMAND_ID_* values
+ * @param command Pointer to a lowspeed command structure containing the command data.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_lowspeed_command_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t command_id,
+ struct en50221_app_lowspeed_command *command);
+
+/**
+ * Type definition for send - called when we receive data to send. The block can be segmented into
+ * multiple pieces - last_more indicates the details of this.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param phase_id Comms phase id.
+ * @param data The data.
+ * @param length Number of bytes.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_lowspeed_send_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t phase_id, uint8_t *data, uint32_t length);
+
+/**
+ * Opaque type representing a lowspeed resource.
+ */
+typedef void *en50221_app_lowspeed;
+
+/**
+ * Create an instance of the lowspeed resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_lowspeed en50221_app_lowspeed_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the lowspeed resource.
+ *
+ * @param lowspeed Instance to destroy.
+ */
+extern void en50221_app_lowspeed_destroy(en50221_app_lowspeed lowspeed);
+
+/**
+ * Informs the lowspeed object that a session to it has been closed - cleans up internal state.
+ *
+ * @param lowspeed lowspeed resource instance.
+ * @param session_number The session concerned.
+ */
+extern void en50221_app_lowspeed_clear_session(en50221_app_lowspeed lowspeed, uint16_t session_number);
+
+/**
+ * Register the callback for when we receive a comms command.
+ *
+ * @param lowspeed lowspeed resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_lowspeed_register_command_callback(en50221_app_lowspeed lowspeed,
+ en50221_app_lowspeed_command_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive data to send.
+ *
+ * @param lowspeed lowspeed resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_lowspeed_register_send_callback(en50221_app_lowspeed lowspeed,
+ en50221_app_lowspeed_send_callback callback, void *arg);
+
+/**
+ * Send a comms reply to the CAM.
+ *
+ * @param lowspeed lowspeed resource instance.
+ * @param session_number Session number to send it on.
+ * @param comms_reply_id One of the COMMS_REPLY_ID_* values.
+ * @param return_value Comms reply specific value.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_lowspeed_send_comms_reply(en50221_app_lowspeed lowspeed,
+ uint16_t session_number,
+ uint8_t comms_reply_id,
+ uint8_t return_value);
+
+/**
+ * Send received data to the CAM.
+ *
+ * @param lowspeed lowspeed resource instance.
+ * @param session_number Session number to send it on.
+ * @param phase_id Comms phase id.
+ * @param tx_data_length Length of data in bytes (max 254 bytes as per spec).
+ * @param tx_data Data.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_lowspeed_send_comms_data(en50221_app_lowspeed lowspeed,
+ uint16_t session_number,
+ uint8_t phase_id,
+ uint32_t tx_data_length,
+ uint8_t *tx_data);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param lowspeed lowspeed instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_lowspeed_message(en50221_app_lowspeed lowspeed,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c
new file mode 100644
index 0000000..ab5c6e4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.c
@@ -0,0 +1,1316 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include <libucsi/dvb/types.h>
+#include "en50221_app_mmi.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_mmi_session {
+ uint16_t session_number;
+
+ uint8_t *menu_block_chain;
+ uint32_t menu_block_length;
+
+ uint8_t *list_block_chain;
+ uint32_t list_block_length;
+
+ uint8_t *subtitlesegment_block_chain;
+ uint32_t subtitlesegment_block_length;
+
+ uint8_t *subtitledownload_block_chain;
+ uint32_t subtitledownload_block_length;
+
+ struct en50221_app_mmi_session *next;
+};
+
+struct en50221_app_mmi_private {
+ struct en50221_app_send_functions *funcs;
+ struct en50221_app_mmi_session *sessions;
+
+ en50221_app_mmi_close_callback closecallback;
+ void *closecallback_arg;
+
+ en50221_app_mmi_display_control_callback displaycontrolcallback;
+ void *displaycontrolcallback_arg;
+
+ en50221_app_mmi_keypad_control_callback keypadcontrolcallback;
+ void *keypadcontrolcallback_arg;
+
+ en50221_app_mmi_subtitle_segment_callback subtitlesegmentcallback;
+ void *subtitlesegmentcallback_arg;
+
+ en50221_app_mmi_scene_end_mark_callback sceneendmarkcallback;
+ void *sceneendmarkcallback_arg;
+
+ en50221_app_mmi_scene_control_callback scenecontrolcallback;
+ void *scenecontrolcallback_arg;
+
+ en50221_app_mmi_subtitle_download_callback subtitledownloadcallback;
+ void *subtitledownloadcallback_arg;
+
+ en50221_app_mmi_flush_download_callback flushdownloadcallback;
+ void *flushdownloadcallback_arg;
+
+ en50221_app_mmi_enq_callback enqcallback;
+ void *enqcallback_arg;
+
+ en50221_app_mmi_menu_callback menucallback;
+ void *menucallback_arg;
+
+ en50221_app_mmi_list_callback listcallback;
+ void *listcallback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_mmi_parse_close(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_enq(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number, uint32_t tag_id,
+ int more_last, uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number, uint32_t tag_id,
+ int more_last, uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number, uint32_t tag_id,
+ int more_last, uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_mmi_defragment(struct en50221_app_mmi_private *private,
+ uint16_t session_number,
+ uint32_t tag_id,
+ int more_last,
+ uint8_t *indata,
+ uint32_t indata_length,
+ uint8_t **outdata,
+ uint32_t *outdata_length);
+static int en50221_app_mmi_defragment_text(uint8_t *data,
+ uint32_t data_length,
+ uint8_t **outdata,
+ uint32_t *outdata_length,
+ uint32_t *outconsumed);
+
+
+
+en50221_app_mmi en50221_app_mmi_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_mmi_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_mmi_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->closecallback = NULL;
+ private->displaycontrolcallback = NULL;
+ private->keypadcontrolcallback = NULL;
+ private->subtitlesegmentcallback = NULL;
+ private->sceneendmarkcallback = NULL;
+ private->scenecontrolcallback = NULL;
+ private->subtitledownloadcallback = NULL;
+ private->flushdownloadcallback = NULL;
+ private->enqcallback = NULL;
+ private->menucallback = NULL;
+ private->listcallback = NULL;
+ private->sessions = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_mmi_destroy(en50221_app_mmi mmi)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ struct en50221_app_mmi_session *cur_s = private->sessions;
+ while(cur_s) {
+ struct en50221_app_mmi_session *next = cur_s->next;
+ if (cur_s->menu_block_chain)
+ free(cur_s->menu_block_chain);
+ if (cur_s->list_block_chain)
+ free(cur_s->list_block_chain);
+ if (cur_s->subtitlesegment_block_chain)
+ free(cur_s->subtitlesegment_block_chain);
+ if (cur_s->subtitledownload_block_chain)
+ free(cur_s->subtitledownload_block_chain);
+ free(cur_s);
+ cur_s = next;
+ }
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_mmi_clear_session(en50221_app_mmi mmi, uint16_t session_number)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ struct en50221_app_mmi_session *cur_s = private->sessions;
+ struct en50221_app_mmi_session *prev_s = NULL;
+ while(cur_s) {
+ if (cur_s->session_number == session_number) {
+ if (cur_s->menu_block_chain)
+ free(cur_s->menu_block_chain);
+ if (cur_s->list_block_chain)
+ free(cur_s->list_block_chain);
+ if (cur_s->subtitlesegment_block_chain)
+ free(cur_s->subtitlesegment_block_chain);
+ if (cur_s->subtitledownload_block_chain)
+ free(cur_s->subtitledownload_block_chain);
+ if (prev_s) {
+ prev_s->next = cur_s->next;
+ } else {
+ private->sessions = cur_s->next;
+ }
+ free(cur_s);
+ return;
+ }
+
+ prev_s = cur_s;
+ cur_s=cur_s->next;
+ }
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_close_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_close_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->closecallback = callback;
+ private->closecallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_display_control_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_display_control_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->displaycontrolcallback = callback;
+ private->displaycontrolcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_keypad_control_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_keypad_control_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->keypadcontrolcallback = callback;
+ private->keypadcontrolcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_subtitle_segment_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_subtitle_segment_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->subtitlesegmentcallback = callback;
+ private->subtitlesegmentcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_scene_end_mark_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_scene_end_mark_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->sceneendmarkcallback = callback;
+ private->sceneendmarkcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_scene_control_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_scene_control_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->scenecontrolcallback = callback;
+ private->scenecontrolcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_subtitle_download_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_subtitle_download_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->subtitledownloadcallback = callback;
+ private->subtitledownloadcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_flush_download_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_flush_download_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->flushdownloadcallback = callback;
+ private->flushdownloadcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_enq_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_enq_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->enqcallback = callback;
+ private->enqcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_menu_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_menu_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->menucallback = callback;
+ private->menucallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_mmi_register_list_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_list_callback callback, void *arg)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+
+ pthread_mutex_lock(&private->lock);
+ private->listcallback = callback;
+ private->listcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_mmi_close(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t cmd_id,
+ uint8_t delay)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t data[6];
+ int data_length = 5;
+
+ data[0] = (TAG_CLOSE_MMI >> 16) & 0xFF;
+ data[1] = (TAG_CLOSE_MMI >> 8) & 0xFF;
+ data[2] = TAG_CLOSE_MMI & 0xFF;
+ data[3] = 1;
+ data[4] = cmd_id;
+ if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) {
+ data[3] = 2;
+ data[5] = delay;
+ data_length = 6;
+ }
+ return private->funcs->send_data(private->funcs->arg, session_number, data, data_length);
+}
+
+int en50221_app_mmi_display_reply(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t reply_id,
+ struct en502221_app_mmi_display_reply_details *details)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t data[32];
+ struct iovec iov[2];
+ uint32_t iov_count;
+ int length_field_len;
+
+ // fill out the start of the header
+ data[0] = (TAG_DISPLAY_REPLY >> 16) & 0xFF;
+ data[1] = (TAG_DISPLAY_REPLY >> 8) & 0xFF;
+ data[2] = TAG_DISPLAY_REPLY & 0xFF;
+
+ switch(reply_id) {
+ case MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK:
+ data[3] = 2;
+ data[4] = reply_id;
+ data[5] = details->u.mode_ack.mmi_mode;
+ iov[0].iov_base = data;
+ iov[0].iov_len = 6;
+ iov_count = 1;
+ break;
+
+ case MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES:
+ case MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES:
+ if ((length_field_len = asn_1_encode(details->u.char_table.table_length+1, data+3, 3)) < 0) {
+ return -1;
+ }
+ data[3+length_field_len] = reply_id;
+ iov[0].iov_base = data;
+ iov[0].iov_len = 3+length_field_len+1;
+ iov[1].iov_base = details->u.char_table.table;
+ iov[1].iov_len = details->u.char_table.table_length;
+ iov_count = 2;
+ break;
+
+ case MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS:
+ case MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS:
+ {
+ if ((length_field_len = asn_1_encode(1+9+(details->u.gfx.num_pixel_depths*2), data+3, 3)) < 0) {
+ return -1;
+ }
+ data[3+length_field_len] = reply_id;
+ data[3+length_field_len+1] = details->u.gfx.width >> 8;
+ data[3+length_field_len+2] = details->u.gfx.width;
+ data[3+length_field_len+3] = details->u.gfx.height >> 8;
+ data[3+length_field_len+4] = details->u.gfx.height;
+ data[3+length_field_len+5] = ((details->u.gfx.aspect_ratio & 0x0f) << 4) |
+ ((details->u.gfx.gfx_relation_to_video & 0x07) << 1) |
+ (details->u.gfx.multiple_depths & 1);
+ data[3+length_field_len+6] = details->u.gfx.display_bytes >> 4;
+ data[3+length_field_len+7] = ((details->u.gfx.display_bytes & 0x0f) << 4) |
+ ((details->u.gfx.composition_buffer_bytes & 0xf0) >> 4);
+ data[3+length_field_len+8] = ((details->u.gfx.composition_buffer_bytes & 0x0f) << 4) |
+ ((details->u.gfx.object_cache_bytes & 0xf0) >> 4);
+ data[3+length_field_len+9] = ((details->u.gfx.object_cache_bytes & 0x0f) << 4) |
+ (details->u.gfx.num_pixel_depths & 0x0f);
+
+ // render the pixel depths themselves
+ uint8_t *pixdepths = alloca(details->u.gfx.num_pixel_depths * 2);
+ if (pixdepths == NULL) {
+ return -1;
+ }
+ uint32_t i;
+ for(i=0; i < details->u.gfx.num_pixel_depths; i++) {
+ pixdepths[0] = ((details->u.gfx.pixel_depths[i].display_depth & 0x07) << 5) |
+ ((details->u.gfx.pixel_depths[i].pixels_per_byte & 0x07) << 2);
+ pixdepths[1] = details->u.gfx.pixel_depths[i].region_overhead;
+ pixdepths+=2;
+ }
+
+ // make up the iovs
+ iov[0].iov_base = data;
+ iov[0].iov_len = 3+length_field_len+10;
+ iov[1].iov_base = pixdepths;
+ iov[1].iov_len = details->u.gfx.num_pixel_depths *2;
+ iov_count = 2;
+ break;
+ }
+
+ default:
+ data[3] = 1;
+ data[4] = reply_id;
+ iov[0].iov_base = data;
+ iov[0].iov_len = 5;
+ iov_count = 1;
+ break;
+ }
+
+ // sendit
+ return private->funcs->send_datav(private->funcs->arg, session_number, iov, iov_count);
+}
+
+int en50221_app_mmi_keypress(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t keycode)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t data[5];
+
+ data[0] = (TAG_KEYPRESS >> 16) & 0xFF;
+ data[1] = (TAG_KEYPRESS >> 8) & 0xFF;
+ data[2] = TAG_KEYPRESS & 0xFF;
+ data[3] = 1;
+ data[4] = keycode;
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 5);
+}
+
+int en50221_app_mmi_display_message(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t display_message_id)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t data[5];
+
+ data[0] = (TAG_DISPLAY_MESSAGE >> 16) & 0xFF;
+ data[1] = (TAG_DISPLAY_MESSAGE >> 8) & 0xFF;
+ data[2] = TAG_DISPLAY_MESSAGE & 0xFF;
+ data[3] = 1;
+ data[4] = display_message_id;
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 5);
+}
+
+int en50221_app_mmi_scene_done(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t decoder_continue,
+ uint8_t scene_reveal,
+ uint8_t scene_tag)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t data[5];
+
+ data[0] = (TAG_SCENE_DONE >> 16) & 0xFF;
+ data[1] = (TAG_SCENE_DONE >> 8) & 0xFF;
+ data[2] = TAG_SCENE_DONE & 0xFF;
+ data[3] = 1;
+ data[4] = (decoder_continue ? 0x80 : 0x00) |
+ (scene_reveal ? 0x40 : 0x00) |
+ (scene_tag & 0x0f);
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 5);
+}
+
+int en50221_app_mmi_download_reply(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint16_t object_id,
+ uint8_t download_reply_id)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t data[7];
+
+ data[0] = (TAG_DOWNLOAD_REPLY >> 16) & 0xFF;
+ data[1] = (TAG_DOWNLOAD_REPLY >> 8) & 0xFF;
+ data[2] = TAG_DOWNLOAD_REPLY & 0xFF;
+ data[3] = 3;
+ data[4] = object_id >> 8;
+ data[5] = object_id;
+ data[6] = download_reply_id;
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 7);
+}
+
+int en50221_app_mmi_answ(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t answ_id,
+ uint8_t *text,
+ uint32_t text_count)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t buf[10];
+
+ // set up the tag
+ buf[0] = (TAG_ANSWER >> 16) & 0xFF;
+ buf[1] = (TAG_ANSWER >> 8) & 0xFF;
+ buf[2] = TAG_ANSWER & 0xFF;
+
+ // encode the length field
+ struct iovec iov[2];
+ int length_field_len = 0;
+ int iov_count = 1;
+ if (answ_id == MMI_ANSW_ID_ANSWER) {
+ if ((length_field_len = asn_1_encode(text_count+1, buf+3, 3)) < 0) {
+ return -1;
+ }
+ buf[3+length_field_len] = answ_id;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 3+length_field_len+1;
+ iov[1].iov_base = text;
+ iov[1].iov_len = text_count;
+ iov_count=2;
+ } else {
+ buf[3] = 1;
+ buf[4] = answ_id;
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 5;
+ iov_count = 1;
+ }
+
+ // create the data and send it
+ return private->funcs->send_datav(private->funcs->arg, session_number, iov, iov_count);
+}
+
+int en50221_app_mmi_menu_answ(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t choice_ref)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ uint8_t data[5];
+
+ data[0] = (TAG_MENU_ANSWER >> 16) & 0xFF;
+ data[1] = (TAG_MENU_ANSWER >> 8) & 0xFF;
+ data[2] = TAG_MENU_ANSWER & 0xFF;
+ data[3] = 1;
+ data[4] = choice_ref;
+ return private->funcs->send_data(private->funcs->arg, session_number, data, 5);
+}
+
+int en50221_app_mmi_message(en50221_app_mmi mmi,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_mmi_private *private = (struct en50221_app_mmi_private *) mmi;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_CLOSE_MMI:
+ return en50221_app_mmi_parse_close(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_DISPLAY_CONTROL:
+ return en50221_app_mmi_parse_display_control(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_KEYPAD_CONTROL:
+ return en50221_app_mmi_parse_keypad_control(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_ENQUIRY:
+ return en50221_app_mmi_parse_enq(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_MENU_LAST:
+ return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 1, data+3, data_length-3);
+ case TAG_MENU_MORE:
+ return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 0, data+3, data_length-3);
+ case TAG_LIST_LAST:
+ return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 1, data+3, data_length-3);
+ case TAG_LIST_MORE:
+ return en50221_app_mmi_parse_list_menu(private, slot_id, session_number, tag, 0, data+3, data_length-3);
+ case TAG_SUBTITLE_SEGMENT_LAST:
+ return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 1, data+3, data_length-3);
+ case TAG_SUBTITLE_SEGMENT_MORE:
+ return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 0, data+3, data_length-3);
+ case TAG_SCENE_END_MARK:
+ return en50221_app_mmi_parse_scene_end_mark(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_SCENE_CONTROL:
+ return en50221_app_mmi_parse_scene_control(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_SUBTITLE_DOWNLOAD_LAST:
+ return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 1, data+3, data_length-3);
+ case TAG_SUBTITLE_DOWNLOAD_MORE:
+ return en50221_app_mmi_parse_subtitle(private, slot_id, session_number, tag, 0, data+3, data_length-3);
+ case TAG_FLUSH_DOWNLOAD:
+ return en50221_app_mmi_parse_flush_download(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+
+
+static int en50221_app_mmi_parse_close(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length < 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] > (data_length-1)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t cmd_id = data[1];
+ uint8_t delay = 0;
+ if (cmd_id == MMI_CLOSE_MMI_CMD_ID_DELAY) {
+ if (data[0] != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ delay = data[2];
+ }
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_mmi_close_callback cb = private->closecallback;
+ void *cb_arg = private->closecallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, cmd_id, delay);
+ }
+ return 0;
+}
+
+static int en50221_app_mmi_parse_display_control(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length < 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] > (data_length-1)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t cmd_id = data[1];
+ uint8_t mmi_mode = 0;
+ if (cmd_id == MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE) {
+ if (data[0] != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ mmi_mode = data[2];
+ }
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_mmi_display_control_callback cb = private->displaycontrolcallback;
+ void *cb_arg = private->displaycontrolcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, cmd_id, mmi_mode);
+ }
+ return 0;
+}
+
+static int en50221_app_mmi_parse_keypad_control(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length < 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // skip over the length field
+ data += length_field_len;
+
+ // extract the information
+ uint8_t cmd_id = data[0];
+ uint8_t *keycodes = data+1;
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_mmi_keypad_control_callback cb = private->keypadcontrolcallback;
+ void *cb_arg = private->keypadcontrolcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, cmd_id, keycodes, asn_data_length-1);
+ }
+ return 0;
+}
+
+static int en50221_app_mmi_parse_enq(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length < 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // skip over the length field
+ data += length_field_len;
+
+ // extract the information
+ uint8_t blind_answer = (data[0] & 0x01) ? 1 : 0;
+ uint8_t answer_length = data[1];
+ uint8_t *text = data+2;
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_mmi_enq_callback cb = private->enqcallback;
+ void *cb_arg = private->enqcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, blind_answer, answer_length, text, asn_data_length - 2);
+ }
+ return 0;
+}
+
+static int en50221_app_mmi_parse_list_menu(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number, uint32_t tag_id,
+ int more_last, uint8_t *data, uint32_t data_length)
+{
+ int result = 0;
+ uint8_t *text_flags = NULL;
+ struct en50221_app_mmi_text *text_data = NULL;
+ uint32_t i;
+ uint8_t text_count = 0;
+
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // skip over the length field
+ data += length_field_len;
+
+ // defragment
+ pthread_mutex_lock(&private->lock);
+ uint8_t *outdata;
+ uint32_t outdata_length;
+ int dfstatus = en50221_app_mmi_defragment(private, session_number, tag_id, more_last,
+ data, asn_data_length,
+ &outdata, &outdata_length);
+ if (dfstatus <= 0) {
+ pthread_mutex_unlock(&private->lock);
+ return dfstatus;
+ }
+ data = outdata;
+ data_length = outdata_length;
+
+ // check the reassembled data length
+ if (data_length < 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ pthread_mutex_unlock(&private->lock);
+ result = -1;
+ goto exit_cleanup;
+ }
+
+ // now, parse the data
+ uint8_t choice_nb = data[0];
+ text_count = choice_nb + 3;
+ if (choice_nb == 0xff) text_count = 3;
+ data++;
+ data_length--;
+
+ // variables for extracted text state
+ text_flags = alloca(text_count);
+ if (text_flags == NULL) {
+ pthread_mutex_unlock(&private->lock);
+ result = -1;
+ goto exit_cleanup;
+ }
+ memset(text_flags, 0, text_count);
+ text_data = (struct en50221_app_mmi_text*) alloca(sizeof(struct en50221_app_mmi_text) * text_count);
+ if (text_data == NULL) {
+ pthread_mutex_unlock(&private->lock);
+ result = -1;
+ goto exit_cleanup;
+ }
+ memset(text_data, 0, sizeof(struct en50221_app_mmi_text) * text_count);
+
+ // extract the text!
+ for(i=0; i<text_count; i++) {
+ uint32_t consumed = 0;
+ int cur_status = en50221_app_mmi_defragment_text(data, data_length,
+ &text_data[i].text, &text_data[i].text_length,
+ &consumed);
+ if (cur_status < 0) {
+ pthread_mutex_unlock(&private->lock);
+ result = -1;
+ goto exit_cleanup;
+ }
+
+ text_flags[i] = cur_status;
+ data += consumed;
+ data_length -= consumed;
+ }
+
+ // work out what to pass to the user
+ struct en50221_app_mmi_text *text_data_for_user =
+ (struct en50221_app_mmi_text*) alloca(sizeof(struct en50221_app_mmi_text) * text_count);
+ if (text_data_for_user == NULL) {
+ result = -1;
+ goto exit_cleanup;
+ }
+ memcpy(text_data_for_user, text_data, sizeof(struct en50221_app_mmi_text) * text_count);
+ struct en50221_app_mmi_text *text_ptr = NULL;
+ if (text_count > 3) {
+ text_ptr = &text_data_for_user[3];
+ }
+ uint8_t *items_raw = NULL;
+ uint32_t items_raw_length = 0;
+ if (choice_nb == 0xff) {
+ items_raw = data;
+ items_raw_length = data_length;
+ }
+
+ // do callback
+ result = 0;
+ switch(tag_id) {
+ case TAG_MENU_LAST:
+ {
+ en50221_app_mmi_menu_callback cb = private->menucallback;
+ void *cb_arg = private->menucallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ result = cb(cb_arg, slot_id, session_number,
+ &text_data_for_user[0],
+ &text_data_for_user[1],
+ &text_data_for_user[2],
+ text_count-3,
+ text_ptr,
+ items_raw_length,
+ items_raw);
+ }
+ break;
+ }
+
+ case TAG_LIST_LAST:
+ {
+ en50221_app_mmi_list_callback cb = private->listcallback;
+ void *cb_arg = private->listcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ result = cb(cb_arg, slot_id, session_number,
+ &text_data_for_user[0],
+ &text_data_for_user[1],
+ &text_data_for_user[2],
+ text_count-3,
+ text_ptr,
+ items_raw_length,
+ items_raw);
+ }
+ break;
+ }
+
+ default:
+ pthread_mutex_unlock(&private->lock);
+ break;
+ }
+
+exit_cleanup:
+ if ((dfstatus == 2) && outdata) free(outdata);
+ if (text_flags && text_data) {
+ for(i=0; i< text_count; i++) {
+ if ((text_flags[i] == 2) && text_data[i].text) {
+ free(text_data[i].text);
+ }
+ }
+ }
+ return result;
+}
+
+static int en50221_app_mmi_parse_subtitle(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number, uint32_t tag_id,
+ int more_last, uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // skip over the length field
+ data += length_field_len;
+
+ // defragment
+ pthread_mutex_lock(&private->lock);
+ uint8_t *outdata;
+ uint32_t outdata_length;
+ int dfstatus = en50221_app_mmi_defragment(private, session_number, tag_id, more_last,
+ data, asn_data_length,
+ &outdata, &outdata_length);
+ if (dfstatus <= 0) {
+ pthread_mutex_unlock(&private->lock);
+ return dfstatus;
+ }
+
+ // do callback
+ int cbstatus = 0;
+ switch(tag_id) {
+ case TAG_SUBTITLE_SEGMENT_LAST:
+ {
+ en50221_app_mmi_subtitle_segment_callback cb = private->subtitlesegmentcallback;
+ void *cb_arg = private->subtitlesegmentcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ cbstatus = cb(cb_arg, slot_id, session_number, outdata, outdata_length);
+ }
+ break;
+ }
+
+ case TAG_SUBTITLE_DOWNLOAD_LAST:
+ {
+ en50221_app_mmi_subtitle_download_callback cb = private->subtitledownloadcallback;
+ void *cb_arg = private->subtitledownloadcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ cbstatus = cb(cb_arg, slot_id, session_number, outdata, outdata_length);
+ }
+ break;
+ }
+ }
+
+ // free the data returned by the defragment call if asked to
+ if (dfstatus == 2) {
+ free(outdata);
+ }
+
+ // done
+ return cbstatus;
+}
+
+static int en50221_app_mmi_parse_scene_end_mark(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t flags = data[1];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_mmi_scene_end_mark_callback cb = private->sceneendmarkcallback;
+ void *cb_arg = private->sceneendmarkcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number,
+ (flags & 0x80) ? 1 : 0,
+ (flags & 0x40) ? 1 : 0,
+ (flags & 0x20) ? 1 : 0,
+ flags & 0x0f);
+ }
+ return 0;
+}
+
+static int en50221_app_mmi_parse_scene_control(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t flags = data[1];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_mmi_scene_control_callback cb = private->scenecontrolcallback;
+ void *cb_arg = private->scenecontrolcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number,
+ (flags & 0x80) ? 1 : 0,
+ (flags & 0x40) ? 1 : 0,
+ flags & 0x0f);
+ }
+ return 0;
+}
+
+static int en50221_app_mmi_parse_flush_download(struct en50221_app_mmi_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // validate data
+ if (data_length != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 0) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_mmi_flush_download_callback cb = private->flushdownloadcallback;
+ void *cb_arg = private->flushdownloadcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number);
+ }
+ return 0;
+}
+
+static int en50221_app_mmi_defragment(struct en50221_app_mmi_private *private,
+ uint16_t session_number,
+ uint32_t tag_id,
+ int more_last,
+ uint8_t *indata,
+ uint32_t indata_length,
+ uint8_t **outdata,
+ uint32_t *outdata_length)
+{
+ struct en50221_app_mmi_session *cur_s = private->sessions;
+ while(cur_s) {
+ if (cur_s->session_number == session_number)
+ break;
+ cur_s=cur_s->next;
+ }
+
+ // more data is still to come
+ if (!more_last) {
+ // if there was no previous session, create one
+ if (cur_s == NULL) {
+ cur_s = malloc(sizeof(struct en50221_app_mmi_session));
+ if (cur_s == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ return -1;
+ }
+ cur_s->session_number = session_number;
+ cur_s->menu_block_chain = NULL;
+ cur_s->menu_block_length = 0;
+ cur_s->list_block_chain = NULL;
+ cur_s->list_block_length = 0;
+ cur_s->subtitlesegment_block_chain = NULL;
+ cur_s->subtitlesegment_block_length = 0;
+ cur_s->subtitledownload_block_chain = NULL;
+ cur_s->subtitledownload_block_length = 0;
+ cur_s->next = private->sessions;
+ private->sessions = cur_s;
+ }
+
+ // find the block/block_length to use
+ uint8_t **block_chain;
+ uint32_t *block_length;
+ switch(tag_id) {
+ case TAG_MENU_LAST:
+ case TAG_MENU_MORE:
+ block_chain = &cur_s->menu_block_chain;
+ block_length = &cur_s->menu_block_length;
+ break;
+ case TAG_LIST_LAST:
+ case TAG_LIST_MORE:
+ block_chain = &cur_s->list_block_chain;
+ block_length = &cur_s->list_block_length;
+ break;
+ case TAG_SUBTITLE_SEGMENT_LAST:
+ case TAG_SUBTITLE_SEGMENT_MORE:
+ block_chain = &cur_s->subtitlesegment_block_chain;
+ block_length = &cur_s->subtitlesegment_block_length;
+ break;
+ case TAG_SUBTITLE_DOWNLOAD_LAST:
+ case TAG_SUBTITLE_DOWNLOAD_MORE:
+ block_chain = &cur_s->subtitledownload_block_chain;
+ block_length = &cur_s->subtitledownload_block_length;
+ break;
+ default:
+ return -1;
+ }
+
+ // append the data
+ uint8_t *new_data = realloc(*block_chain, *block_length + indata_length);
+ if (new_data == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ return -1;
+ }
+ memcpy(new_data + *block_length, indata, indata_length);
+ *block_chain = new_data;
+ *block_length += indata_length;
+
+ // success, but block not complete yet
+ return 0;
+ }
+
+ // we hit the last of a possible chain of fragments
+ if (cur_s != NULL) {
+ // find the block/block_length to use
+ uint8_t **block_chain;
+ uint32_t *block_length;
+ switch(tag_id) {
+ case TAG_MENU_LAST:
+ case TAG_MENU_MORE:
+ block_chain = &cur_s->menu_block_chain;
+ block_length = &cur_s->menu_block_length;
+ break;
+ case TAG_LIST_LAST:
+ case TAG_LIST_MORE:
+ block_chain = &cur_s->list_block_chain;
+ block_length = &cur_s->list_block_length;
+ break;
+ case TAG_SUBTITLE_SEGMENT_LAST:
+ case TAG_SUBTITLE_SEGMENT_MORE:
+ block_chain = &cur_s->subtitlesegment_block_chain;
+ block_length = &cur_s->subtitlesegment_block_length;
+ break;
+ case TAG_SUBTITLE_DOWNLOAD_LAST:
+ case TAG_SUBTITLE_DOWNLOAD_MORE:
+ block_chain = &cur_s->subtitledownload_block_chain;
+ block_length = &cur_s->subtitledownload_block_length;
+ break;
+ default:
+ return -1;
+ }
+
+ // we have a preceding fragment - need to append
+ uint8_t *new_data = realloc(*block_chain, *block_length + indata_length);
+ if (new_data == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ return -1;
+ }
+ memcpy(new_data + *block_length, indata, indata_length);
+ *outdata_length = *block_length + indata_length;
+ *outdata = new_data;
+ *block_chain = NULL;
+ *block_length = 0;
+
+ // success, and indicate to free the block when done
+ return 2;
+ }
+
+ // success, but indicate it is not to be freed
+ *outdata_length = indata_length;
+ *outdata = indata;
+ return 1;
+}
+
+static int en50221_app_mmi_defragment_text(uint8_t *data,
+ uint32_t data_length,
+ uint8_t **outdata,
+ uint32_t *outdata_length,
+ uint32_t *outconsumed)
+{
+ uint8_t *text = NULL;
+ uint32_t text_length = 0;
+ uint32_t consumed = 0;
+
+ while(1) {
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Short data\n");
+ if (text) free(text);
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+ data += 3;
+ data_length -=3;
+ consumed += 3;
+
+ // get the length of the data and adjust
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ if (text) free(text);
+ return -1;
+ }
+ data += length_field_len;
+ data_length -= length_field_len;
+ consumed += length_field_len;
+
+ // deal with the tags
+ if (tag == TAG_TEXT_LAST) {
+ if (text == NULL) {
+ *outdata = data;
+ *outdata_length = asn_data_length;
+ *outconsumed = consumed + asn_data_length;
+ return 1;
+ } else {
+ // append the data
+ uint8_t *new_text = realloc(text, text_length + asn_data_length);
+ if (new_text == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ if (text) free(text);
+ return -1;
+ }
+ memcpy(new_text + text_length, data, asn_data_length);
+ *outdata = new_text;
+ *outdata_length = text_length + asn_data_length;
+ *outconsumed = consumed + asn_data_length;
+ return 2;
+ }
+
+ } else if (tag == TAG_TEXT_MORE) {
+ // append the data
+ uint8_t *new_text = realloc(text, text_length + asn_data_length);
+ if (new_text == NULL) {
+ print(LOG_LEVEL, ERROR, 1, "Ran out of memory\n");
+ if (text) free(text);
+ return -1;
+ }
+ memcpy(new_text + text_length, data, asn_data_length);
+ text = new_text;
+ text_length += asn_data_length;
+
+ // consume the data
+ data += asn_data_length;
+ data_length -= asn_data_length;
+ consumed += asn_data_length;
+ } else {
+ // unknown tag
+ print(LOG_LEVEL, ERROR, 1, "Unknown MMI text tag\n");
+ if (text) free(text);
+ return -1;
+ }
+ }
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h
new file mode 100644
index 0000000..b5e3abf
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_mmi.h
@@ -0,0 +1,571 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_mmi_H__
+#define __EN50221_APPLICATION_mmi_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EN50221_APP_MMI_RESOURCEID MKRID(64,1,1)
+
+#define MMI_CLOSE_MMI_CMD_ID_IMMEDIATE 0x00
+#define MMI_CLOSE_MMI_CMD_ID_DELAY 0x01
+
+#define MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE 0x01
+#define MMI_DISPLAY_CONTROL_CMD_ID_GET_DISPLAY_CHAR_TABLES 0x02
+#define MMI_DISPLAY_CONTROL_CMD_ID_GET_INPUT_CHAR_TABLES 0x03
+#define MMI_DISPLAY_CONTROL_CMD_ID_GET_OVERLAY_GFX_CHARACTERISTICS 0x04
+#define MMI_DISPLAY_CONTROL_CMD_ID_GET_FULLSCREEN_GFX_CHARACTERISTICS 0x05
+
+#define MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK 0x01
+#define MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES 0x02
+#define MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES 0x03
+#define MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS 0x04
+#define MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS 0x05
+#define MMI_DISPLAY_REPLY_ID_UNKNOWN_CMD_ID 0xF0
+#define MMI_DISPLAY_REPLY_ID_UNKNOWN_MMI_MODE 0xF1
+#define MMI_DISPLAY_REPLY_ID_UNKNOWN_CHAR_TABLE 0xF2
+
+#define MMI_MODE_HIGH_LEVEL 0x01
+#define MMI_MODE_LOW_LEVEL_OVERLAY_GFX 0x02
+#define MMI_MODE_LOW_LEVEL_FULLSCREEN_GFX 0x03
+
+#define MMI_KEYPAD_CONTROL_CMD_ID_INTERCEPT_ALL 0x01
+#define MMI_KEYPAD_CONTROL_CMD_ID_IGNORE_ALL 0x02
+#define MMI_KEYPAD_CONTROL_CMD_ID_INTERCEPT_SELECTED 0x03
+#define MMI_KEYPAD_CONTROL_CMD_ID_IGNORE_SELECTED 0x04
+#define MMI_KEYPAD_CONTROL_CMD_ID_REJECT_KEYPRESS 0x05
+
+#define MMI_GFX_VIDEO_RELATION_NONE 0x00
+#define MMI_GFX_VIDEO_RELATION_MATCHES_EXACTLY 0x07
+
+#define MMI_DISPLAY_MESSAGE_ID_OK 0x00
+#define MMI_DISPLAY_MESSAGE_ID_ERROR 0x01
+#define MMI_DISPLAY_MESSAGE_ID_OUT_OF_MEMORY 0x02
+#define MMI_DISPLAY_MESSAGE_ID_SUBTITLE_SYNTAX_ERROR 0x03
+#define MMI_DISPLAY_MESSAGE_ID_UNDEFINED_REGION 0x04
+#define MMI_DISPLAY_MESSAGE_ID_UNDEFINED_CLUT 0x05
+#define MMI_DISPLAY_MESSAGE_ID_UNDEFINED_OBJECT 0x06
+#define MMI_DISPLAY_MESSAGE_ID_INCOMPATABLE_OBJECT 0x07
+#define MMI_DISPLAY_MESSAGE_ID_UNKNOWN_CHARACTER 0x08
+#define MMI_DISPLAY_MESSAGE_ID_DISPLAY_CHANGED 0x09
+
+#define MMI_DOWNLOAD_REPLY_ID_OK 0x00
+#define MMI_DOWNLOAD_REPLY_ID_NOT_OBJECT_SEGMENT 0x01
+#define MMI_DOWNLOAD_REPLY_ID_OUT_OF_MEMORY 0x02
+
+#define MMI_ANSW_ID_CANCEL 0x00
+#define MMI_ANSW_ID_ANSWER 0x01
+
+/**
+ * A pixel depth as supplied with display_reply details
+ */
+struct en50221_app_mmi_pixel_depth {
+ uint8_t display_depth;
+ uint8_t pixels_per_byte;
+ uint8_t region_overhead;
+};
+
+/**
+ * Details returned with a display_reply
+ */
+struct en502221_app_mmi_display_reply_details {
+ union {
+ struct {
+ uint16_t width;
+ uint16_t height;
+ uint8_t aspect_ratio;
+ uint8_t gfx_relation_to_video; /* one of MMI_GFX_VIDEO_RELATION_* */
+ uint8_t multiple_depths;
+ uint16_t display_bytes;
+ uint8_t composition_buffer_bytes;
+ uint8_t object_cache_bytes;
+ uint8_t num_pixel_depths;
+ struct en50221_app_mmi_pixel_depth *pixel_depths;
+ } gfx; /* MMI_DISPLAY_REPLY_ID_LIST_OVERLAY_GFX_CHARACTERISTICS or
+ MMI_DISPLAY_REPLY_ID_LIST_FULLSCREEN_GFX_CHARACTERISTICS */
+
+ struct {
+ uint32_t table_length;
+ uint8_t *table;
+ } char_table; /* MMI_DISPLAY_REPLY_ID_LIST_DISPLAY_CHAR_TABLES or
+ MMI_DISPLAY_REPLY_ID_LIST_INPUT_CHAR_TABLES */
+
+ struct {
+ uint8_t mmi_mode; /* one of the MMI_MODE_* values */
+ } mode_ack; /* for MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK */
+ } u;
+};
+
+/**
+ * Pointer to a text string.
+ */
+struct en50221_app_mmi_text {
+ uint8_t *text;
+ uint32_t text_length;
+};
+
+/**
+ * Type definition for close - called when we receive an mmi_close from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param cmd_id One of the MMI_CLOSE_MMI_CMD_ID_* values.
+ * @param delay Delay supplied with MMI_CLOSE_MMI_CMD_ID_DELAY.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_close_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t cmd_id, uint8_t delay);
+
+/**
+ * Type definition for display_control callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param cmd_id One of the MMI_DISPLAY_CONTROL_CMD_ID_* values.
+ * @param delay One of the MMI_MODE_* values.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_display_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t cmd_id, uint8_t mmi_mode);
+
+/**
+ * Type definition for keypad_control callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param cmd_id One of the MMI_KEYPAD_CONTROL_CMD_ID_* values.
+ * @param key_codes Pointer to the key codes.
+ * @param key_codes_count Number of key codes.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_keypad_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t cmd_id, uint8_t *key_codes, uint32_t key_codes_count);
+
+/**
+ * Type definition for subtitle_segment callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param segment Pointer to the segment data.
+ * @param segment_size Size of segment data.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_subtitle_segment_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t *segment, uint32_t segment_size);
+
+/**
+ * Type definition for scene_end_mark callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param decoder_continue_flag
+ * @param scene_reveal_flag
+ * @param send_scene_done
+ * @param scene_tag
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_scene_end_mark_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t decoder_continue_flag, uint8_t scene_reveal_flag,
+ uint8_t send_scene_done, uint8_t scene_tag);
+
+/**
+ * Type definition for scene_control callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param decoder_continue_flag
+ * @param scene_reveal_flag
+ * @param scene_tag
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_scene_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t decoder_continue_flag, uint8_t scene_reveal_flag,
+ uint8_t scene_tag);
+
+/**
+ * Type definition for subtitle_download callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param segment Pointer to the segment data.
+ * @param segment_size Size of segment data.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_subtitle_download_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t *segment, uint32_t segment_size);
+
+/**
+ * Type definition for flush_download callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_flush_download_callback)(void *arg, uint8_t slot_id, uint16_t session_number);
+
+/**
+ * Type definition for enq callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param blind_answer 1=>Obscure text input in some manner,
+ * @param expected_answer_length Expected max number of characters to be returned.
+ * @param text Pointer to the text data.
+ * @param text_size Size of text data.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_enq_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t blind_answer, uint8_t expected_answer_length,
+ uint8_t *text, uint32_t text_size);
+
+/**
+ * Type definition for menu callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param title Title text.
+ * @param sub_title Sub-Title text.
+ * @param bottom Bottom text.
+ * @param item_count Number of text elements in items.
+ * @param items Pointer to array of en50221_app_mmi_text structures which are standard menu choices,
+ * @param item_raw_length Length of item raw data.
+ * @param items_raw If nonstandard items were supplied, pointer to their data.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_menu_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ struct en50221_app_mmi_text *title,
+ struct en50221_app_mmi_text *sub_title,
+ struct en50221_app_mmi_text *bottom,
+ uint32_t item_count, struct en50221_app_mmi_text *items,
+ uint32_t item_raw_length, uint8_t *items_raw);
+
+/**
+ * Type definition for list callback.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param title Title text.
+ * @param sub_title Sub-Title text.
+ * @param bottom Bottom text.
+ * @param item_count Number of text elements in items.
+ * @param items Pointer to array of en50221_app_mmi_text structures which are standard menu choices,
+ * @param item_raw_length Length of item raw data.
+ * @param items_raw If nonstandard items were supplied, pointer to their data.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_mmi_list_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ struct en50221_app_mmi_text *title,
+ struct en50221_app_mmi_text *sub_title,
+ struct en50221_app_mmi_text *bottom,
+ uint32_t item_count, struct en50221_app_mmi_text *items,
+ uint32_t item_raw_length, uint8_t *items_raw);
+
+/**
+ * Opaque type representing a mmi resource.
+ */
+typedef void *en50221_app_mmi;
+
+/**
+ * Create an instance of the mmi resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_mmi en50221_app_mmi_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the mmi resource.
+ *
+ * @param mmi Instance to destroy.
+ */
+extern void en50221_app_mmi_destroy(en50221_app_mmi mmi);
+
+/**
+ * Informs the mmi object that a session to it has been closed - cleans up internal state.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number The session concerned.
+ */
+extern void en50221_app_mmi_clear_session(en50221_app_mmi mmi, uint16_t session_number);
+
+/**
+ * Register the callback for when we receive an mmi_close request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_close_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_close_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a display control request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_display_control_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_display_control_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a keypad control request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_keypad_control_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_keypad_control_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a subtitle segment request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_subtitle_segment_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_subtitle_segment_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a scene end mark request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_scene_end_mark_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_scene_end_mark_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a scene control request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_scene_control_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_scene_control_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a subtitle download request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_subtitle_download_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_subtitle_download_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a flush download request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_flush_download_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_flush_download_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive an enq request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_enq_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_enq_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a menu request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_menu_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_menu_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a list request.
+ *
+ * @param mmi mmi resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_mmi_register_list_callback(en50221_app_mmi mmi,
+ en50221_app_mmi_list_callback callback, void *arg);
+
+/**
+ * Send an mmi_close to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param cmd_id One of the MMI_CLOSE_MMI_CMD_ID_* values.
+ * @param delay Delay to use if MMI_CLOSE_MMI_CMD_ID_DELAY specified.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_close(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t cmd_id,
+ uint8_t delay);
+
+/**
+ * Send a display_reply to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param reply_id One of the MMI_DISPLAY_REPLY_ID_* values.
+ * @param details The details of the reply - can be NULL if the chosen reply_id does not need it.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_display_reply(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t reply_id,
+ struct en502221_app_mmi_display_reply_details *details);
+
+/**
+ * Send a keypress to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param keycode The keycode.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_keypress(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t keycode);
+
+/**
+ * Send a display message to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param display_message_id One of the MMI_DISPLAY_MESSAGE_ID_* values.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_display_message(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t display_message_id);
+
+/**
+ * Send a scene done message to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param decoder_continue Copy of flag in scene_end_mark.
+ * @param scene_reveal Copy of flag in scene_end_mark.
+ * @param scene_tag Scene tag this responds to.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_scene_done(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t decoder_continue,
+ uint8_t scene_reveal,
+ uint8_t scene_tag);
+
+/**
+ * Send a download reply to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param object_id Object id.
+ * @param download_reply_id One of the MMI_DOWNLOAD_REPLY_ID_* values.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_download_reply(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint16_t object_id,
+ uint8_t download_reply_id);
+
+/**
+ * Send an answ to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param answ_id One of the MMI_ANSW_ID_* values.
+ * @param text The text if MMI_ANSW_ID_ANSWER.
+ * @param text_count Length of text.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_answ(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t answ_id,
+ uint8_t *text,
+ uint32_t text_count);
+
+/**
+ * Send a menu answ to the cam.
+ *
+ * @param mmi mmi resource instance.
+ * @param session_number Session number to send it on.
+ * @param choice_ref Option chosen by user (0=>canceled).
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_menu_answ(en50221_app_mmi mmi,
+ uint16_t session_number,
+ uint8_t choice_ref);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param mmi mmi instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_mmi_message(en50221_app_mmi mmi,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c
new file mode 100644
index 0000000..7c57aba
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.c
@@ -0,0 +1,294 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include <libucsi/endianops.h>
+#include "en50221_app_rm.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_rm_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_rm_enq_callback enqcallback;
+ void *enqcallback_arg;
+
+ en50221_app_rm_reply_callback replycallback;
+ void *replycallback_arg;
+
+ en50221_app_rm_changed_callback changedcallback;
+ void *changedcallback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+static int en50221_app_rm_parse_profile_change(struct en50221_app_rm_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+en50221_app_rm en50221_app_rm_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_rm_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_rm_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->enqcallback = NULL;
+ private->replycallback = NULL;
+ private->changedcallback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_rm_destroy(en50221_app_rm rm)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_rm_register_enq_callback(en50221_app_rm rm,
+ en50221_app_rm_enq_callback callback, void *arg)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+
+ pthread_mutex_lock(&private->lock);
+ private->enqcallback = callback;
+ private->enqcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_rm_register_reply_callback(en50221_app_rm rm,
+ en50221_app_rm_reply_callback callback, void *arg)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+
+ pthread_mutex_lock(&private->lock);
+ private->replycallback = callback;
+ private->replycallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_rm_register_changed_callback(en50221_app_rm rm,
+ en50221_app_rm_changed_callback callback, void *arg)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+
+ pthread_mutex_lock(&private->lock);
+ private->changedcallback = callback;
+ private->changedcallback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_rm_enq(en50221_app_rm rm, uint16_t session_number)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+ uint8_t buf[4];
+
+ // set up the tag
+ buf[0] = (TAG_PROFILE_ENQUIRY >> 16) & 0xFF;
+ buf[1] = (TAG_PROFILE_ENQUIRY >> 8) & 0xFF;
+ buf[2] = TAG_PROFILE_ENQUIRY & 0xFF;
+ buf[3] = 0;
+
+ // create the data and send it
+ return private->funcs->send_data(private->funcs->arg, session_number, buf, 4);
+}
+
+int en50221_app_rm_reply(en50221_app_rm rm, uint16_t session_number,
+ uint32_t resource_id_count,
+ uint32_t *resource_ids)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+ uint8_t buf[10];
+
+ // set up the tag
+ buf[0] = (TAG_PROFILE >> 16) & 0xFF;
+ buf[1] = (TAG_PROFILE >> 8) & 0xFF;
+ buf[2] = TAG_PROFILE & 0xFF;
+
+ // encode the length field
+ int length_field_len;
+ if ((length_field_len = asn_1_encode(resource_id_count*4, buf+3, 3)) < 0) {
+ return -1;
+ }
+
+ // copy the data and byteswap it
+ uint32_t *copy_resource_ids = alloca(4*resource_id_count);
+ if (copy_resource_ids == NULL) {
+ return -1;
+ }
+ uint8_t *data = (uint8_t*) copy_resource_ids;
+ memcpy(data, resource_ids, resource_id_count*4);
+ uint32_t i;
+ for(i=0; i<resource_id_count; i++) {
+ bswap32(data);
+ data+=4;
+ }
+
+ // build the iovecs
+ struct iovec iov[2];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 3+length_field_len;
+ iov[1].iov_base = (uint8_t*) copy_resource_ids;
+ iov[1].iov_len = resource_id_count * 4;
+
+ // create the data and send it
+ return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2);
+}
+
+int en50221_app_rm_changed(en50221_app_rm rm, uint16_t session_number)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+ uint8_t buf[4];
+
+ // set up the tag
+ buf[0] = (TAG_PROFILE_CHANGE >> 16) & 0xFF;
+ buf[1] = (TAG_PROFILE_CHANGE >> 8) & 0xFF;
+ buf[2] = TAG_PROFILE_CHANGE & 0xFF;
+ buf[3] = 0;
+
+ // create the data and send it
+ return private->funcs->send_data(private->funcs->arg, session_number, buf, 4);
+}
+
+int en50221_app_rm_message(en50221_app_rm rm,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_rm_private *private = (struct en50221_app_rm_private *) rm;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ // dispatch it
+ switch(tag)
+ {
+ case TAG_PROFILE_ENQUIRY:
+ return en50221_app_rm_parse_profile_enq(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_PROFILE:
+ return en50221_app_rm_parse_profile_reply(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_PROFILE_CHANGE:
+ return en50221_app_rm_parse_profile_change(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+static int en50221_app_rm_parse_profile_enq(struct en50221_app_rm_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ (void)data;
+ (void)data_length;
+
+ pthread_mutex_lock(&private->lock);
+ en50221_app_rm_enq_callback cb = private->enqcallback;
+ void *cb_arg = private->enqcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number);
+ }
+ return 0;
+}
+
+static int en50221_app_rm_parse_profile_reply(struct en50221_app_rm_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t resources_count = asn_data_length / 4;
+ uint32_t *resource_ids = (uint32_t*) (data+length_field_len);
+ data += length_field_len;
+
+ // byteswap it
+ uint32_t i;
+ for(i=0; i< resources_count; i++) {
+ bswap32(data);
+ data+=4;
+ }
+
+ // inform observer
+ pthread_mutex_lock(&private->lock);
+ en50221_app_rm_reply_callback cb = private->replycallback;
+ void *cb_arg = private->replycallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, resources_count, resource_ids);
+ }
+ return 0;
+}
+
+static int en50221_app_rm_parse_profile_change(struct en50221_app_rm_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ (void)data;
+ (void)data_length;
+
+ pthread_mutex_lock(&private->lock);
+ en50221_app_rm_changed_callback cb = private->changedcallback;
+ void *cb_arg = private->changedcallback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h
new file mode 100644
index 0000000..696065d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_rm.h
@@ -0,0 +1,178 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_RM_H__
+#define __EN50221_APPLICATION_RM_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EN50221_APP_RM_RESOURCEID MKRID(1,1,1)
+
+/**
+ * Type definition for profile_enq callback function - called when we receive
+ * a profile_enq from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_rm_enq_callback)(void *arg, uint8_t slot_id, uint16_t session_number);
+
+/**
+ * Type definition for profile_reply callback function - called when we receive
+ * a profile_reply from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id_count Number of resource_ids.
+ * @param resource_ids The resource ids themselves.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_rm_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint32_t resource_id_count,
+ uint32_t *resource_ids);
+/**
+ * Type definition for profile_changed callback function - called when we receive
+ * a profile_changed from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_rm_changed_callback)(void *arg, uint8_t slot_id, uint16_t session_number);
+
+
+
+/**
+ * Opaque type representing a resource manager.
+ */
+typedef void *en50221_app_rm;
+
+/**
+ * Create an instance of the resource manager.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_rm en50221_app_rm_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the resource manager.
+ *
+ * @param rm Instance to destroy.
+ */
+extern void en50221_app_rm_destroy(en50221_app_rm rm);
+
+/**
+ * Register the callback for when we receive a profile_enq from a CAM.
+ *
+ * @param rm Resource manager instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_rm_register_enq_callback(en50221_app_rm rm,
+ en50221_app_rm_enq_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a profile_reply from a CAM.
+ *
+ * @param rm Resource manager instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_rm_register_reply_callback(en50221_app_rm rm,
+ en50221_app_rm_reply_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive a profile_changed from a CAM.
+ *
+ * @param rm Resource manager instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_rm_register_changed_callback(en50221_app_rm rm,
+ en50221_app_rm_changed_callback callback, void *arg);
+
+/**
+ * Send a profile_enq to a CAM.
+ *
+ * @param rm Resource manager resource instance.
+ * @param session_number Session number to send it on.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_rm_enq(en50221_app_rm rm, uint16_t session_number);
+
+/**
+ * Send a profile_reply to a CAM.
+ *
+ * @param rm Resource manager resource instance.
+ * @param session_number Session number to send it on.
+ * @param resource_id_count Number of resource ids.
+ * @param resource_ids The resource IDs themselves
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_rm_reply(en50221_app_rm rm, uint16_t session_number,
+ uint32_t resource_id_count,
+ uint32_t *resource_ids);
+
+/**
+ * Send a profile_changed to a CAM.
+ *
+ * @param rm Resource manager resource instance.
+ * @param session_number Session number to send it on.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_rm_changed(en50221_app_rm rm, uint16_t session_number);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param rm rm instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_rm_message(en50221_app_rm rm,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c
new file mode 100644
index 0000000..83015ae
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.c
@@ -0,0 +1,293 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include "en50221_app_smartcard.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_smartcard_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_smartcard_command_callback command_callback;
+ void *command_callback_arg;
+
+ en50221_app_smartcard_send_callback send_callback;
+ void *send_callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+en50221_app_smartcard en50221_app_smartcard_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_smartcard_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_smartcard_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->command_callback = NULL;
+ private->send_callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_smartcard_destroy(en50221_app_smartcard smartcard)
+{
+ struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_smartcard_register_command_callback(en50221_app_smartcard smartcard,
+ en50221_app_smartcard_command_callback callback, void *arg)
+{
+ struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard;
+
+ pthread_mutex_lock(&private->lock);
+ private->command_callback = callback;
+ private->command_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+void en50221_app_smartcard_register_send_callback(en50221_app_smartcard smartcard,
+ en50221_app_smartcard_send_callback callback, void *arg)
+{
+ struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard;
+
+ pthread_mutex_lock(&private->lock);
+ private->send_callback = callback;
+ private->send_callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_smartcard_command_reply(en50221_app_smartcard smartcard,
+ uint16_t session_number,
+ uint8_t reply_id,
+ uint8_t status,
+ uint8_t *data,
+ uint32_t data_length)
+{
+ struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard;
+ uint8_t hdr[10];
+ struct iovec iovec[2];
+ int iov_count = 0;
+
+ // the tag
+ hdr[0] = (TAG_SMARTCARD_REPLY >> 16) & 0xFF;
+ hdr[1] = (TAG_SMARTCARD_REPLY >> 8) & 0xFF;
+ hdr[2] = TAG_SMARTCARD_REPLY & 0xFF;
+
+ // the rest of the data
+ if (reply_id == SMARTCARD_REPLY_ID_ANSW_TO_RESET) {
+ // encode the length field
+ int length_field_len;
+ if ((length_field_len = asn_1_encode(data_length+2, data+3, 3)) < 0) {
+ return -1;
+ }
+
+ // the rest of the header
+ hdr[3+length_field_len] = reply_id;
+ hdr[3+length_field_len+1] = status;
+ iovec[0].iov_base = hdr;
+ iovec[0].iov_len = 3+length_field_len+2;
+
+ // the data
+ iovec[1].iov_base = data;
+ iovec[1].iov_len = data_length;
+ iov_count = 2;
+ } else {
+ hdr[3] = 2;
+ hdr[4] = reply_id;
+ hdr[5] = status;
+ iovec[0].iov_base = data;
+ iovec[0].iov_len = 6;
+ iov_count = 1;
+ }
+
+ return private->funcs->send_datav(private->funcs->arg, session_number, iovec, iov_count);
+}
+
+int en50221_app_smartcard_receive(en50221_app_smartcard smartcard,
+ uint16_t session_number,
+ uint8_t *data,
+ uint32_t data_length,
+ uint8_t SW1,
+ uint8_t SW2)
+{
+ struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard;
+ uint8_t buf[10];
+ uint8_t trailer[10];
+
+ // set up the tag
+ buf[0] = (TAG_SMARTCARD_RCV >> 16) & 0xFF;
+ buf[1] = (TAG_SMARTCARD_RCV >> 8) & 0xFF;
+ buf[2] = TAG_SMARTCARD_RCV & 0xFF;
+
+ // encode the length field
+ int length_field_len;
+ if ((length_field_len = asn_1_encode(data_length+2, buf+3, 3)) < 0) {
+ return -1;
+ }
+
+ // set up the trailer
+ trailer[0] = SW1;
+ trailer[1] = SW2;
+
+ // build the iovecs
+ struct iovec iov[3];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 3+length_field_len;
+ iov[1].iov_base = data;
+ iov[1].iov_len = data_length;
+ iov[2].iov_base = trailer;
+ iov[2].iov_len = 2;
+
+ // create the data and send it
+ return private->funcs->send_datav(private->funcs->arg, session_number, iov, 3);
+}
+
+int en50221_app_smartcard_message(en50221_app_smartcard smartcard,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_smartcard_private *private = (struct en50221_app_smartcard_private *) smartcard;
+ (void)resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_SMARTCARD_COMMAND:
+ return en50221_app_smartcard_parse_command(private, slot_id, session_number, data+3, data_length-3);
+ case TAG_SMARTCARD_SEND:
+ return en50221_app_smartcard_parse_send(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+
+
+
+
+
+static int en50221_app_smartcard_parse_command(struct en50221_app_smartcard_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ if (data_length != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (data[0] != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t command_id = data[1];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_smartcard_command_callback cb = private->command_callback;
+ void *cb_arg = private->command_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, command_id);
+ }
+ return 0;
+}
+
+static int en50221_app_smartcard_parse_send(struct en50221_app_smartcard_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length < 8) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ data += length_field_len;
+
+ // parse
+ uint8_t CLA = data[0];
+ uint8_t INS = data[1];
+ uint8_t P1 = data[2];
+ uint8_t P2 = data[3];
+ uint16_t length_in = (data[4]<<8)|data[5];
+ uint8_t *data_in = data + 6;
+
+ // validate the length
+ if ((length_in + 8) != asn_data_length) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint16_t length_out = (data[6+length_in]<<8)|data[6+length_in+1];
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_smartcard_send_callback cb = private->send_callback;
+ void *cb_arg = private->send_callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, CLA, INS, P1, P2, data_in, length_in, length_out);
+ }
+ return 0;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h
new file mode 100644
index 0000000..56655c4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_smartcard.h
@@ -0,0 +1,191 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_smartcard_H__
+#define __EN50221_APPLICATION_smartcard_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define SMARTCARD_COMMAND_ID_CONNECT 0x01
+#define SMARTCARD_COMMAND_ID_DISCONNECT 0x02
+#define SMARTCARD_COMMAND_ID_POWERON_CARD 0x03
+#define SMARTCARD_COMMAND_ID_POWEROFF_CARD 0x04
+#define SMARTCARD_COMMAND_ID_RESET_CARD 0x05
+#define SMARTCARD_COMMAND_ID_RESET_STATUS 0x06
+#define SMARTCARD_COMMAND_ID_READ_ANSW_TO_RESET 0x07
+
+#define SMARTCARD_REPLY_ID_CONNECTED 0x01
+#define SMARTCARD_REPLY_ID_FREE 0x02
+#define SMARTCARD_REPLY_ID_BUSY 0x03
+#define SMARTCARD_REPLY_ID_ANSW_TO_RESET 0x04
+#define SMARTCARD_REPLY_ID_NO_ANSW_TO_RESET 0x05
+
+#define SMARTCARD_STATUS_CARD_INSERTED 0x01
+#define SMARTCARD_STATUS_CARD_REMOVED 0x02
+#define SMARTCARD_STATUS_CARD_IN_PLACE_POWEROFF 0x03
+#define SMARTCARD_STATUS_CARD_IN_PLACE_POWERON 0x04
+#define SMARTCARD_STATUS_CARD_NO_CARD 0x05
+#define SMARTCARD_STATUS_CARD_UNRESPONSIVE_CARD 0x06
+#define SMARTCARD_STATUS_CARD_REFUSED_CARD 0x07
+
+#define EN50221_APP_SMARTCARD_RESOURCEID(DEVICE_NUMBER) MKRID(112, ((DEVICE_NUMBER)& 0x0f), 1)
+
+
+
+/**
+ * Type definition for command - called when we receive a command.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param command_id One of the SMARTCARD_COMMAND_ID_* values
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_smartcard_command_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t command_id);
+
+/**
+ * Type definition for command - called when we receive a send command.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param CLA CLA value.
+ * @param INS INS value.
+ * @param P1 P1 value.
+ * @param P2 P2 value.
+ * @param in Data to send to the card
+ * @param in_length Number of bytes to send.
+ * @param out_length Number of bytes expected.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_smartcard_send_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t CLA, uint8_t INS, uint8_t P1, uint8_t P2,
+ uint8_t *in, uint32_t in_length,
+ uint32_t out_length);
+
+/**
+ * Opaque type representing a smartcard resource.
+ */
+typedef void *en50221_app_smartcard;
+
+/**
+ * Create an instance of the smartcard resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_smartcard en50221_app_smartcard_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the smartcard resource.
+ *
+ * @param smartcard Instance to destroy.
+ */
+extern void en50221_app_smartcard_destroy(en50221_app_smartcard smartcard);
+
+/**
+ * Register the callback for when we receive a comms command.
+ *
+ * @param smartcard smartcard resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_smartcard_register_command_callback(en50221_app_smartcard smartcard,
+ en50221_app_smartcard_command_callback callback, void *arg);
+
+/**
+ * Register the callback for when we receive data to send.
+ *
+ * @param smartcard smartcard resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_smartcard_register_send_callback(en50221_app_smartcard smartcard,
+ en50221_app_smartcard_send_callback callback, void *arg);
+
+/**
+ * Send a command response to the CAM.
+ *
+ * @param smartcard smartcard resource instance.
+ * @param session_number Session number to send it on.
+ * @param reply_id One of the SMARTCARD_REPLY_ID_* values.
+ * @param status One of the SMARTCARD_STATUS_* values.
+ * @param data Data to send when it is a SMARTCARD_REPLY_ID_ANSW_TO_RESET.
+ * @param data_length Length of data to send.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_smartcard_command_reply(en50221_app_smartcard smartcard,
+ uint16_t session_number,
+ uint8_t reply_id,
+ uint8_t status,
+ uint8_t *data,
+ uint32_t data_length);
+
+/**
+ * Send data received from a smartcart to the CAM.
+ *
+ * @param smartcard smartcard resource instance.
+ * @param session_number Session number to send it on.
+ * @param data Data to send when it is a SMARTCARD_REPLY_ID_ANSW_TO_RESET.
+ * @param data_length Length of data to send.
+ * @param SW1 SW1 value.
+ * @param SW2 SW2 value.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_smartcard_receive(en50221_app_smartcard smartcard,
+ uint16_t session_number,
+ uint8_t *data,
+ uint32_t data_length,
+ uint8_t SW1,
+ uint8_t SW2);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param smartcard smartcard instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_smartcard_message(en50221_app_smartcard smartcard,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h
new file mode 100644
index 0000000..2086a80
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_tags.h
@@ -0,0 +1,104 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APP_TAGS_H__
+#define __EN50221_APP_TAGS_H__
+
+/* Resource Manager */
+#define TAG_PROFILE_ENQUIRY 0x9f8010
+#define TAG_PROFILE 0x9f8011
+#define TAG_PROFILE_CHANGE 0x9f8012
+
+/* Application Info */
+#define TAG_APP_INFO_ENQUIRY 0x9f8020
+#define TAG_APP_INFO 0x9f8021
+#define TAG_ENTER_MENU 0x9f8022
+
+/* CA Support */
+#define TAG_CA_INFO_ENQUIRY 0x9f8030
+#define TAG_CA_INFO 0x9f8031
+#define TAG_CA_PMT 0x9f8032
+#define TAG_CA_PMT_REPLY 0x9f8033
+
+/* Host Control */
+#define TAG_TUNE 0x9f8400
+#define TAG_REPLACE 0x9f8401
+#define TAG_CLEAR_REPLACE 0x9f8402
+#define TAG_ASK_RELEASE 0x9f8403
+
+/* Date and Time */
+#define TAG_DATE_TIME_ENQUIRY 0x9f8440
+#define TAG_DATE_TIME 0x9f8441
+
+/* Man Machine Interface (MMI) */
+#define TAG_CLOSE_MMI 0x9f8800
+#define TAG_DISPLAY_CONTROL 0x9f8801
+#define TAG_DISPLAY_REPLY 0x9f8802
+#define TAG_TEXT_LAST 0x9f8803
+#define TAG_TEXT_MORE 0x9f8804
+#define TAG_KEYPAD_CONTROL 0x9f8805
+#define TAG_KEYPRESS 0x9f8806
+#define TAG_ENQUIRY 0x9f8807
+#define TAG_ANSWER 0x9f8808
+#define TAG_MENU_LAST 0x9f8809
+#define TAG_MENU_MORE 0x9f880a
+#define TAG_MENU_ANSWER 0x9f880b
+#define TAG_LIST_LAST 0x9f880c
+#define TAG_LIST_MORE 0x9f880d
+#define TAG_SUBTITLE_SEGMENT_LAST 0x9f880e
+#define TAG_SUBTITLE_SEGMENT_MORE 0x9f880f
+#define TAG_DISPLAY_MESSAGE 0x9f8810
+#define TAG_SCENE_END_MARK 0x9f8811
+#define TAG_SCENE_DONE 0x9f8812
+#define TAG_SCENE_CONTROL 0x9f8813
+#define TAG_SUBTITLE_DOWNLOAD_LAST 0x9f8814
+#define TAG_SUBTITLE_DOWNLOAD_MORE 0x9f8815
+#define TAG_FLUSH_DOWNLOAD 0x9f8816
+#define TAG_DOWNLOAD_REPLY 0x9f8817
+
+/* Low Speed Communications */
+#define TAG_COMMS_COMMAND 0x9f8c00
+#define TAG_CONNECTION_DESCRIPTOR 0x9f8c01
+#define TAG_COMMS_REPLY 0x9f8c02
+#define TAG_COMMS_SEND_LAST 0x9f8c03
+#define TAG_COMMS_SEND_MORE 0x9f8c04
+#define TAG_COMMS_RECV_LAST 0x9f8c05
+#define TAG_COMMS_RECV_MORE 0x9f8c06
+
+/* Authentication */
+#define TAG_AUTH_REQ 0x9f8200
+#define TAG_AUTH_RESP 0x9f8201
+
+/* Teletext */
+#define TAG_TELETEXT_EBU 0x9f9000
+
+/* Smartcard */
+#define TAG_SMARTCARD_COMMAND 0x9f8e00
+#define TAG_SMARTCARD_REPLY 0x9f8e01
+#define TAG_SMARTCARD_SEND 0x9f8e02
+#define TAG_SMARTCARD_RCV 0x9f8e03
+
+/* EPG */
+#define TAG_EPG_ENQUIRY 0x9f8f00
+#define TAG_EPG_REPLY 0x9f8f01
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c
new file mode 100644
index 0000000..cc2ee41
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.c
@@ -0,0 +1,139 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <string.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <pthread.h>
+#include "en50221_app_teletext.h"
+#include "en50221_app_tags.h"
+#include "asn_1.h"
+
+struct en50221_app_teletext_private {
+ struct en50221_app_send_functions *funcs;
+
+ en50221_app_teletext_callback callback;
+ void *callback_arg;
+
+ pthread_mutex_t lock;
+};
+
+static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length);
+
+
+
+en50221_app_teletext en50221_app_teletext_create(struct en50221_app_send_functions *funcs)
+{
+ struct en50221_app_teletext_private *private = NULL;
+
+ // create structure and set it up
+ private = malloc(sizeof(struct en50221_app_teletext_private));
+ if (private == NULL) {
+ return NULL;
+ }
+ private->funcs = funcs;
+ private->callback = NULL;
+
+ pthread_mutex_init(&private->lock, NULL);
+
+ // done
+ return private;
+}
+
+void en50221_app_teletext_destroy(en50221_app_teletext teletext)
+{
+ struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext;
+
+ pthread_mutex_destroy(&private->lock);
+ free(private);
+}
+
+void en50221_app_teletext_register_callback(en50221_app_teletext teletext,
+ en50221_app_teletext_callback callback, void *arg)
+{
+ struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext;
+
+ pthread_mutex_lock(&private->lock);
+ private->callback = callback;
+ private->callback_arg = arg;
+ pthread_mutex_unlock(&private->lock);
+}
+
+int en50221_app_teletext_message(en50221_app_teletext teletext,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length)
+{
+ struct en50221_app_teletext_private *private = (struct en50221_app_teletext_private *) teletext;
+ (void) resource_id;
+
+ // get the tag
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
+
+ switch(tag)
+ {
+ case TAG_TELETEXT_EBU:
+ return en50221_app_teletext_parse_ebu(private, slot_id, session_number, data+3, data_length-3);
+ }
+
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
+ return -1;
+}
+
+
+static int en50221_app_teletext_parse_ebu(struct en50221_app_teletext_private *private,
+ uint8_t slot_id, uint16_t session_number,
+ uint8_t *data, uint32_t data_length)
+{
+ // first of all, decode the length field
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
+ return -1;
+ }
+
+ // check it
+ if (asn_data_length > (data_length-length_field_len)) {
+ print(LOG_LEVEL, ERROR, 1, "Received short data\n");
+ return -1;
+ }
+ uint8_t *teletext_data = data + length_field_len;
+
+ // tell the app
+ pthread_mutex_lock(&private->lock);
+ en50221_app_teletext_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->lock);
+ if (cb) {
+ return cb(cb_arg, slot_id, session_number, teletext_data, asn_data_length);
+ }
+ return 0;
+}
+
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h
new file mode 100644
index 0000000..1164d94
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_teletext.h
@@ -0,0 +1,104 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APPLICATION_teletext_H__
+#define __EN50221_APPLICATION_teletext_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_app_utils.h>
+
+#define EN50221_APP_TELETEXT_RESOURCEID MKRID(128, 1, 1)
+
+
+/**
+ * Type definition for request - called when we receive teletext from a CAM.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number concerned.
+ * @param teletext_data Data for the request.
+ * @param teletext_data_lenghth Number of bytes.
+ * @return 0 on success, -1 on failure.
+ */
+typedef int (*en50221_app_teletext_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+ uint8_t *teletext_data,
+ uint32_t teletext_data_length);
+
+/**
+ * Opaque type representing a teletext resource.
+ */
+typedef void *en50221_app_teletext;
+
+/**
+ * Create an instance of the teletext resource.
+ *
+ * @param funcs Send functions to use.
+ * @return Instance, or NULL on failure.
+ */
+extern en50221_app_teletext en50221_app_teletext_create(struct en50221_app_send_functions *funcs);
+
+/**
+ * Destroy an instance of the teletext resource.
+ *
+ * @param teletext Instance to destroy.
+ */
+extern void en50221_app_teletext_destroy(en50221_app_teletext teletext);
+
+/**
+ * Register the callback for when we receive a request.
+ *
+ * @param teletext teletext resource instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_app_teletext_register_callback(en50221_app_teletext teletext,
+ en50221_app_teletext_callback callback, void *arg);
+
+/**
+ * Pass data received for this resource into it for parsing.
+ *
+ * @param teletext teletext instance.
+ * @param slot_id Slot ID concerned.
+ * @param session_number Session number concerned.
+ * @param resource_id Resource ID concerned.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, -1 on failure.
+ */
+extern int en50221_app_teletext_message(en50221_app_teletext teletext,
+ uint8_t slot_id,
+ uint16_t session_number,
+ uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c
new file mode 100644
index 0000000..af68846
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.c
@@ -0,0 +1,37 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "en50221_app_utils.h"
+
+struct en50221_app_public_resource_id *
+ en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, uint32_t resource_id)
+{
+ // reject private resources
+ if ((resource_id & 0xc0000000) == 0xc0000000)
+ return NULL;
+
+ idf->resource_class = (resource_id >> 16) & 0xffff; // use the resource_id as the MSBs of class
+ idf->resource_type = (resource_id >> 6) & 0x3ff;
+ idf->resource_version = resource_id & 0x3f;
+ return idf;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h
new file mode 100644
index 0000000..34ca68f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_app_utils.h
@@ -0,0 +1,105 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __EN50221_APP_UTILS_H__
+#define __EN50221_APP_UTILS_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/uio.h>
+
+/**
+ * A decomposed public resource structure.
+ *
+ * we will ignore private resource (resource_id_type==3),
+ * because they are not used by any modules at all and
+ * would need special code for any private resource anyway.
+ */
+struct en50221_app_public_resource_id {
+ uint16_t resource_class;
+ uint16_t resource_type;
+ uint8_t resource_version;
+};
+
+/**
+ * An abstraction away from hardcoded send functions so different layers may be
+ * slotted in under the application layer.
+ */
+struct en50221_app_send_functions {
+ /**
+ * Argument to pass to these functions.
+ */
+ void *arg;
+
+ /**
+ * Send data.
+ */
+ int (*send_data)(void *arg, uint16_t session_number, uint8_t *data, uint16_t data_length);
+
+ /**
+ * Send vector data.
+ */
+ int (*send_datav)(void *arg, uint16_t session_number, struct iovec *vector, int iov_count);
+};
+
+/**
+ * Make a host-endian uint32_t formatted resource id.
+ *
+ * @param CLASS Class of resource.
+ * @param TYPE Type of resource.
+ * @param VERSION Version of resource.
+ * @return Formatted resource id.
+ */
+#define MKRID(CLASS, TYPE, VERSION) ((((CLASS)&0xffff)<<16) | (((TYPE)&0x3ff)<<6) | ((VERSION)&0x3f))
+
+/**
+ * Decode a host-endian public resource_id into an en50221_app_public_resource_id structure.
+ *
+ * @param idf Structure to write decoded resource_id into.
+ * @param resource_id ID to decode.
+ * @return Pointer to idf on success, or NULL if this is not a public resource.
+ */
+struct en50221_app_public_resource_id *
+ en50221_app_decode_public_resource_id(struct en50221_app_public_resource_id *idf, uint32_t resource_id);
+
+/**
+ * Encode an en50221_app_public_resource_id structure into a host-endian uint32_t.
+ *
+ * @param idf Structure to encode.
+ * @return The encoded value
+ */
+static inline uint32_t en50221_app_encode_public_resource_id(struct en50221_app_public_resource_id *idf)
+{
+ return MKRID(idf->resource_class, idf->resource_type, idf->resource_version);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h
new file mode 100644
index 0000000..045a6a5
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_errno.h
@@ -0,0 +1,52 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 session layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef EN50221_ERRNO
+#define EN50221_ERRNO 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define EN50221ERR_CAREAD -1 /* error during read from CA device. */
+#define EN50221ERR_CAWRITE -2 /* error during write to CA device. */
+#define EN50221ERR_TIMEOUT -3 /* timeout occured waiting for a response from a device. */
+#define EN50221ERR_BADSLOTID -4 /* bad slot ID supplied by user - the offending slot_id will not be set. */
+#define EN50221ERR_BADCONNECTIONID -5 /* bad connection ID supplied by user. */
+#define EN50221ERR_BADSTATE -6 /* slot/connection in the wrong state. */
+#define EN50221ERR_BADCAMDATA -7 /* CAM supplied an invalid request. */
+#define EN50221ERR_OUTOFMEMORY -8 /* memory allocation failed. */
+#define EN50221ERR_ASNENCODE -9 /* ASN.1 encode failure - indicates library bug. */
+#define EN50221ERR_OUTOFCONNECTIONS -10 /* no more connections available. */
+#define EN50221ERR_OUTOFSLOTS -11 /* no more slots available - the offending slot_id will not be set. */
+#define EN50221ERR_IOVLIMIT -12 /* Too many struct iovecs were used. */
+#define EN50221ERR_BADSESSIONNUMBER -13 /* Bad session number suppplied by user. */
+#define EN50221ERR_OUTOFSESSIONS -14 /* no more sessions available. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c
new file mode 100644
index 0000000..1cc9a2e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.c
@@ -0,0 +1,954 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <sys/uio.h>
+#include <pthread.h>
+#include "en50221_transport.h"
+#include "en50221_session.h"
+#include "en50221_errno.h"
+#include "asn_1.h"
+
+
+// these are the possible session statuses
+#define S_STATUS_OPEN 0x00 // session is opened
+#define S_STATUS_CLOSE_NO_RES 0xF0 // could not open session, no proper resource available
+#define S_STATUS_CLOSE_RES_UNAVAILABLE 0xF1 // could not open session, resource unavailable
+#define S_STATUS_CLOSE_RES_LOW_VERSION 0xF2 // could not open session, resource version too low
+#define S_STATUS_CLOSE_RES_BUSY 0xF3 // could not open session, resource is busy
+
+#define ST_OPEN_SESSION_REQ 0x91 // h<--m
+#define ST_OPEN_SESSION_RES 0x92 // h-->m
+#define ST_CREATE_SESSION 0x93 // h-->m
+#define ST_CREATE_SESSION_RES 0x94 // h<--m
+#define ST_CLOSE_SESSION_REQ 0x95 // h<->m
+#define ST_CLOSE_SESSION_RES 0x96 // h<->m
+#define ST_SESSION_NUMBER 0x90 // h<->m
+
+#define S_STATE_IDLE 0x01 // this session is not in use
+#define S_STATE_ACTIVE 0x02 // this session is in use
+#define S_STATE_IN_CREATION 0x04 // this session waits for a ST_CREATE_SESSION_RES to become active
+#define S_STATE_IN_DELETION 0x08 // this session waits for ST_CLOSE_SESSION_RES to become idle again
+
+
+// for each session we store its identifier, the resource-id
+// it is linked to and the callback of the specific resource
+struct en50221_session {
+ uint8_t state;
+ uint32_t resource_id;
+ uint8_t slot_id;
+ uint8_t connection_id;
+
+ en50221_sl_resource_callback callback;
+ void *callback_arg;
+
+ pthread_mutex_t session_lock;
+};
+
+struct en50221_session_layer_private
+{
+ uint32_t max_sessions;
+ en50221_transport_layer tl;
+
+ en50221_sl_lookup_callback lookup;
+ void *lookup_arg;
+
+ en50221_sl_session_callback session;
+ void *session_arg;
+
+ pthread_mutex_t global_lock;
+ pthread_mutex_t setcallback_lock;
+
+ int error;
+
+ struct en50221_session *sessions;
+};
+
+static void en50221_sl_transport_callback(void *arg, int reason, uint8_t *data, uint32_t data_length,
+ uint8_t slot_id, uint8_t connection_id);
+static int en50221_sl_alloc_new_session(struct en50221_session_layer_private *private,
+ uint32_t resource_id,
+ uint8_t slot_id,
+ uint8_t connection_id,
+ en50221_sl_resource_callback callback, void* arg);
+
+
+
+
+en50221_session_layer en50221_sl_create(en50221_transport_layer tl,
+ uint32_t max_sessions)
+{
+ struct en50221_session_layer_private *private = NULL;
+ uint32_t i;
+
+ // setup structure
+ private = (struct en50221_session_layer_private*) malloc(sizeof(struct en50221_session_layer_private));
+ if (private == NULL)
+ goto error_exit;
+ private->max_sessions = max_sessions;
+ private->lookup = NULL;
+ private->session = NULL;
+ private->tl = tl;
+ private->error = 0;
+
+ // init the mutex
+ pthread_mutex_init(&private->global_lock, NULL);
+ pthread_mutex_init(&private->setcallback_lock, NULL);
+
+ // create the slots
+ private->sessions = malloc(sizeof(struct en50221_session) * max_sessions);
+ if (private->sessions == NULL)
+ goto error_exit;
+
+ // set them up
+ for(i=0; i< max_sessions; i++) {
+ private->sessions[i].state = S_STATE_IDLE;
+ private->sessions[i].callback = NULL;
+
+ pthread_mutex_init(&private->sessions[i].session_lock, NULL);
+ }
+
+ // register ourselves with the transport layer
+ en50221_tl_register_callback(tl, en50221_sl_transport_callback, private);
+
+ return private;
+
+error_exit:
+ en50221_sl_destroy(private);
+ return NULL;
+}
+
+void en50221_sl_destroy(en50221_session_layer sl)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+ uint32_t i;
+
+ if (private) {
+ if (private->sessions) {
+ for(i=0; i< private->max_sessions; i++) {
+ pthread_mutex_destroy(&private->sessions[i].session_lock);
+ }
+ free(private->sessions);
+ }
+
+ pthread_mutex_destroy(&private->setcallback_lock);
+ pthread_mutex_destroy(&private->global_lock);
+
+ free(private);
+ }
+}
+
+int en50221_sl_get_error(en50221_session_layer tl)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) tl;
+ return private->error;
+}
+
+void en50221_sl_register_lookup_callback(en50221_session_layer sl, en50221_sl_lookup_callback callback, void *arg)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+
+ pthread_mutex_lock(&private->setcallback_lock);
+ private->lookup = callback;
+ private->lookup_arg = arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+}
+
+void en50221_sl_register_session_callback(en50221_session_layer sl,
+ en50221_sl_session_callback callback, void *arg)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+
+ pthread_mutex_lock(&private->setcallback_lock);
+ private->session = callback;
+ private->session_arg = arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+}
+
+int en50221_sl_create_session(en50221_session_layer sl, int slot_id, uint8_t connection_id, uint32_t resource_id,
+ en50221_sl_resource_callback callback, void* arg)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+
+ // lookup next free session_id:
+ pthread_mutex_lock(&private->global_lock);
+ int session_number = en50221_sl_alloc_new_session(private, resource_id, slot_id, connection_id, callback, arg);
+ if (session_number == -1) {
+ pthread_mutex_unlock(&private->global_lock);
+ return -1;
+ }
+ pthread_mutex_unlock(&private->global_lock);
+
+ // make up the header
+ uint8_t hdr[8];
+ hdr[0] = ST_CREATE_SESSION;
+ hdr[1] = 6;
+ hdr[2] = resource_id >> 24;
+ hdr[3] = resource_id >> 16;
+ hdr[4] = resource_id >> 8;
+ hdr[5] = resource_id;
+ hdr[6] = session_number >> 8;
+ hdr[7] = session_number;
+
+ // send this command
+ if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 8)) {
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (private->sessions[session_number].state == S_STATE_IN_CREATION) {
+ private->sessions[session_number].state = S_STATE_IDLE;
+ }
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ private->error = en50221_tl_get_error(private->tl);
+ return -1;
+ }
+
+ // ok.
+ return session_number;
+}
+
+int en50221_sl_destroy_session(en50221_session_layer sl, uint16_t session_number)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+
+ if (session_number >= private->max_sessions) {
+ private->error = EN50221ERR_BADSESSIONNUMBER;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (!(private->sessions[session_number].state & (S_STATE_ACTIVE|S_STATE_IN_DELETION))) {
+ private->error = EN50221ERR_BADSESSIONNUMBER;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return -1;
+ }
+
+ // set the state
+ private->sessions[session_number].state = S_STATE_IN_DELETION;
+
+ // get essential details
+ uint8_t slot_id = private->sessions[session_number].slot_id;
+ uint8_t connection_id = private->sessions[session_number].connection_id;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ // sendit
+ uint8_t hdr[4];
+ hdr[0] = ST_CLOSE_SESSION_REQ;
+ hdr[1] = 2;
+ hdr[2] = session_number >> 8;
+ hdr[3] = session_number;
+ if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 4)) {
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (private->sessions[session_number].state == S_STATE_IN_DELETION) {
+ private->sessions[session_number].state = S_STATE_IDLE;
+ }
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ private->error = en50221_tl_get_error(private->tl);
+ return -1;
+ }
+
+ return 0;
+}
+
+int en50221_sl_send_data(en50221_session_layer sl, uint16_t session_number, uint8_t *data, uint16_t data_length)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+
+ if (session_number >= private->max_sessions) {
+ private->error = EN50221ERR_BADSESSIONNUMBER;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (private->sessions[session_number].state != S_STATE_ACTIVE) {
+ private->error = EN50221ERR_BADSESSIONNUMBER;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return -1;
+ }
+
+ // get essential details
+ uint8_t slot_id = private->sessions[session_number].slot_id;
+ uint8_t connection_id = private->sessions[session_number].connection_id;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ // sendit
+ struct iovec iov[2];
+ uint8_t hdr[4];
+ hdr[0] = ST_SESSION_NUMBER;
+ hdr[1] = 2;
+ hdr[2] = session_number >> 8;
+ hdr[3] = session_number;
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = 4;
+ iov[1].iov_base = data;
+ iov[1].iov_len = data_length;
+ if (en50221_tl_send_datav(private->tl, slot_id, connection_id, iov, 2)) {
+ private->error = en50221_tl_get_error(private->tl);
+ return -1;
+ }
+
+ return 0;
+}
+
+int en50221_sl_send_datav(en50221_session_layer sl, uint16_t session_number,
+ struct iovec *vector, int iov_count)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+
+ if (session_number >= private->max_sessions) {
+ private->error = EN50221ERR_BADSESSIONNUMBER;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (private->sessions[session_number].state != S_STATE_ACTIVE) {
+ private->error = EN50221ERR_BADSESSIONNUMBER;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return -1;
+ }
+ if (iov_count > 9) {
+ private->error = EN50221ERR_IOVLIMIT;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return -1;
+ }
+ uint8_t slot_id = private->sessions[session_number].slot_id;
+ uint8_t connection_id = private->sessions[session_number].connection_id;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ // make up the header
+ struct iovec out_iov[10];
+ uint8_t hdr[4];
+ hdr[0] = ST_SESSION_NUMBER;
+ hdr[1] = 2;
+ hdr[2] = session_number >> 8;
+ hdr[3] = session_number;
+ out_iov[0].iov_base = hdr;
+ out_iov[0].iov_len = 4;
+
+ // make up the data
+ memcpy(&out_iov[1], vector, iov_count * sizeof(struct iovec));
+
+ // send this command
+ if (en50221_tl_send_datav(private->tl, slot_id, connection_id, out_iov, iov_count+1)) {
+ private->error = en50221_tl_get_error(private->tl);
+ return -1;
+ }
+ return 0;
+}
+
+int en50221_sl_broadcast_data(en50221_session_layer sl, int slot_id, uint32_t resource_id,
+ uint8_t *data, uint16_t data_length)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) sl;
+ uint32_t i;
+
+ for(i = 0; i < private->max_sessions; i++)
+ {
+ pthread_mutex_lock(&private->sessions[i].session_lock);
+
+ if (private->sessions[i].state != S_STATE_ACTIVE) {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ continue;
+ }
+ if ((slot_id != -1) && (slot_id != private->sessions[i].slot_id)) {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ continue;
+ }
+
+ if (private->sessions[i].resource_id == resource_id) {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ en50221_sl_send_data(sl, i, data, data_length);
+ } else {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ }
+ }
+
+ return 0;
+}
+
+
+
+static void en50221_sl_handle_open_session_request(struct en50221_session_layer_private *private,
+ uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id)
+{
+ // check
+ if (data_length < 5) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+ if (data[0] != 4) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+
+ // get the resource id
+ uint32_t requested_resource_id = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
+
+ // get lookup callback details
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_lookup_callback lcb = private->lookup;
+ void *lcb_arg = private->lookup_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ // first of all, lookup this resource id
+ int status = S_STATUS_CLOSE_NO_RES;
+ en50221_sl_resource_callback resource_callback = NULL;
+ void *resource_arg = NULL;
+ uint32_t connected_resource_id;
+ if (lcb) {
+ status = lcb(lcb_arg, slot_id, requested_resource_id, &resource_callback, &resource_arg, &connected_resource_id);
+ switch(status) {
+ case 0:
+ status = S_STATUS_OPEN;
+ break;
+
+ case -1:
+ status = S_STATUS_CLOSE_NO_RES;
+ break;
+
+ case -2:
+ status = S_STATUS_CLOSE_RES_LOW_VERSION;
+ break;
+
+ case -3:
+ status = S_STATUS_CLOSE_RES_UNAVAILABLE;
+ break;
+ }
+ }
+
+ // if we found it, get a new session for it
+ int session_number = -1;
+ if (status == S_STATUS_OPEN) {
+ // lookup next free session_id:
+ pthread_mutex_lock(&private->global_lock);
+ session_number = en50221_sl_alloc_new_session(private, connected_resource_id, slot_id, connection_id,
+ resource_callback, resource_arg);
+ pthread_mutex_unlock(&private->global_lock);
+
+ if (session_number == -1) {
+ status = S_STATUS_CLOSE_NO_RES;
+ } else {
+ // inform upper layers/ check availability
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb) {
+ if (cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTING, slot_id, session_number, connected_resource_id)) {
+ status = S_STATUS_CLOSE_RES_BUSY;
+ }
+ } else {
+ status = S_STATUS_CLOSE_RES_UNAVAILABLE;
+ }
+ }
+ }
+
+ // send response
+ uint8_t hdr[9];
+ hdr[0] = ST_OPEN_SESSION_RES;
+ hdr[1] = 7;
+ hdr[2] = status;
+ hdr[3] = connected_resource_id >> 24;
+ hdr[4] = connected_resource_id >> 16;
+ hdr[5] = connected_resource_id >> 8;
+ hdr[6] = connected_resource_id;
+ hdr[7] = session_number >> 8;
+ hdr[8] = session_number;
+ if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 9)) {
+ print(LOG_LEVEL, ERROR, 1, "Transport layer error %i occurred\n", en50221_tl_get_error(private->tl));
+ status = S_STATUS_CLOSE_NO_RES;
+ // fallthrough
+ }
+
+ // inform upper layers what happened
+ if (session_number != -1) {
+ // setup session state apppropriately from upper layer response
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (status != S_STATUS_OPEN) {
+ private->sessions[session_number].state = S_STATE_IDLE;
+ } else {
+ private->sessions[session_number].state = S_STATE_ACTIVE;
+ }
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ // tell upper layers
+ if (private->sessions[session_number].state == S_STATE_ACTIVE) {
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ if (status == S_STATUS_OPEN) {
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTED, slot_id, session_number, connected_resource_id);
+ } else {
+ private->sessions[session_number].state = S_STATE_IDLE;
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_CAMCONNECTFAIL, slot_id, session_number, connected_resource_id);
+ }
+ }
+ }
+}
+
+static void en50221_sl_handle_close_session_request(struct en50221_session_layer_private *private,
+ uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id)
+{
+ // check
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+ if (data[0] != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+
+ // extract session number
+ uint16_t session_number = (data[1] << 8) | data[2];
+
+ // check session number is ok
+ uint8_t code = 0x00;
+ uint32_t resource_id = 0;
+ if (session_number >= private->max_sessions) {
+ code = 0xF0; // session close error
+ print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id);
+ } else {
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (slot_id != private->sessions[session_number].slot_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ code = 0xF0; // session close error
+ }
+ if (connection_id != private->sessions[session_number].connection_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ code = 0xF0; // session close error
+ }
+ if (!(private->sessions[session_number].state & (S_STATE_ACTIVE|S_STATE_IN_DELETION))) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ code = 0xF0; // session close error
+ }
+
+ if (code == 0x00) {
+ private->sessions[session_number].state = S_STATE_IDLE;
+ code = 0x00; // close ok
+ }
+ resource_id = private->sessions[session_number].resource_id;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ }
+
+ // make up the response
+ uint8_t hdr[5];
+ hdr[0] = ST_CLOSE_SESSION_RES;
+ hdr[1] = 3;
+ hdr[2] = code;
+ hdr[3] = session_number >> 8;
+ hdr[4] = session_number;
+
+ // sendit
+ if (en50221_tl_send_data(private->tl, slot_id, connection_id, hdr, 5)) {
+ print(LOG_LEVEL, ERROR, 1, "Transport layer reports error %i on slot %i\n",
+ en50221_tl_get_error(private->tl), slot_id);
+ }
+
+ // callback to announce destruction to resource if it was ok
+ if (code == 0x00) {
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, session_number, resource_id);
+ }
+}
+
+static void en50221_sl_handle_create_session_response(struct en50221_session_layer_private *private,
+ uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id)
+{
+ // check
+ if (data_length < 8) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+ if (data[0] != 7) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+
+ // extract session number
+ uint16_t session_number = (data[5] << 8) | data[6];
+
+ // check session number is ok
+ if (session_number >= private->max_sessions) {
+ print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id);
+ return;
+ }
+
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (slot_id != private->sessions[session_number].slot_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+ if (connection_id != private->sessions[session_number].connection_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+ if (private->sessions[session_number].state != S_STATE_IN_CREATION) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+
+ // extract status
+ if (data[1] != S_STATUS_OPEN) {
+ print(LOG_LEVEL, ERROR, 1, "Session creation failed 0x%02x\n", data[1]);
+ private->sessions[session_number].state = S_STATE_IDLE;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ // inform upper layers
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_CONNECTFAIL, slot_id, session_number,
+ private->sessions[session_number].resource_id);
+ return;
+ }
+
+ // set it active
+ private->sessions[session_number].state = S_STATE_ACTIVE;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ // inform upper layers
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_CONNECTED, slot_id, session_number,
+ private->sessions[session_number].resource_id);
+}
+
+static void en50221_sl_handle_close_session_response(struct en50221_session_layer_private *private,
+ uint8_t *data, uint32_t data_length, uint8_t slot_id, uint8_t connection_id)
+{
+ // check
+ if (data_length < 5) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+ if (data[0] != 4) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ return;
+ }
+
+ // extract session number
+ uint16_t session_number = (data[2] << 8) | data[3];
+
+ // check session number is ok
+ if (session_number >= private->max_sessions) {
+ print(LOG_LEVEL, ERROR, 1, "Received bad session id %i\n", slot_id);
+ return;
+ }
+
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (slot_id != private->sessions[session_number].slot_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+ if (connection_id != private->sessions[session_number].connection_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+ if (private->sessions[session_number].state != S_STATE_IN_DELETION) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+
+ // extract status
+ if (data[1] != 0x00) {
+ print(LOG_LEVEL, ERROR, 1, "Session close failed 0x%02x\n", data[1]);
+ // just fallthrough anyway
+ }
+
+ // completed
+ private->sessions[session_number].state = S_STATE_IDLE;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+}
+
+static void en50221_sl_handle_session_package(struct en50221_session_layer_private *private,
+ uint8_t *data, uint32_t data_length,
+ uint8_t slot_id, uint8_t connection_id)
+{
+ // check
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id);
+ return;
+ }
+ if (data[0] != 2) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id);
+ return;
+ }
+
+ // get session number
+ uint16_t session_number = (data[1] << 8) | data[2];
+
+ // check it
+ if (session_number >= private->max_sessions) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with bad session_number from module on slot %i\n", slot_id);
+ return;
+ }
+
+ pthread_mutex_lock(&private->sessions[session_number].session_lock);
+ if (slot_id != private->sessions[session_number].slot_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+ if (connection_id != private->sessions[session_number].connection_id) {
+ print(LOG_LEVEL, ERROR, 1, "Received unexpected session on invalid slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+ if (private->sessions[session_number].state != S_STATE_ACTIVE) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with bad session_number from module on slot %i\n", slot_id);
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+ return;
+ }
+
+ en50221_sl_resource_callback cb = private->sessions[session_number].callback;
+ void *cb_arg = private->sessions[session_number].callback_arg;
+ uint32_t resource_id = private->sessions[session_number].resource_id;
+ pthread_mutex_unlock(&private->sessions[session_number].session_lock);
+
+ // there can be > 1 APDU following the package - all for the same session/resource_id tho.
+ data += 3;
+ data_length -= 3;
+ while(data_length) {
+ // check length field
+ if (data_length < 3) {
+ print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id);
+ return;
+ }
+
+ // parse the APDU's length field
+ int length_field_len;
+ uint16_t asn_data_length;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data+3, data_length-3)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id);
+ return;
+ }
+ uint32_t apdu_length = 3 + length_field_len + asn_data_length;
+
+ // check there is enough data
+ if (apdu_length > data_length) {
+ print(LOG_LEVEL, ERROR, 1, "Received invalid sized session package from slot %i\n", slot_id);
+ return;
+ }
+
+ // pass the APDU up to the higher layers
+ if (cb)
+ cb(cb_arg, slot_id, session_number, resource_id, data, apdu_length);
+
+ // next!
+ data += apdu_length;
+ data_length -= apdu_length;
+ }
+
+}
+
+static void en50221_sl_transport_callback(void *arg, int reason, uint8_t *data, uint32_t data_length,
+ uint8_t slot_id, uint8_t connection_id)
+{
+ struct en50221_session_layer_private *private = (struct en50221_session_layer_private *) arg;
+ uint32_t i;
+
+ // deal with the reason for this callback
+ switch(reason) {
+ case T_CALLBACK_REASON_DATA:
+ // fallthrough into rest of this function
+ break;
+
+ case T_CALLBACK_REASON_CONNECTIONOPEN:
+ {
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_TC_CONNECT, slot_id, connection_id, 0);
+ return;
+ }
+
+ case T_CALLBACK_REASON_CAMCONNECTIONOPEN:
+ {
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_TC_CAMCONNECT, slot_id, connection_id, 0);
+ return;
+ }
+
+ case T_CALLBACK_REASON_CONNECTIONCLOSE:
+ {
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ for(i=0; i< private->max_sessions; i++) {
+ pthread_mutex_lock(&private->sessions[i].session_lock);
+
+ if (private->sessions[i].state == S_STATE_IDLE) {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ continue;
+ }
+ if (private->sessions[i].connection_id != connection_id) {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ continue;
+ }
+
+ private->sessions[i].state = S_STATE_IDLE;
+
+ uint8_t slot_id = private->sessions[i].slot_id;
+ uint32_t resource_id = private->sessions[i].resource_id;
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id);
+ }
+ return;
+ }
+
+ case T_CALLBACK_REASON_SLOTCLOSE:
+ {
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_sl_session_callback cb = private->session;
+ void *cb_arg = private->session_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ for(i=0; i< private->max_sessions; i++) {
+ pthread_mutex_lock(&private->sessions[i].session_lock);
+
+ if (private->sessions[i].state == S_STATE_IDLE) {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ continue;
+ }
+ if (private->sessions[i].slot_id != slot_id) {
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+ continue;
+ }
+ private->sessions[i].state = S_STATE_IDLE;
+
+ uint32_t resource_id = private->sessions[i].resource_id;
+ pthread_mutex_unlock(&private->sessions[i].session_lock);
+
+ if (cb)
+ cb(cb_arg, S_SCALLBACK_REASON_CLOSE, slot_id, i, resource_id);
+
+ }
+ return;
+ }
+ }
+
+ // sanity check data length
+ if (data_length < 1) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %i\n", slot_id);
+ return;
+ }
+
+ // deal with the data
+ uint8_t spdu_tag = data[0];
+ switch(spdu_tag)
+ {
+ case ST_OPEN_SESSION_REQ:
+ en50221_sl_handle_open_session_request(private, data+1, data_length-1, slot_id, connection_id);
+ break;
+
+ case ST_CLOSE_SESSION_REQ:
+ en50221_sl_handle_close_session_request(private, data+1, data_length-1, slot_id, connection_id);
+ break;
+
+ case ST_SESSION_NUMBER:
+ en50221_sl_handle_session_package(private, data+1, data_length-1, slot_id, connection_id);
+ break;
+
+ case ST_CREATE_SESSION_RES:
+ en50221_sl_handle_create_session_response(private, data+1, data_length-1, slot_id, connection_id);
+ break;
+
+ case ST_CLOSE_SESSION_RES:
+ en50221_sl_handle_close_session_response(private, data+1, data_length-1, slot_id, connection_id);
+ break;
+
+ default:
+ print(LOG_LEVEL, ERROR, 1, "Received unknown session tag %02x from module on slot %i", spdu_tag, slot_id);
+ break;
+ }
+}
+
+static int en50221_sl_alloc_new_session(struct en50221_session_layer_private *private,
+ uint32_t resource_id,
+ uint8_t slot_id,
+ uint8_t connection_id,
+ en50221_sl_resource_callback callback, void* arg)
+{
+ int session_number = -1;
+ uint32_t i;
+ for(i = 1; i < private->max_sessions; i++) {
+ if (private->sessions[i].state == S_STATE_IDLE) {
+ session_number = i;
+ break;
+ }
+ }
+ if (session_number == -1) {
+ private->error = EN50221ERR_OUTOFSESSIONS;
+ return -1;
+ }
+
+ // setup the session
+ private->sessions[session_number].state = S_STATE_IN_CREATION;
+ private->sessions[session_number].resource_id = resource_id;
+ private->sessions[session_number].slot_id = slot_id;
+ private->sessions[session_number].connection_id = connection_id;
+ private->sessions[session_number].callback = callback;
+ private->sessions[session_number].callback_arg = arg;
+
+ // ok
+ return session_number;
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h
new file mode 100644
index 0000000..c7cc6a8
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_session.h
@@ -0,0 +1,212 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 session layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian@jusst.de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef __EN50221_SESSION_H__
+#define __EN50221_SESSION_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <libdvben50221/en50221_transport.h>
+
+#define S_SCALLBACK_REASON_CAMCONNECTING 0x00 // CAM originated session connecting to resource (check for availability)
+#define S_SCALLBACK_REASON_CAMCONNECTED 0x01 // CAM originated session connection established succesfully
+#define S_SCALLBACK_REASON_CAMCONNECTFAIL 0x02 // CAM originated session connection failed
+#define S_SCALLBACK_REASON_CONNECTED 0x03 // Host originated session ACKed by CAM.
+#define S_SCALLBACK_REASON_CONNECTFAIL 0x04 // Host originated session NACKed by CAM.
+#define S_SCALLBACK_REASON_CLOSE 0x05 // Session closed
+#define S_SCALLBACK_REASON_TC_CONNECT 0x06 // A host originated transport connection has been established.
+#define S_SCALLBACK_REASON_TC_CAMCONNECT 0x07 // A CAM originated transport connection has been established.
+
+
+/**
+ * Opaque type representing a session layer.
+ */
+typedef void *en50221_session_layer;
+
+/**
+ * Type definition for resource callback function - called by session layer when data
+ * arrives for a particular resource.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number.
+ * @param resource_id Resource id.
+ * @param data The data.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, or -1 on failure.
+ */
+typedef int (*en50221_sl_resource_callback)(void *arg, uint8_t slot_id,
+ uint16_t session_number, uint32_t resource_id,
+ uint8_t *data, uint32_t data_length);
+
+/**
+ * Type definition for resource lookup callback function - used by the session layer to
+ * look up requested resources.
+ *
+ * @param arg Private argument.
+ * @param slot_id Slot id the request came from.
+ * @param requested_resource_id Resource id requested.
+ * @param callback_out Output parameter for pointer to resource callback function.
+ * @param arg_out Output parameter for arg to pass to resource callback.
+ * @param resource_id_out Set this to the resource_id connected to (e.g. may differ from resource_id due to versions).
+ * @return 0 on success,
+ * -1 if the resource was not found,
+ * -2 if it exists, but had a lower version, or
+ * -3 if it exists, but was unavailable.
+ */
+typedef int (*en50221_sl_lookup_callback)(void *arg, uint8_t slot_id, uint32_t requested_resource_id,
+ en50221_sl_resource_callback *callback_out, void **arg_out,
+ uint32_t *resource_id_out);
+
+
+/**
+ * Type definition for session callback function - used to inform top level code when a CAM
+ * modifies a session to a resource.
+ *
+ * @param arg Private argument.
+ * @param reason One of the S_CCALLBACK_REASON_* values above.
+ * @param slot_id Slot id concerned.
+ * @param session_number Session number.
+ * @param resource_id Resource id.
+ * @return 0 on sucess, or -1 on error.
+ */
+typedef int (*en50221_sl_session_callback)(void *arg, int reason,
+ uint8_t slot_id, uint16_t session_number, uint32_t resource_id);
+
+/**
+ * Construct a new instance of the session layer.
+ *
+ * @param tl The en50221_transport_layer instance to use.
+ * @param max_sessions Maximum number of sessions supported.
+ * @return The en50221_session_layer instance, or NULL on error.
+ */
+extern en50221_session_layer en50221_sl_create(en50221_transport_layer tl, uint32_t max_sessions);
+
+/**
+ * Destroy an instance of the session layer.
+ *
+ * @param tl The en50221_session_layer instance.
+ */
+extern void en50221_sl_destroy(en50221_session_layer sl);
+
+/**
+ * Gets the last error.
+ *
+ * @param tl The en50221_session_layer instance.
+ * @return One of the EN50221ERR_* values.
+ */
+extern int en50221_sl_get_error(en50221_session_layer tl);
+
+/**
+ * Register the callback for resource lookup.
+ *
+ * @param sl The en50221_session_layer instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_sl_register_lookup_callback(en50221_session_layer sl,
+ en50221_sl_lookup_callback callback, void *arg);
+
+/**
+ * Register the callback for informing about session from a cam.
+ *
+ * @param sl The en50221_session_layer instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_sl_register_session_callback(en50221_session_layer sl,
+ en50221_sl_session_callback callback, void *arg);
+
+/**
+ * Create a new session to a module in a slot.
+ *
+ * @param sl The en50221_session_layer instance.
+ * @param slot The slot to connect to.
+ * @param resource_id The resource_id to connect to.
+ * @param callback The callback for received data.
+ * @param arg Argument to pass to the callback.
+ * @return The new session_number, or -1 on error.
+ */
+extern int en50221_sl_create_session(en50221_session_layer sl, int slot_id, uint8_t connection_id,
+ uint32_t resource_id,
+ en50221_sl_resource_callback callback, void* arg);
+
+/**
+ * Destroy a session.
+ *
+ * @param sl The en50221_session_layer instance.
+ * @param session_number The session to destroy.
+ * @return 0 on success, or -1 on error.
+ */
+extern int en50221_sl_destroy_session(en50221_session_layer sl, uint16_t session_number);
+
+/**
+ * this function is used to take a data-block, pack into
+ * into a SPDU (SESSION_NUMBER) and send it to the transport layer
+ *
+ * @param sl The en50221_session_layer instance to use.
+ * @param session_number Session number concerned.
+ * @param data Data to send.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, or -1 on error.
+ */
+extern int en50221_sl_send_data(en50221_session_layer sl, uint16_t session_number, uint8_t *data, uint16_t data_length);
+
+/**
+ * this function is used to take a data-block, pack into
+ * into a SPDU (SESSION_NUMBER) and send it to the transport layer
+ *
+ * @param sl The en50221_session_layer instance to use.
+ * @param session_number Session number concerned.
+ * @param vector IOVEC to send.
+ * @param iov_count Number of elements in io vector.
+ * @return 0 on success, or -1 on error.
+ */
+extern int en50221_sl_send_datav(en50221_session_layer sl, uint16_t session_number,
+ struct iovec *vector, int iov_count);
+
+/**
+ * this is used to send a message to all sessions, linked
+ * to resource res
+ *
+ * @param tl The en50221_session_layer instance to use.
+ * @param slot_id Set to -1 to send to any slot. Other values will send to only that slot.
+ * @param resource_id Resource id concerned.
+ * @param data Data to send.
+ * @param data_length Length of data in bytes.
+ * @return 0 on success, or -1 on error.
+ */
+extern int en50221_sl_broadcast_data(en50221_session_layer sl, int slot_id, uint32_t resource_id,
+ uint8_t *data, uint16_t data_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c
new file mode 100644
index 0000000..ff7c936
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.c
@@ -0,0 +1,1240 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 transport layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <time.h>
+#include <libdvbmisc/dvbmisc.h>
+#include <libdvbapi/dvbca.h>
+#include "en50221_errno.h"
+#include "en50221_transport.h"
+#include "asn_1.h"
+
+// these are the Transport Tags, like
+// described in EN50221, Annex A.4.1.13 (pg70)
+#define T_SB 0x80 // sb primitive h<--m
+#define T_RCV 0x81 // receive primitive h-->m
+#define T_CREATE_T_C 0x82 // create transport connection primitive h-->m
+#define T_C_T_C_REPLY 0x83 // ctc reply primitive h<--m
+#define T_DELETE_T_C 0x84 // delete tc primitive h<->m
+#define T_D_T_C_REPLY 0x85 // dtc reply primitive h<->m
+#define T_REQUEST_T_C 0x86 // request transport connection primitive h<--m
+#define T_NEW_T_C 0x87 // new tc / reply to t_request primitive h-->m
+#define T_T_C_ERROR 0x77 // error creating tc primitive h-->m
+#define T_DATA_LAST 0xA0 // convey data from higher constructed h<->m
+ // layers
+#define T_DATA_MORE 0xA1 // convey data from higher constructed h<->m
+ // layers
+
+struct en50221_message {
+ struct en50221_message *next;
+ uint32_t length;
+ uint8_t data[0];
+};
+
+struct en50221_connection {
+ uint32_t state; // the current state: idle/in_delete/in_create/active
+ struct timeval tx_time; // time last request was sent from host->module, or 0 if ok
+ struct timeval last_poll_time; // time of last poll transmission
+ uint8_t *chain_buffer; // used to save parts of chained packets
+ uint32_t buffer_length;
+
+ struct en50221_message *send_queue;
+ struct en50221_message *send_queue_tail;
+};
+
+struct en50221_slot {
+ int ca_hndl;
+ uint8_t slot; // CAM slot
+ struct en50221_connection *connections;
+
+ pthread_mutex_t slot_lock;
+
+ uint32_t response_timeout;
+ uint32_t poll_delay;
+};
+
+struct en50221_transport_layer_private
+{
+ uint8_t max_slots;
+ uint8_t max_connections_per_slot;
+ struct en50221_slot *slots;
+ struct pollfd *slot_pollfds;
+ int slots_changed;
+
+ pthread_mutex_t global_lock;
+ pthread_mutex_t setcallback_lock;
+
+ int error;
+ int error_slot;
+
+ en50221_tl_callback callback;
+ void *callback_arg;
+};
+
+static int en50221_tl_process_data(struct en50221_transport_layer_private *tl, uint8_t slot_id,
+ uint8_t *data, uint32_t data_length);
+static int en50221_tl_poll_tc(struct en50221_transport_layer_private *tl, uint8_t slot_id, uint8_t connection_id);
+static int en50221_tl_alloc_new_tc(struct en50221_transport_layer_private *tl, uint8_t slot_id);
+static void queue_message(struct en50221_transport_layer_private *tl, uint8_t slot_id,
+ uint8_t connection_id, struct en50221_message *msg);
+static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id);
+static int en50221_tl_handle_delete_tc(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id);
+static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id);
+static int en50221_tl_handle_request_tc(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id);
+static int en50221_tl_handle_data_more(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_length);
+static int en50221_tl_handle_data_last(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_length);
+static int en50221_tl_handle_sb(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_length);
+
+
+en50221_transport_layer en50221_tl_create(uint8_t max_slots, uint8_t max_connections_per_slot)
+{
+ struct en50221_transport_layer_private *private = NULL;
+ int i;
+ int j;
+
+ // setup structure
+ private = (struct en50221_transport_layer_private*) malloc(sizeof(struct en50221_transport_layer_private));
+ if (private == NULL)
+ goto error_exit;
+ private->max_slots = max_slots;
+ private->max_connections_per_slot = max_connections_per_slot;
+ private->slots = NULL;
+ private->slot_pollfds = NULL;
+ private->slots_changed = 1;
+ private->callback = NULL;
+ private->callback_arg = NULL;
+ private->error_slot = 0;
+ private->error = 0;
+ pthread_mutex_init(&private->global_lock, NULL);
+ pthread_mutex_init(&private->setcallback_lock, NULL);
+
+ // create the slots
+ private->slots = malloc(sizeof(struct en50221_slot) * max_slots);
+ if (private->slots == NULL)
+ goto error_exit;
+
+ // set them up
+ for(i=0; i< max_slots; i++) {
+ private->slots[i].ca_hndl = -1;
+
+ // create the connections for this slot
+ private->slots[i].connections = malloc(sizeof(struct en50221_connection) * max_connections_per_slot);
+ if (private->slots[i].connections == NULL)
+ goto error_exit;
+
+ // create a mutex for the slot
+ pthread_mutex_init(&private->slots[i].slot_lock, NULL);
+
+ // set them up
+ for(j = 0; j < max_connections_per_slot; j++) {
+ private->slots[i].connections[j].state = T_STATE_IDLE;
+ private->slots[i].connections[j].tx_time.tv_sec = 0;
+ private->slots[i].connections[j].last_poll_time.tv_sec = 0;
+ private->slots[i].connections[j].last_poll_time.tv_usec = 0;
+ private->slots[i].connections[j].chain_buffer = NULL;
+ private->slots[i].connections[j].buffer_length = 0;
+ private->slots[i].connections[j].send_queue = NULL;
+ private->slots[i].connections[j].send_queue_tail = NULL;
+ }
+ }
+
+ // create the pollfds
+ private->slot_pollfds = malloc(sizeof(struct pollfd) * max_slots);
+ if (private->slot_pollfds == NULL) {
+ goto error_exit;
+ }
+ memset(private->slot_pollfds, 0, sizeof(struct pollfd) * max_slots);
+
+ return private;
+
+error_exit:
+ en50221_tl_destroy(private);
+ return NULL;
+}
+
+// Destroy an instance of the transport layer
+void en50221_tl_destroy(en50221_transport_layer tl)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+ int i, j;
+
+ if (private) {
+ if (private->slots) {
+ for(i=0; i< private->max_slots; i++) {
+ if (private->slots[i].connections) {
+ for(j=0; j<private->max_connections_per_slot; j++) {
+ if (private->slots[i].connections[j].chain_buffer) {
+ free(private->slots[i].connections[j].chain_buffer);
+ }
+
+ struct en50221_message *cur_msg = private->slots[i].connections[j].send_queue;
+ while(cur_msg) {
+ struct en50221_message *next_msg = cur_msg->next;
+ free(cur_msg);
+ cur_msg = next_msg;
+ }
+ private->slots[i].connections[j].send_queue = NULL;
+ private->slots[i].connections[j].send_queue_tail = NULL;
+ }
+ free(private->slots[i].connections);
+ pthread_mutex_destroy(&private->slots[i].slot_lock);
+ }
+ }
+ free(private->slots);
+ }
+ if (private->slot_pollfds) {
+ free(private->slot_pollfds);
+ }
+ pthread_mutex_destroy(&private->setcallback_lock);
+ pthread_mutex_destroy(&private->global_lock);
+ free(private);
+ }
+}
+
+// this can be called from the user-space app to
+// register new slots that we should work with
+int en50221_tl_register_slot(en50221_transport_layer tl, int ca_hndl, uint8_t slot,
+ uint32_t response_timeout, uint32_t poll_delay)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+
+ // lock
+ pthread_mutex_lock(&private->global_lock);
+
+ // we browse through the array of slots
+ // to look for the first unused one
+ int i;
+ int16_t slot_id = -1;
+ for(i=0; i < private->max_slots; i++) {
+ if (private->slots[i].ca_hndl == -1) {
+ slot_id = i;
+ break;
+ }
+ }
+ if (slot_id == -1) {
+ private->error = EN50221ERR_OUTOFSLOTS;
+ pthread_mutex_unlock(&private->global_lock);
+ return -1;
+ }
+
+ // set up the slot struct
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ private->slots[slot_id].ca_hndl = ca_hndl;
+ private->slots[slot_id].slot = slot;
+ private->slots[slot_id].response_timeout = response_timeout;
+ private->slots[slot_id].poll_delay = poll_delay;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+
+ private->slots_changed = 1;
+ pthread_mutex_unlock(&private->global_lock);
+ return slot_id;
+}
+
+void en50221_tl_destroy_slot(en50221_transport_layer tl, uint8_t slot_id)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+ int i;
+
+ if (slot_id >= private->max_slots)
+ return;
+
+ // lock
+ pthread_mutex_lock(&private->global_lock);
+
+ // clear the slot
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ private->slots[slot_id].ca_hndl = -1;
+ for(i=0; i<private->max_connections_per_slot; i++) {
+ private->slots[slot_id].connections[i].state = T_STATE_IDLE;
+ private->slots[slot_id].connections[i].tx_time.tv_sec = 0;
+ private->slots[slot_id].connections[i].last_poll_time.tv_sec = 0;
+ private->slots[slot_id].connections[i].last_poll_time.tv_usec = 0;
+ if (private->slots[slot_id].connections[i].chain_buffer) {
+ free(private->slots[slot_id].connections[i].chain_buffer);
+ }
+ private->slots[slot_id].connections[i].chain_buffer = NULL;
+ private->slots[slot_id].connections[i].buffer_length = 0;
+
+ struct en50221_message *cur_msg = private->slots[slot_id].connections[i].send_queue;
+ while(cur_msg) {
+ struct en50221_message *next_msg = cur_msg->next;
+ free(cur_msg);
+ cur_msg = next_msg;
+ }
+ private->slots[slot_id].connections[i].send_queue = NULL;
+ private->slots[slot_id].connections[i].send_queue_tail = NULL;
+ }
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+
+ // tell upper layers
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_tl_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb)
+ cb(cb_arg, T_CALLBACK_REASON_SLOTCLOSE, NULL, 0, slot_id, 0);
+
+ private->slots_changed = 1;
+ pthread_mutex_unlock(&private->global_lock);
+}
+
+int en50221_tl_poll(en50221_transport_layer tl)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+ uint8_t data[4096];
+ int slot_id;
+ int j;
+
+ // make up pollfds if the slots have changed
+ pthread_mutex_lock(&private->global_lock);
+ if (private->slots_changed) {
+ for(slot_id = 0; slot_id < private->max_slots; slot_id++) {
+ if (private->slots[slot_id].ca_hndl != -1) {
+ private->slot_pollfds[slot_id].fd = private->slots[slot_id].ca_hndl;
+ private->slot_pollfds[slot_id].events = POLLIN|POLLPRI|POLLERR;
+ private->slot_pollfds[slot_id].revents = 0;
+ } else {
+ private->slot_pollfds[slot_id].fd = 0;
+ private->slot_pollfds[slot_id].events = 0;
+ private->slot_pollfds[slot_id].revents = 0;
+ }
+ }
+ private->slots_changed = 0;
+ }
+ pthread_mutex_unlock(&private->global_lock);
+
+ // anything happened?
+ if (poll(private->slot_pollfds, private->max_slots, 10) < 0) {
+ private->error_slot = -1;
+ private->error = EN50221ERR_CAREAD;
+ return -1;
+ }
+
+ // go through all slots (even though poll may not have reported any events
+ for(slot_id = 0; slot_id < private->max_slots; slot_id++) {
+
+ // check if this slot is still used and get its handle
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ if (private->slots[slot_id].ca_hndl == -1) {
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ continue;
+ }
+ int ca_hndl = private->slots[slot_id].ca_hndl;
+
+ if (private->slot_pollfds[slot_id].revents & (POLLPRI | POLLIN)) {
+ // read data
+ uint8_t r_slot_id;
+ uint8_t connection_id;
+ int readcnt = dvbca_link_read(ca_hndl, &r_slot_id, &connection_id, data, sizeof(data));
+ if (readcnt < 0) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAREAD;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // process it if we got some
+ if (readcnt > 0) {
+ if (private->slots[slot_id].slot != r_slot_id) {
+ // this message is for an other CAM of the same CA
+ int new_slot_id;
+ for(new_slot_id = 0; new_slot_id < private->max_slots; new_slot_id++) {
+ if ((private->slots[new_slot_id].ca_hndl == ca_hndl) && (private->slots[new_slot_id].slot == r_slot_id))
+ break;
+ }
+ if (new_slot_id != private->max_slots) {
+ // we found the requested CAM
+ pthread_mutex_lock(&private->slots[new_slot_id].slot_lock);
+ if (en50221_tl_process_data(private, new_slot_id, data, readcnt)) {
+ pthread_mutex_unlock(&private->slots[new_slot_id].slot_lock);
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ pthread_mutex_unlock(&private->slots[new_slot_id].slot_lock);
+ } else {
+ private->error = EN50221ERR_BADSLOTID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ }
+ else if (en50221_tl_process_data(private, slot_id, data, readcnt)) {
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ }
+ } else if (private->slot_pollfds[slot_id].revents & POLLERR) {
+ // an error was reported
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAREAD;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // poll the connections on this slot + check for timeouts
+ for(j=0; j < private->max_connections_per_slot; j++) {
+ // ignore connection if idle
+ if (private->slots[slot_id].connections[j].state == T_STATE_IDLE) {
+ continue;
+ }
+
+ // send queued data
+ if (private->slots[slot_id].connections[j].state & (T_STATE_IN_CREATION|T_STATE_ACTIVE|T_STATE_ACTIVE_DELETEQUEUED)) {
+ // send data if there is some to go and we're not waiting for a response already
+ if (private->slots[slot_id].connections[j].send_queue &&
+ (private->slots[slot_id].connections[j].tx_time.tv_sec == 0)) {
+
+ // get the message
+ struct en50221_message *msg = private->slots[slot_id].connections[j].send_queue;
+ if (msg->next != NULL) {
+ private->slots[slot_id].connections[j].send_queue = msg->next;
+ } else {
+ private->slots[slot_id].connections[j].send_queue = NULL;
+ private->slots[slot_id].connections[j].send_queue_tail = NULL;
+ }
+
+ // send the message
+ if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, j, msg->data, msg->length) < 0) {
+ free(msg);
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAWRITE;
+ print(LOG_LEVEL, ERROR, 1, "CAWrite failed");
+ return -1;
+ }
+ gettimeofday(&private->slots[slot_id].connections[j].tx_time, 0);
+
+ // fixup connection state for T_DELETE_T_C
+ if (msg->length && (msg->data[0] == T_DELETE_T_C)) {
+ private->slots[slot_id].connections[j].state = T_STATE_IN_DELETION;
+ if (private->slots[slot_id].connections[j].chain_buffer) {
+ free(private->slots[slot_id].connections[j].chain_buffer);
+ }
+ private->slots[slot_id].connections[j].chain_buffer = NULL;
+ private->slots[slot_id].connections[j].buffer_length = 0;
+ }
+
+ free(msg);
+ }
+ }
+
+ // poll it if we're not expecting a reponse and the poll time has elapsed
+ if (private->slots[slot_id].connections[j].state & T_STATE_ACTIVE) {
+ if ((private->slots[slot_id].connections[j].tx_time.tv_sec == 0) &&
+ (time_after(private->slots[slot_id].connections[j].last_poll_time, private->slots[slot_id].poll_delay))) {
+
+ gettimeofday(&private->slots[slot_id].connections[j].last_poll_time, 0);
+ if (en50221_tl_poll_tc(private, slot_id, j)) {
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ }
+ }
+
+ // check for timeouts - in any state
+ if (private->slots[slot_id].connections[j].tx_time.tv_sec &&
+ (time_after(private->slots[slot_id].connections[j].tx_time, private->slots[slot_id].response_timeout))) {
+
+ if (private->slots[slot_id].connections[j].state & (T_STATE_IN_CREATION|T_STATE_IN_DELETION)) {
+ private->slots[slot_id].connections[j].state = T_STATE_IDLE;
+ } else if (private->slots[slot_id].connections[j].state & (T_STATE_ACTIVE|T_STATE_ACTIVE_DELETEQUEUED)) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_TIMEOUT;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ }
+ }
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ }
+
+ return 0;
+}
+
+void en50221_tl_register_callback(en50221_transport_layer tl, en50221_tl_callback callback, void *arg)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+
+ pthread_mutex_lock(&private->setcallback_lock);
+ private->callback = callback;
+ private->callback_arg = arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+}
+
+int en50221_tl_get_error_slot(en50221_transport_layer tl)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+ return private->error_slot;
+}
+
+int en50221_tl_get_error(en50221_transport_layer tl)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+ return private->error;
+}
+
+int en50221_tl_send_data(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_size)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+
+#ifdef DEBUG_TXDATA
+ printf("[[[[[[[[[[[[[[[[[[[[\n");
+ uint32_t ii=0;
+ for(ii=0;ii<data_size;ii++) {
+ printf("%02x: %02x\n", ii, data[ii]);
+ }
+ printf("]]]]]]]]]]]]]]]]]]]]\n");
+#endif
+
+ if (slot_id >= private->max_slots) {
+ private->error = EN50221ERR_BADSLOTID;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ if (private->slots[slot_id].ca_hndl == -1) {
+ private->error = EN50221ERR_BADSLOTID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ if (connection_id >= private->max_connections_per_slot) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCONNECTIONID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) {
+ private->error = EN50221ERR_BADCONNECTIONID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // allocate msg structure
+ struct en50221_message *msg = malloc(sizeof(struct en50221_message)+data_size+10);
+ if (msg == NULL) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_OUTOFMEMORY;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // make up data to send
+ int length_field_len;
+ msg->data[0] = T_DATA_LAST;
+ if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) {
+ free(msg);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_ASNENCODE;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ msg->data[1 + length_field_len] = connection_id;
+ memcpy(msg->data+1+length_field_len+1, data, data_size);
+ msg->length = 1+length_field_len+1+data_size;
+
+ // queue it for transmission
+ queue_message(private, slot_id, connection_id, msg);
+
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return 0;
+}
+
+int en50221_tl_send_datav(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id,
+ struct iovec *vector, int iov_count)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+
+#ifdef DEBUG_TXDATA
+ printf("[[[[[[[[[[[[[[[[[[[[\n");
+ uint32_t ii=0;
+ uint32_t iipos=0;
+ for(ii=0;ii<(uint32_t) iov_count;ii++) {
+ uint32_t jj;
+ for(jj=0; jj< vector[ii].iov_len; jj++) {
+ printf("%02x: %02x\n", jj+iipos, *((uint8_t*) (vector[ii].iov_base) +jj));
+ }
+ iipos += vector[ii].iov_len;
+ }
+ printf("]]]]]]]]]]]]]]]]]]]]\n");
+#endif
+
+ if (slot_id >= private->max_slots) {
+ private->error = EN50221ERR_BADSLOTID;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ if (private->slots[slot_id].ca_hndl == -1) {
+ private->error = EN50221ERR_BADSLOTID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ if (connection_id >= private->max_connections_per_slot) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCONNECTIONID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) {
+ private->error = EN50221ERR_BADCONNECTIONID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // calculate the total length of the data to send
+ uint32_t data_size = 0;
+ int i;
+ for(i=0; i< iov_count; i++) {
+ data_size += vector[i].iov_len;
+ }
+
+ // allocate msg structure
+ struct en50221_message *msg = malloc(sizeof(struct en50221_message)+data_size+10);
+ if (msg == NULL) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_OUTOFMEMORY;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // make up data to send
+ int length_field_len;
+ msg->data[0] = T_DATA_LAST;
+ if ((length_field_len = asn_1_encode(data_size + 1, msg->data + 1, 3)) < 0) {
+ free(msg);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_ASNENCODE;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ msg->data[1 + length_field_len] = connection_id;
+ msg->length = 1+length_field_len+1+data_size;
+ msg->next = NULL;
+
+ // merge the iovecs
+ uint32_t pos = 1+length_field_len+1;
+ for(i=0; i< iov_count; i++) {
+ memcpy(msg->data+pos, vector[i].iov_base, vector[i].iov_len);
+ pos += vector[i].iov_len;
+ }
+
+ // queue it for transmission
+ queue_message(private, slot_id, connection_id, msg);
+
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return 0;
+}
+
+int en50221_tl_new_tc(en50221_transport_layer tl, uint8_t slot_id)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+
+ // check
+ if (slot_id >= private->max_slots) {
+ private->error = EN50221ERR_BADSLOTID;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ if (private->slots[slot_id].ca_hndl == -1) {
+ private->error = EN50221ERR_BADSLOTID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // allocate a new connection if possible
+ int conid = en50221_tl_alloc_new_tc(private, slot_id);
+ if (conid == -1) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_OUTOFCONNECTIONS;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // allocate msg structure
+ struct en50221_message *msg = malloc(sizeof(struct en50221_message)+3);
+ if (msg == NULL) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_OUTOFMEMORY;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // make up the data to send
+ msg->data[0] = T_CREATE_T_C;
+ msg->data[1] = 1;
+ msg->data[2] = conid;
+ msg->length = 3;
+ msg->next = NULL;
+
+ // queue it for transmission
+ queue_message(private, slot_id, conid, msg);
+
+ // done
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return conid;
+}
+
+int en50221_tl_del_tc(en50221_transport_layer tl, uint8_t slot_id, uint8_t connection_id)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+
+ // check
+ if (slot_id >= private->max_slots) {
+ private->error = EN50221ERR_BADSLOTID;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ if (private->slots[slot_id].ca_hndl == -1) {
+ private->error = EN50221ERR_BADSLOTID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ if (connection_id >= private->max_connections_per_slot) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCONNECTIONID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ if (!(private->slots[slot_id].connections[connection_id].state &
+ (T_STATE_ACTIVE|T_STATE_IN_DELETION))) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADSTATE;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // allocate msg structure
+ struct en50221_message *msg = malloc(sizeof(struct en50221_message)+3);
+ if (msg == NULL) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_OUTOFMEMORY;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+
+ // make up the data to send
+ msg->data[0] = T_DELETE_T_C;
+ msg->data[1] = 1;
+ msg->data[2] = connection_id;
+ msg->length = 3;
+ msg->next = NULL;
+
+ // queue it for transmission
+ queue_message(private, slot_id, connection_id, msg);
+ private->slots[slot_id].connections[connection_id].state = T_STATE_ACTIVE_DELETEQUEUED;
+
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return 0;
+}
+
+int en50221_tl_get_connection_state(en50221_transport_layer tl,
+ uint8_t slot_id, uint8_t connection_id)
+{
+ struct en50221_transport_layer_private *private = (struct en50221_transport_layer_private *) tl;
+
+ if (slot_id >= private->max_slots) {
+ private->error = EN50221ERR_BADSLOTID;
+ return -1;
+ }
+
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ if (private->slots[slot_id].ca_hndl == -1) {
+ private->error = EN50221ERR_BADSLOTID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ if (connection_id >= private->max_connections_per_slot) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCONNECTIONID;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ return -1;
+ }
+ int state = private->slots[slot_id].connections[connection_id].state;
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+
+ return state;
+}
+
+
+
+
+// ask the module for new data
+static int en50221_tl_poll_tc(struct en50221_transport_layer_private *private, uint8_t slot_id, uint8_t connection_id)
+{
+ gettimeofday(&private->slots[slot_id].connections[connection_id].tx_time, 0);
+
+ // send command
+ uint8_t hdr[3];
+ hdr[0] = T_DATA_LAST;
+ hdr[1] = 1;
+ hdr[2] = connection_id;
+ if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAWRITE;
+ return -1;
+ }
+ return 0;
+}
+
+// handle incoming data
+static int en50221_tl_process_data(struct en50221_transport_layer_private *private, uint8_t slot_id,
+ uint8_t *data, uint32_t data_length)
+{
+ int result;
+
+#ifdef DEBUG_RXDATA
+ printf("-------------------\n");
+ uint32_t ii=0;
+ for(ii=0; ii< data_length; ii++) {
+ printf("%02x: %02x\n", ii, data[ii]);
+ }
+ printf("+++++++++++++++++++\n");
+#endif
+
+ // process the received data
+ while(data_length) {
+ // parse the header
+ uint8_t tpdu_tag = data[0];
+ uint16_t asn_data_length;
+ int length_field_len;
+ if ((length_field_len = asn_1_decode(&asn_data_length, data + 1, data_length - 1)) < 0) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid asn from module on slot %02x\n", slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+ if ((asn_data_length < 1) || (asn_data_length > (data_length-(1+length_field_len)))) {
+ print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+ uint8_t connection_id = data[1 + length_field_len];
+ data += 1 + length_field_len + 1;
+ data_length -= (1 + length_field_len + 1);
+ asn_data_length--;
+
+ // check the connection_id
+ if (connection_id >= private->max_connections_per_slot) {
+ print(LOG_LEVEL, ERROR, 1, "Received bad connection id %02x from module on slot %02x\n", connection_id, slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCONNECTIONID;
+ return -1;
+ }
+
+ // process the TPDUs
+ switch(tpdu_tag) {
+ case T_C_T_C_REPLY:
+ if ((result = en50221_tl_handle_create_tc_reply(private, slot_id, connection_id)) < 0) {
+ return -1;
+ }
+ break;
+ case T_DELETE_T_C:
+ if ((result = en50221_tl_handle_delete_tc(private, slot_id, connection_id)) < 0) {
+ return -1;
+ }
+ break;
+ case T_D_T_C_REPLY:
+ if ((result = en50221_tl_handle_delete_tc_reply(private, slot_id, connection_id)) < 0) {
+ return -1;
+ }
+ break;
+ case T_REQUEST_T_C:
+ if ((result = en50221_tl_handle_request_tc(private, slot_id, connection_id)) < 0) {
+ return -1;
+ }
+ break;
+ case T_DATA_MORE:
+ if ((result = en50221_tl_handle_data_more(private, slot_id, connection_id, data, asn_data_length)) < 0) {
+ return -1;
+ }
+ break;
+ case T_DATA_LAST:
+ if ((result = en50221_tl_handle_data_last(private, slot_id, connection_id, data, asn_data_length)) < 0) {
+ return -1;
+ }
+ break;
+ case T_SB:
+ if ((result = en50221_tl_handle_sb(private, slot_id, connection_id, data, asn_data_length)) < 0) {
+ return -1;
+ }
+ break;
+ default:
+ print(LOG_LEVEL, ERROR, 1, "Recieved unexpected TPDU tag %02x from module on slot %02x\n",
+ tpdu_tag, slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ // skip over the consumed data
+ data += asn_data_length;
+ data_length -= asn_data_length;
+ }
+
+ return 0;
+}
+
+static int en50221_tl_handle_create_tc_reply(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id)
+{
+ // set this connection to state active
+ if (private->slots[slot_id].connections[connection_id].state == T_STATE_IN_CREATION) {
+ private->slots[slot_id].connections[connection_id].state = T_STATE_ACTIVE;
+ private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0;
+
+ // tell upper layers
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_tl_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb)
+ cb(cb_arg, T_CALLBACK_REASON_CONNECTIONOPEN, NULL, 0, slot_id, connection_id);
+ } else {
+ print(LOG_LEVEL, ERROR, 1, "Received T_C_T_C_REPLY for connection not in "
+ "T_STATE_IN_CREATION from module on slot %02x\n", slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int en50221_tl_handle_delete_tc(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id)
+{
+ // immediately delete this connection and send D_T_C_REPLY
+ if (private->slots[slot_id].connections[connection_id].state & (T_STATE_ACTIVE|T_STATE_IN_DELETION))
+ {
+ // clear down the slot
+ private->slots[slot_id].connections[connection_id].state = T_STATE_IDLE;
+ if (private->slots[slot_id].connections[connection_id].chain_buffer) {
+ free(private->slots[slot_id].connections[connection_id].chain_buffer);
+ }
+ private->slots[slot_id].connections[connection_id].chain_buffer = NULL;
+ private->slots[slot_id].connections[connection_id].buffer_length = 0;
+
+ // send the reply
+ uint8_t hdr[3];
+ hdr[0] = T_D_T_C_REPLY;
+ hdr[1] = 1;
+ hdr[2] = connection_id;
+ if (dvbca_link_write(private->slots[slot_id].ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAWRITE;
+ return -1;
+ }
+
+ // tell upper layers
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_tl_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb)
+ cb(cb_arg, T_CALLBACK_REASON_CONNECTIONCLOSE, NULL, 0, slot_id, connection_id);
+ }
+ else {
+ print(LOG_LEVEL, ERROR, 1, "Received T_DELETE_T_C for inactive connection from module on slot %02x\n",
+ slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int en50221_tl_handle_delete_tc_reply(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id)
+{
+ // delete this connection, should be in T_STATE_IN_DELETION already
+ if (private->slots[slot_id].connections[connection_id].state == T_STATE_IN_DELETION) {
+ private->slots[slot_id].connections[connection_id].state = T_STATE_IDLE;
+ } else {
+ print(LOG_LEVEL, ERROR, 1, "Received T_D_T_C_REPLY received for connection not in "
+ "T_STATE_IN_DELETION from module on slot %02x\n", slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int en50221_tl_handle_request_tc(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id)
+{
+ // allocate a new connection if possible
+ int conid = en50221_tl_alloc_new_tc(private, slot_id);
+ int ca_hndl = private->slots[slot_id].ca_hndl;
+ if (conid == -1) {
+ print(LOG_LEVEL, ERROR, 1, "Too many connections requested by module on slot %02x\n", slot_id);
+
+ // send the error
+ uint8_t hdr[4];
+ hdr[0] = T_T_C_ERROR;
+ hdr[1] = 2;
+ hdr[2] = connection_id;
+ hdr[3] = 1;
+ if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 4) < 0) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAWRITE;
+ return -1;
+ }
+ private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0;
+ } else {
+ // send the NEW_T_C on the connection we received it on
+ uint8_t hdr[4];
+ hdr[0] = T_NEW_T_C;
+ hdr[1] = 2;
+ hdr[2] = connection_id;
+ hdr[3] = conid;
+ if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 4) < 0) {
+ private->slots[slot_id].connections[conid].state = T_STATE_IDLE;
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAWRITE;
+ return -1;
+ }
+ private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0;
+
+ // send the CREATE_T_C on the new connnection
+ hdr[0] = T_CREATE_T_C;
+ hdr[1] = 1;
+ hdr[2] = conid;
+ if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, conid, hdr, 3) < 0) {
+ private->slots[slot_id].connections[conid].state = T_STATE_IDLE;
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAWRITE;
+ return -1;
+ }
+ gettimeofday(&private->slots[slot_id].connections[conid].tx_time, 0);
+
+ // tell upper layers
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_tl_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb)
+ cb(cb_arg, T_CALLBACK_REASON_CAMCONNECTIONOPEN, NULL, 0, slot_id, conid);
+ }
+
+ return 0;
+}
+
+static int en50221_tl_handle_data_more(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_length)
+{
+ // connection in correct state?
+ if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) {
+ print(LOG_LEVEL, ERROR, 1, "Received T_DATA_MORE for connection not in "
+ "T_STATE_ACTIVE from module on slot %02x\n", slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ // a chained data packet is coming in, save
+ // it to the buffer and wait for more
+ private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0;
+ int new_data_length =
+ private->slots[slot_id].connections[connection_id].buffer_length + data_length;
+ uint8_t *new_data_buffer =
+ realloc(private->slots[slot_id].connections[connection_id].chain_buffer, new_data_length);
+ if (new_data_buffer == NULL) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_OUTOFMEMORY;
+ return -1;
+ }
+ private->slots[slot_id].connections[connection_id].chain_buffer = new_data_buffer;
+
+ memcpy(private->slots[slot_id].connections[connection_id].chain_buffer +
+ private->slots[slot_id].connections[connection_id].buffer_length,
+ data, data_length);
+ private->slots[slot_id].connections[connection_id].buffer_length = new_data_length;
+
+ return 0;
+}
+
+static int en50221_tl_handle_data_last(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_length)
+{
+ // connection in correct state?
+ if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) {
+ print(LOG_LEVEL, ERROR, 1, "Received T_DATA_LAST received for connection not in "
+ "T_STATE_ACTIVE from module on slot %02x\n", slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ // last package of a chain or single package comes in
+ private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0;
+ if (private->slots[slot_id].connections[connection_id].chain_buffer == NULL)
+ {
+ // single package => dispatch immediately
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_tl_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+
+ if (cb && data_length) {
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ cb(cb_arg, T_CALLBACK_REASON_DATA, data, data_length, slot_id, connection_id);
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ }
+ }
+ else
+ {
+ int new_data_length = private->slots[slot_id].connections[connection_id].buffer_length + data_length;
+ uint8_t *new_data_buffer =
+ realloc(private->slots[slot_id].connections[connection_id].chain_buffer, new_data_length);
+ if (new_data_buffer == NULL) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_OUTOFMEMORY;
+ return -1;
+ }
+
+ memcpy(new_data_buffer + private->slots[slot_id].connections[connection_id].buffer_length, data, data_length);
+
+ // clean the buffer position
+ private->slots[slot_id].connections[connection_id].chain_buffer = NULL;
+ private->slots[slot_id].connections[connection_id].buffer_length = 0;
+
+ // tell the upper layers
+ pthread_mutex_lock(&private->setcallback_lock);
+ en50221_tl_callback cb = private->callback;
+ void *cb_arg = private->callback_arg;
+ pthread_mutex_unlock(&private->setcallback_lock);
+ if (cb && data_length) {
+ pthread_mutex_unlock(&private->slots[slot_id].slot_lock);
+ cb(cb_arg, T_CALLBACK_REASON_DATA, new_data_buffer, new_data_length, slot_id, connection_id);
+ pthread_mutex_lock(&private->slots[slot_id].slot_lock);
+ }
+
+ free(new_data_buffer);
+ }
+
+ return 0;
+}
+
+static int en50221_tl_handle_sb(struct en50221_transport_layer_private *private,
+ uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_length)
+{
+ // is the connection id ok?
+ if (private->slots[slot_id].connections[connection_id].state != T_STATE_ACTIVE) {
+ print(LOG_LEVEL, ERROR, 1, "Received T_SB for connection not in T_STATE_ACTIVE from module on slot %02x\n",
+ slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ // did we get enough data in the T_SB?
+ if (data_length != 1) {
+ print(LOG_LEVEL, ERROR, 1, "Recieved T_SB with invalid length from module on slot %02x\n", slot_id);
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_BADCAMDATA;
+ return -1;
+ }
+
+ // tell it to send the data if it says there is some
+ if (data[0] & 0x80) {
+ int ca_hndl = private->slots[slot_id].ca_hndl;
+
+ // send the RCV
+ uint8_t hdr[3];
+ hdr[0] = T_RCV;
+ hdr[1] = 1;
+ hdr[2] = connection_id;
+ if (dvbca_link_write(ca_hndl, private->slots[slot_id].slot, connection_id, hdr, 3) < 0) {
+ private->error_slot = slot_id;
+ private->error = EN50221ERR_CAWRITE;
+ return -1;
+ }
+ gettimeofday(&private->slots[slot_id].connections[connection_id].tx_time, 0);
+
+ } else {
+ // no data - indicate not waiting for anything now
+ private->slots[slot_id].connections[connection_id].tx_time.tv_sec = 0;
+ }
+
+ return 0;
+}
+
+static int en50221_tl_alloc_new_tc(struct en50221_transport_layer_private *private, uint8_t slot_id)
+{
+ // we browse through the array of connection
+ // types, to look for the first unused one
+ int i, conid = -1;
+ for(i=1; i < private->max_connections_per_slot; i++) {
+ if (private->slots[slot_id].connections[i].state == T_STATE_IDLE) {
+ conid = i;
+ break;
+ }
+ }
+ if (conid == -1) {
+ print(LOG_LEVEL, ERROR, 1, "CREATE_T_C failed: no more connections available\n");
+ return -1;
+ }
+
+ // set up the connection struct
+ private->slots[slot_id].connections[conid].state = T_STATE_IN_CREATION;
+ private->slots[slot_id].connections[conid].chain_buffer = NULL;
+ private->slots[slot_id].connections[conid].buffer_length = 0;
+
+ return conid;
+}
+
+static void queue_message(struct en50221_transport_layer_private *private, uint8_t slot_id,
+ uint8_t connection_id, struct en50221_message *msg)
+{
+ msg->next = NULL;
+ if (private->slots[slot_id].connections[connection_id].send_queue_tail) {
+ private->slots[slot_id].connections[connection_id].send_queue_tail->next = msg;
+ } else {
+ private->slots[slot_id].connections[connection_id].send_queue = msg;
+ private->slots[slot_id].connections[connection_id].send_queue_tail = msg;
+ }
+}
diff --git a/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h
new file mode 100644
index 0000000..59dc64c
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvben50221/en50221_transport.h
@@ -0,0 +1,231 @@
+/*
+ en50221 encoder An implementation for libdvb
+ an implementation for the en50221 session layer
+
+ Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
+ Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
+ Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#ifndef __EN50221_TRANSPORT_H__
+#define __EN50221_TRANSPORT_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/uio.h>
+
+/**
+ * Callback reasons.
+ */
+#define T_CALLBACK_REASON_CONNECTIONOPEN 0x00 // A connection we opened _to_ the cam has been ACKed
+#define T_CALLBACK_REASON_CAMCONNECTIONOPEN 0x01 // The cam has opened a connection to _us_.
+#define T_CALLBACK_REASON_DATA 0x02 // Data received
+#define T_CALLBACK_REASON_CONNECTIONCLOSE 0x03 // The cam has told us to close a connection.
+#define T_CALLBACK_REASON_SLOTCLOSE 0x04 // The cam in the supplied slot id has been removed.
+
+// these are the states a TC can be in
+#define T_STATE_IDLE 0x01 // this transport connection is not in use
+#define T_STATE_ACTIVE 0x02 // this transport connection is in use
+#define T_STATE_ACTIVE_DELETEQUEUED 0x04 // this transport connection is about to be deleted
+#define T_STATE_IN_CREATION 0x08 // this transport waits for a T_C_T_C_REPLY to become active
+#define T_STATE_IN_DELETION 0x10 // this transport waits for T_D_T_C_REPLY to become idle again
+
+/**
+ * Opaque type representing a transport layer.
+ */
+typedef void *en50221_transport_layer;
+
+/**
+ * Type definition for callback function - used when events are received from a module.
+ *
+ * **IMPORTANT** For all callback reasons except T_CALLBACK_REASON_DATA, an internal lock is held in the
+ * transport layer. Therefore, to avoid deadlock, you *must not* call back into the transport layer for
+ * these reasons.
+ *
+ * However, for T_CALLBACK_REASON_DATA, the internal lock is not held, so calling back into the transport
+ * layer is fine in this case.
+ *
+ * @param arg Private data.
+ * @param reason One of the T_CALLBACK_REASON_* values.
+ * @param data The data.
+ * @param data_length Length of the data.
+ * @param slot_id Slot_id the data was received from.
+ * @param connection_id Connection_id the data was received from.
+ */
+typedef void (*en50221_tl_callback)(void *arg, int reason,
+ uint8_t *data, uint32_t data_length,
+ uint8_t slot_id, uint8_t connection_id);
+
+
+/**
+ * Construct a new instance of the transport layer.
+ *
+ * @param max_slots Maximum number of slots to support.
+ * @param max_connections_per_slot Maximum connections per slot.
+ * @return The en50221_transport_layer instance, or NULL on error.
+ */
+extern en50221_transport_layer en50221_tl_create(uint8_t max_slots, uint8_t max_connections_per_slot);
+
+/**
+ * Destroy an instance of the transport layer.
+ *
+ * @param tl The en50221_transport_layer instance.
+ */
+extern void en50221_tl_destroy(en50221_transport_layer tl);
+
+/**
+ * Register a new slot with the library.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param ca_hndl FD for talking to the slot.
+ * @param slot CAM slot where the requested CAM of the CA is in.
+ * @param response_timeout Maximum timeout in ms to a response we send before signalling a timeout.
+ * @param poll_delay Interval between polls in ms.
+ * @return slot_id on sucess, or -1 on error.
+ */
+extern int en50221_tl_register_slot(en50221_transport_layer tl, int ca_hndl,
+ uint8_t slot, uint32_t response_timeout,
+ uint32_t poll_delay);
+
+/**
+ * Destroy a registered slot - e.g. if a CAM is removed, or an error occurs. Does
+ * not attempt to reset the CAM.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param slot_id Slot to destroy.
+ */
+extern void en50221_tl_destroy_slot(en50221_transport_layer tl, uint8_t slot_id);
+
+/**
+ * Performs one iteration of the transport layer poll -
+ * checking for incoming data furthermore it will handle
+ * the timeouts of certain commands like T_DELETE_T_C it
+ * should be called by the application regularly, generally
+ * faster than the poll delay.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @return 0 on succes, or -1 if there was an error of some sort.
+ */
+extern int en50221_tl_poll(en50221_transport_layer tl);
+
+/**
+ * Register the callback for data reception.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param callback The callback. Set to NULL to remove the callback completely.
+ * @param arg Private data passed as arg0 of the callback.
+ */
+extern void en50221_tl_register_callback(en50221_transport_layer tl,
+ en50221_tl_callback callback, void *arg);
+
+/**
+ * Gets the ID of the slot an error occurred on.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @return The offending slot id.
+ */
+extern int en50221_tl_get_error_slot(en50221_transport_layer tl);
+
+/**
+ * Gets the last error.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @return One of the EN50221ERR_* values.
+ */
+extern int en50221_tl_get_error(en50221_transport_layer tl);
+
+/**
+ * This function is used to take a data-block, pack into
+ * into a TPDU (DATA_LAST) and send it to the device
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param slot_id ID of the slot.
+ * @param connection_id Connection id.
+ * @param data Data to send.
+ * @param data_length Number of bytes to send.
+ * @return 0 on success, or -1 on error.
+ */
+extern int en50221_tl_send_data(en50221_transport_layer tl,
+ uint8_t slot_id, uint8_t connection_id,
+ uint8_t *data, uint32_t data_length);
+
+/**
+ * This function is used to take a data-block, pack into
+ * into a TPDU (DATA_LAST) and send it to the device
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param slot_id ID of the slot.
+ * @param connection_id Connection id.
+ * @param vector iov to send.
+ * @param io_count Number of elements in vector.
+ * @return 0 on success, or -1 on error.
+ */
+extern int en50221_tl_send_datav(en50221_transport_layer tl, uint8_t slot_id,
+ uint8_t connection_id, struct iovec *vector,
+ int iov_count);
+
+/**
+ * Create a new transport connection to the cam.
+ *
+ * **IMPORTANT** When this function returns, it means the request to create a connection
+ * has been submitted. You will need to poll using en50221_tl_get_connection_state() to find out
+ * if/when the connection is established. A callback with T_CALLBACK_REASON_CONNECTIONOPEN reason
+ * will also be sent when it is acked by the CAM.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param slot_id ID of the slot.
+ * @return The allocated connection id on success, or -1 on error.
+ */
+extern int en50221_tl_new_tc(en50221_transport_layer tl, uint8_t slot_id);
+
+/**
+ * Deallocates a transport connection.
+ *
+ * **IMPORTANT** When this function returns, it means the request to destroy a connection
+ * has been submitted. You will need to poll using en50221_tl_get_connection_state() to find out
+ * if/when the connection is destroyed.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param slot_id ID of the slot.
+ * @param connection_id Connection id to send the request _on_.
+ * @return 0 on success, or -1 on error.
+ */
+extern int en50221_tl_del_tc(en50221_transport_layer tl, uint8_t slot_id,
+ uint8_t connection_id);
+
+/**
+ * Checks the state of a connection.
+ *
+ * @param tl The en50221_transport_layer instance.
+ * @param slot_id ID of the slot.
+ * @param connection_id Connection id to send the request _on_.
+ * @return One of the T_STATE_* values.
+ */
+extern int en50221_tl_get_connection_state(en50221_transport_layer tl,
+ uint8_t slot_id, uint8_t connection_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h b/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h
new file mode 100644
index 0000000..75713f4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbmisc/dvbmisc.h
@@ -0,0 +1,72 @@
+/*
+ libdvbmisc - DVB miscellaneous library
+
+ Copyright (C) 2005 Manu Abraham <manu@kromtek.com>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#ifndef DVB_MISC_H
+#define DVB_MISC_H
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#define ERROR 0
+#define NOTICE 1
+#define INFO 2
+#define DEBUG 3
+
+#define print(x, y, z, fmt, arg...) do { \
+ if (z) { \
+ if ((x > ERROR) && (x > y)) \
+ vprint("%s: " fmt "\n", __func__ , ##arg); \
+ else if ((x > NOTICE) && (x > y)) \
+ vprint("%s: " fmt "\n",__func__ , ##arg); \
+ else if ((x > INFO) && (x > y)) \
+ vprint("%s: " fmt "\n", __func__ , ##arg); \
+ else if ((x > DEBUG) && (x > y)) \
+ vprint("%s: " fmt "\n", __func__ , ##arg); \
+ } else { \
+ if (x > y) \
+ vprint(fmt, ##arg); \
+ } \
+} while(0)
+
+static inline void vprint(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+static inline int time_after(struct timeval oldtime, uint32_t delta_ms)
+{
+ // calculate the oldtime + add on the delta
+ uint64_t oldtime_ms = (oldtime.tv_sec * 1000) + (oldtime.tv_usec / 1000);
+ oldtime_ms += delta_ms;
+
+ // calculate the nowtime
+ struct timeval nowtime;
+ gettimeofday(&nowtime, 0);
+ uint64_t nowtime_ms = (nowtime.tv_sec * 1000) + (nowtime.tv_usec / 1000);
+
+ // check
+ return nowtime_ms > oldtime_ms;
+}
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/Makefile.am
new file mode 100644
index 0000000..071f310
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/Makefile.am
@@ -0,0 +1,17 @@
+noinst_LTLIBRARIES = libucsi.la
+
+SUBDIRS = dvb mpeg .
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib
+
+libucsi_la_SOURCES = crc32.c \
+ section_buf.c \
+ transport_packet.c
+
+libucsi_la_LDFLAGS = ./mpeg \
+ ./dvb
+
+libucsi_la_LIBADD = ./mpeg/libdvbmpeg.la \
+ ./dvb/libdvbdvb.la
+
+CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC
diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h
new file mode 100644
index 0000000..a18b29d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/descriptor.h
@@ -0,0 +1,70 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_ATSC_DESCRIPTOR_H
+#define _UCSI_ATSC_DESCRIPTOR_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/endianops.h>
+
+/**
+ * Enumeration of ATSC descriptor tags.
+ */
+enum atsc_descriptor_tag {
+
+/* A 52/A describes a
+ * dtag_atsc_ac3_registration = 0x05, */
+
+/* A90 describes a
+ * dtag_atsc_association_tag = 0x14, */
+
+ dtag_atsc_stuffing = 0x80,
+ dtag_atsc_ac3_audio = 0x81,
+ dtag_atsc_caption_service = 0x86,
+ dtag_atsc_content_advisory = 0x87,
+ dtag_atsc_ca = 0x88,
+ dtag_atsc_extended_channel_name = 0xa0,
+ dtag_atsc_service_location = 0xa1,
+ dtag_atsc_time_shifted_service = 0xa2,
+ dtag_atsc_component_name = 0xa3,
+ dtag_atsc_data_service = 0xa4,
+ dtag_atsc_pid_count = 0xa5,
+ dtag_atsc_download = 0xa6,
+ dtag_atsc_MPE = 0xa7,
+ dtag_atsc_dcc_departing_request = 0xa8,
+ dtag_atsc_dcc_arriving_request = 0xa9,
+ dtag_atsc_redistribution_control = 0xaa,
+ dtag_atsc_dcc_location_code = 0xab,
+ dtag_atsc_private_information = 0xad,
+ dtag_atsc_module_link = 0xb4,
+ dtag_atsc_crc32 = 0xb5,
+ dtag_atsc_group_link = 0xb8,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h b/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h
new file mode 100644
index 0000000..e693b9d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/atsc/section.h
@@ -0,0 +1,69 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_ATSC_SECTION_H
+#define _UCSI_ATSC_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Enumeration of ATSC section tags.
+ */
+enum atsc_section_tag {
+/* 0xC0-0xC6 [ATSC coordinated values which are defined in other standards.] */
+ stag_atsc_master_guide = 0xc7,
+ stag_atsc_terrestrial_virtual_channel = 0xc8,
+ stag_atsc_cable_virtual_channel = 0xc9,
+ stag_atsc_rating_region = 0xca,
+ stag_atsc_event_informationen = 0xcb,
+ stag_atsc_extended_text = 0xcc,
+ stag_atsc_system_time = 0xcd,
+
+ stag_atsc_data_event = 0xce,
+ stag_atsc_data_service = 0xcf,
+ stag_atsc_network_resources = 0xd1,
+ stag_atsc_long_term_serivce = 0xd2,
+/* identical to DVB/ISO ?
+ 0x3F DSM-CC Addressable Section Table
+ 0x3B DSM-CC Section Table
+ 0x3C DSM-CC Section Table */
+
+ /* 0xCE-0xD2 [ATSC coordinated values which are defined in other standards.] */
+ stag_atsc_directed_channel_change = 0xd3,
+ stag_atsc_directed_channel_change_selection_code = 0xd4,
+
+ /* 0xD5-0xDF [ATSC coordinated values which are defined in other standards.] */
+ stag_atsc_aggregate_event_information = 0xd6,
+ stag_atsc_aggregate_extended_text = 0xd7,
+ stag_atsc_satellite_virtual_channel = 0xda,
+
+ /* 0xE0-0xE5 [Used in other systems] */
+ /* 0xE6-0xFE [Reserved for future ATSC use] */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/crc32.c b/kaffeine/src/input/dvb/lib/libucsi/crc32.c
new file mode 100644
index 0000000..dc1de5c
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/crc32.c
@@ -0,0 +1,89 @@
+/**
+ * crc32 calculation routines.
+ *
+ * Copyright (c) 2005 by Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdint.h>
+
+uint32_t crc32tbl[] =
+{
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+ 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+ 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+ 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+ 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+ 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+ 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+ 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+ 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+ 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+ 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+ 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+ 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+ 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+ 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+ 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+ 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+ 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+ 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+ 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+ 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+ 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+ 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+ 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+ 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+ 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+ 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+ 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+ 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+ 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+ 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+ 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+ 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+ 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+ 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+ 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+ 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+ 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+ 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
diff --git a/kaffeine/src/input/dvb/lib/libucsi/crc32.h b/kaffeine/src/input/dvb/lib/libucsi/crc32.h
new file mode 100644
index 0000000..5d77e84
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/crc32.h
@@ -0,0 +1,58 @@
+/**
+ * crc32 calculation routines.
+ *
+ * Copyright (c) 2005 by Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_CRC32_H
+#define _UCSI_CRC32_H 1
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define CRC32_INIT (~0)
+
+extern uint32_t crc32tbl[];
+
+/**
+ * Calculate a CRC32 over a piece of data.
+ *
+ * @param crc Current CRC value (use CRC32_INIT for first call).
+ * @param buf Buffer to calculate over.
+ * @param len Number of bytes.
+ * @return Calculated CRC.
+ */
+static inline uint32_t crc32(uint32_t crc, uint8_t* buf, int len)
+{
+ int i;
+
+ for (i=0; i< len; i++) {
+ crc = (crc << 8) ^ crc32tbl[((crc >> 24) ^ buf[i]) & 0xff];
+ }
+
+ return crc;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/descriptor.h
new file mode 100644
index 0000000..809936d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/descriptor.h
@@ -0,0 +1,129 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DESCRIPTOR_H
+#define _UCSI_DESCRIPTOR_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/endianops.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/**
+ * Generic descriptor header.
+ */
+struct descriptor {
+ uint8_t tag;
+ uint8_t len;
+} __ucsi_packed;
+
+/**
+ * Retreive pointer to the next descriptor structure.
+ *
+ * @param buf The buffer of descriptors.
+ * @param len Size of the buffer.
+ * @param pos Current descriptor.
+ * @return Pointer to next descriptor, or NULL if there are none.
+ */
+static inline struct descriptor *
+ next_descriptor(uint8_t * buf, int len, struct descriptor * pos)
+{
+ uint8_t* next;
+
+ if (pos == NULL)
+ return NULL;
+
+ next = (uint8_t*) pos + 2 + pos->len;
+ if (next >= buf + len)
+ return NULL;
+
+ return (struct descriptor *) next;
+}
+
+
+/**
+ * The unknown descriptor.
+ */
+struct unknown_descriptor {
+ struct descriptor d;
+
+ /* uint8_t data [] */
+} __ucsi_packed;
+
+/**
+ * Retrieve pointer to the unknown descriptor's data field.
+ *
+ * @param d The descriptor.
+ * @return Pointer to the data field.
+ */
+static inline uint8_t *
+ unknown_descriptor_data(struct unknown_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct unknown_descriptor);
+}
+
+/**
+ * Retrieve size of unknown descriptor's data field.
+ *
+ * @param d The descriptor.
+ * @return Size of data field in bytes.
+ */
+static inline int
+ unknown_descriptor_data_size(struct unknown_descriptor *d)
+{
+ return d->d.len;
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline int verify_descriptors(uint8_t * buf, int len)
+{
+ int pos = 0;
+
+ while (pos < len) {
+ if ((pos + 2) > len)
+ return -1;
+
+ pos += 2 + buf[pos+1];
+ }
+
+ if (pos != len)
+ return -1;
+
+ return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile.am
new file mode 100644
index 0000000..b358273
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile.am
@@ -0,0 +1,19 @@
+noinst_LTLIBRARIES = libdvbdvb.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib
+
+libdvbdvb_la_SOURCES = bat_section.c \
+ dit_section.c \
+ eit_section.c \
+ int_section.c \
+ nit_section.c \
+ rst_section.c \
+ sdt_section.c \
+ sit_section.c \
+ st_section.c \
+ tdt_section.c \
+ tot_section.c \
+ tva_container_section.c \
+ types.c
+
+CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h
new file mode 100644
index 0000000..d60e37b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ac3_descriptor.h
@@ -0,0 +1,88 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_AC3_DESCRIPTOR
+#define _UCSI_DVB_AC3_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_ac3_descriptor structure.
+ */
+struct dvb_ac3_descriptor {
+ struct descriptor d;
+
+ EBIT5(uint8_t ac3_type_flag : 1; ,
+ uint8_t bsid_flag : 1; ,
+ uint8_t mainid_flag : 1; ,
+ uint8_t asvc_flag : 1; ,
+ uint8_t reserved : 4; )
+ /* uint8_t additional_info[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_ac3_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_ac3_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_ac3_descriptor*
+ dvb_ac3_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct dvb_ac3_descriptor) - 2))
+ return NULL;
+
+ return (struct dvb_ac3_descriptor*) d;
+}
+
+/**
+ * Retrieve pointer to additional_info field of a dvb_ac3_descriptor.
+ *
+ * @param d dvb_ac3_descriptor pointer.
+ * @return Pointer to additional_info field.
+ */
+static inline uint8_t *dvb_ac3_descriptor_additional_info(struct dvb_ac3_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_ac3_descriptor);
+}
+
+/**
+ * Determine length of additional_info field of a dvb_ac3_descriptor.
+ *
+ * @param d dvb_ac3_descriptor pointer.
+ * @return Length of field in bytes.
+ */
+static inline int dvb_ac3_descriptor_additional_info_length(struct dvb_ac3_descriptor *d)
+{
+ return d->d.len - 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h
new file mode 100644
index 0000000..69a21b8
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/adaptation_field_data_descriptor.h
@@ -0,0 +1,62 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_ADAPTATION_FIELD_DATA_DESCRIPTOR
+#define _UCSI_DVB_ADAPTATION_FIELD_DATA_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_adaptation_field_data_descriptor structure.
+ */
+struct dvb_adaptation_field_data_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t reserved : 7; ,
+ uint8_t announcement_switching_data : 1; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_adaptation_field_data_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to dvb_adaptation_field_data_descriptor, or NULL on error.
+ */
+static inline struct dvb_adaptation_field_data_descriptor*
+ dvb_adaptation_field_data_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_adaptation_field_data_descriptor) - 2))
+ return NULL;
+
+ return (struct dvb_adaptation_field_data_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h
new file mode 100644
index 0000000..877d9c0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_descriptor.h
@@ -0,0 +1,204 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_AIT_APPLICATION_DESCRIPTOR
+#define _UCSI_DVB_AIT_APPLICATION_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for the visibility field.
+ */
+enum {
+ AVB_AIT_APPLICATION_VISIBILITY_HIDDEN = 0x00,
+ AVB_AIT_APPLICATION_VISIBILITY_APPSONLY = 0x01,
+ AVB_AIT_APPLICATION_VISIBILITY_VISIBLE = 0x03
+};
+
+/**
+ * dvb_ait_application_descriptor structure.
+ */
+struct dvb_ait_application_descriptor {
+ struct descriptor d;
+
+ uint8_t application_profiles_length;
+ /* struct dvb_ait_application_profile profiles [] */
+ /* struct dvb_ait_application_descriptor_part2 part2 */
+} __ucsi_packed;
+
+/**
+ * An entry in the profiles field of a dvb_ait_application_descriptor.
+ */
+struct dvb_ait_application_profile {
+ uint16_t application_profile;
+ uint8_t version_major;
+ uint8_t version_minor;
+ uint8_t version_micro;
+} __ucsi_packed;
+
+/**
+ * Second part of a dvb_ait_application_descriptor structure.
+ */
+struct dvb_ait_application_descriptor_part2 {
+ EBIT3(uint8_t service_bound_flag : 1; ,
+ uint8_t visibility : 2; ,
+ uint8_t reserved : 5; )
+ uint8_t application_priority;
+ /* uint8_t transport_protocol_label[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_ait_application_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_ait_application_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_ait_application_descriptor*
+ dvb_ait_application_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint32_t pos2 = 0;
+ uint32_t len = d->len + 2;
+ uint8_t* buf = (uint8_t*) d;
+ struct dvb_ait_application_descriptor *ret =
+ (struct dvb_ait_application_descriptor*) d;
+
+ if (len < sizeof(struct dvb_ait_application_descriptor))
+ return NULL;
+
+ if (len < (sizeof(struct dvb_ait_application_descriptor) + ret->application_profiles_length))
+ return NULL;
+
+ if (ret->application_profiles_length % sizeof(struct dvb_ait_application_profile))
+ return NULL;
+
+ pos += sizeof(struct dvb_ait_application_descriptor);
+ pos2 = 0;
+ while(pos2 < ret->application_profiles_length) {
+ bswap16(buf + pos + pos2);
+ pos2 += sizeof(struct dvb_ait_application_descriptor);
+ }
+ pos += pos2;
+
+ if (len < (pos + sizeof(struct dvb_ait_application_descriptor_part2)))
+ return NULL;
+
+ return ret;
+}
+
+/**
+ * Iterator for the profiles field of a dvb_ait_application_descriptor.
+ *
+ * @param d dvb_ait_application_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_ait_application_profile.
+ */
+#define dvb_ait_application_descriptor_profiles_for_each(d, pos) \
+ for ((pos) = dvb_ait_application_descriptor_profiles_first(d); \
+ (pos); \
+ (pos) = dvb_ait_application_descriptor_profiles_next(d, pos))
+
+/**
+ * Accessor for the part2 field of a dvb_ait_application_descriptor.
+ *
+ * @param d dvb_ait_application_descriptor pointer.
+ * @return dvb_ait_application_descriptor_part2 pointer.
+ */
+static inline struct dvb_ait_application_descriptor_part2*
+ dvb_ait_application_descriptor_part2(struct dvb_ait_application_descriptor* d)
+{
+ return (struct dvb_ait_application_descriptor_part2*)
+ ((uint8_t*) d +
+ sizeof(struct dvb_ait_application_descriptor) +
+ d->application_profiles_length);
+}
+
+/**
+ * Accessor for the transport_protocol_label field of a dvb_ait_application_descriptor_part2.
+ *
+ * @param d dvb_ait_application_descriptor_part2 pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ dvb_ait_application_descriptor_part2_transport_protocol_label(struct dvb_ait_application_descriptor_part2* d)
+{
+ return (uint8_t*) d +
+ sizeof(struct dvb_ait_application_descriptor_part2);
+}
+
+/**
+ * Calculate the number of bytes in the transport_protocol_label field of a dvb_ait_application_descriptor_part2.
+ *
+ * @param d dvb_ait_application_descriptor pointer.
+ * @param part2 dvb_ait_application_descriptor_part2 pointer.
+ * @return Number of bytes.
+ */
+static inline int
+ dvb_ait_application_descriptor_part2_transport_protocol_label_length(struct dvb_ait_application_descriptor *d,
+ struct dvb_ait_application_descriptor_part2* part2)
+{
+ uint8_t *ptr = (uint8_t*) part2 + sizeof(struct dvb_ait_application_descriptor_part2);
+ uint8_t *end = (uint8_t*) d + d->d.len + 2;
+
+ return (int) (end - ptr);
+}
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_ait_application_profile*
+ dvb_ait_application_descriptor_profiles_first(struct dvb_ait_application_descriptor *d)
+{
+ if (d->application_profiles_length == 0)
+ return NULL;
+
+ return (struct dvb_ait_application_profile *)
+ ((uint8_t*) d + sizeof(struct dvb_ait_application_descriptor));
+}
+
+static inline struct dvb_ait_application_profile*
+ dvb_ait_application_descriptor_profiles_next(struct dvb_ait_application_descriptor *d,
+ struct dvb_ait_application_profile *pos)
+{
+ uint8_t *end = (uint8_t*) d +
+ sizeof(struct dvb_ait_application_descriptor) +
+ d->application_profiles_length;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_ait_application_profile);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_ait_application_profile *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h
new file mode 100644
index 0000000..5ea5932
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_icons_descriptor.h
@@ -0,0 +1,157 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_AIT_APPLICATION_ICONS_DESCRIPTOR
+#define _UCSI_DVB_AIT_APPLICATION_ICONS_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * Possible values for the icon_flags field.
+ */
+enum {
+ AIT_APPLICATION_ICON_FLAG_32_32 = 0x001,
+ AIT_APPLICATION_ICON_FLAG_32_32_43 = 0x002,
+ AIT_APPLICATION_ICON_FLAG_24_32_169 = 0x004,
+
+ AIT_APPLICATION_ICON_FLAG_64_64 = 0x008,
+ AIT_APPLICATION_ICON_FLAG_64_64_43 = 0x010,
+ AIT_APPLICATION_ICON_FLAG_48_64_169 = 0x020,
+
+ AIT_APPLICATION_ICON_FLAG_128_128 = 0x040,
+ AIT_APPLICATION_ICON_FLAG_128_128_43 = 0x080,
+ AIT_APPLICATION_ICON_FLAG_96_128_169 = 0x100
+};
+
+/**
+ * dvb_ait_application_icons_descriptor structure.
+ */
+struct dvb_ait_application_icons_descriptor {
+ struct descriptor d;
+
+ uint8_t icon_locator_length;
+ /* uint8_t icon_locator[] */
+ /* struct dvb_ait_application_icons_descriptor_part2 */
+} __ucsi_packed;
+
+/**
+ * Second part of a dvb_ait_application_icons_descriptor.
+ */
+struct dvb_ait_application_icons_descriptor_part2 {
+ uint16_t icon_flags;
+ /* uint8_t reserved[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_ait_application_icons_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_ait_application_icons_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_ait_application_icons_descriptor*
+ dvb_ait_application_icons_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d;
+ uint32_t pos = 0;
+ uint32_t len = d->len + 2;
+ struct dvb_ait_application_icons_descriptor *ret =
+ (struct dvb_ait_application_icons_descriptor *) d;
+
+ if (len < sizeof(struct dvb_ait_application_icons_descriptor))
+ return NULL;
+ if (len < (sizeof(struct dvb_ait_application_icons_descriptor) + ret->icon_locator_length))
+ return NULL;
+
+ pos += sizeof(struct dvb_ait_application_icons_descriptor) + ret->icon_locator_length;
+
+ if ((len - pos) < sizeof(struct dvb_ait_application_icons_descriptor_part2))
+ return NULL;
+ bswap16(buf + pos);
+
+ return ret;
+}
+/**
+ * Accessor for the icon_locator field of a dvb_ait_application_icons_descriptor.
+ *
+ * @param e dvb_ait_application_icons_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_ait_application_icons_descriptor_icon_locator(struct dvb_ait_application_icons_descriptor *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_ait_application_icons_descriptor);
+}
+
+/**
+ * Accessor for the part2 field of a dvb_ait_application_icons_descriptor.
+ *
+ * @param e dvb_ait_application_icons_descriptor Pointer.
+ * @return dvb_ait_application_icons_descriptor_part2 pointer.
+ */
+static inline struct dvb_ait_application_icons_descriptor_part2 *
+ dvb_ait_application_icons_descriptor_part2(struct dvb_ait_application_icons_descriptor *e)
+{
+ return (struct dvb_ait_application_icons_descriptor_part2 *)
+ ((uint8_t *) e + sizeof(struct dvb_ait_application_icons_descriptor) +
+ e->icon_locator_length);
+}
+
+/**
+ * Accessor for the reserved field of a dvb_ait_application_icons_descriptor_part2.
+ *
+ * @param e dvb_ait_application_icons_part2 pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_ait_application_icons_descriptor_part2_reserved(struct dvb_ait_application_icons_descriptor_part2 *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_ait_application_icons_descriptor_part2);
+}
+
+/**
+ * Calculate the number of bytes in the reserved field of a dvb_ait_application_icons_descriptor_part2.
+ *
+ * @param d dvb_ait_application_icons_descriptorpointer.
+ * @param part2 dvb_ait_application_icons_descriptor_part2 pointer.
+ * @return Number of bytes.
+ */
+static inline int
+ dvb_ait_application_icons_descriptor_part2_reserved_length(struct dvb_ait_application_icons_descriptor *d,
+ struct dvb_ait_application_icons_descriptor_part2* part2)
+{
+ uint8_t *ptr = (uint8_t*) part2 + sizeof(struct dvb_ait_application_icons_descriptor_part2);
+ uint8_t *end = (uint8_t*) d + d->d.len + 2;
+
+ return (int) (end - ptr);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_name_descriptor.h
new file mode 100644
index 0000000..a4b719e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_application_name_descriptor.h
@@ -0,0 +1,145 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_AIT_APPLICATION_NAME_DESCRIPTOR
+#define _UCSI_DVB_AIT_APPLICATION_NAME_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_ait_application_name_descriptor structure.
+ */
+struct dvb_ait_application_name_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_ait_application_name names[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the names field of a dvb_ait_application_name_descriptor.
+ */
+struct dvb_ait_application_name {
+ iso639lang_t language_code;
+ uint8_t application_name_length;
+ /* uint8_t name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_ait_application_name_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_ait_application_name_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_ait_application_name_descriptor*
+ dvb_ait_application_name_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+
+ while(pos < len) {
+ struct dvb_ait_application_name *e =
+ (struct dvb_ait_application_name*) (buf + pos);
+
+ pos += sizeof(struct dvb_ait_application_name);
+
+ if (pos > len)
+ return NULL;
+
+ pos += e->application_name_length;
+
+ if (pos > len)
+ return NULL;
+ }
+
+ return (struct dvb_ait_application_name_descriptor*) d;
+}
+
+/**
+ * Iterator for entries in the names field of a dvb_ait_application_name_descriptor.
+ *
+ * @param d dvb_ait_application_name_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_ait_application_name.
+ */
+#define dvb_ait_application_name_descriptor_names_for_each(d, pos) \
+ for ((pos) = dvb_ait_application_name_descriptor_names_first(d); \
+ (pos); \
+ (pos) = dvb_ait_application_name_descriptor_names_next(d, pos))
+
+/**
+ * Accessor for the name field of a dvb_ait_application_name.
+ *
+ * @param e dvb_ait_application_name pointer.
+ * @return Pointer to the name field.
+ */
+static inline uint8_t *
+ dvb_ait_application_name_name(struct dvb_ait_application_name *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_ait_application_name);
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_ait_application_name*
+ dvb_ait_application_name_descriptor_names_first(struct dvb_ait_application_name_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_ait_application_name *)
+ ((uint8_t*) d + sizeof(struct dvb_ait_application_name_descriptor));
+}
+
+static inline struct dvb_ait_application_name*
+ dvb_ait_application_name_descriptor_names_next(struct dvb_ait_application_name_descriptor *d,
+ struct dvb_ait_application_name *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_ait_application_name) +
+ pos->application_name_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_ait_application_name *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_external_application_authorisation_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_external_application_authorisation_descriptor.h
new file mode 100644
index 0000000..34f584a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ait_external_application_authorisation_descriptor.h
@@ -0,0 +1,125 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_AIT_EXTERNAL_APPLICATION_AUTHORISATION_DESCRIPTOR
+#define _UCSI_DVB_AIT_EXTERNAL_APPLICATION_AUTHORISATION_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_ait_external_application_authorisation_descriptor structure.
+ */
+struct dvb_ait_external_application_authorisation_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_ait_external_application_authorisation auths[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the auths field of a dvb_ait_external_application_authorisation_descriptor.
+ */
+struct dvb_ait_external_application_authorisation {
+ uint32_t organization_id;
+ uint16_t application_id;
+ uint8_t application_priority;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_ait_external_application_authorisation_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_ait_external_application_authorisation_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_ait_external_application_authorisation_descriptor*
+ dvb_ait_external_application_authorisation_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+
+ if (len % sizeof(struct dvb_ait_external_application_authorisation))
+ return NULL;
+
+ while(pos < len) {
+ bswap32(buf + pos);
+ bswap32(buf + pos + 4);
+ pos += sizeof(struct dvb_ait_external_application_authorisation);
+ }
+
+ return (struct dvb_ait_external_application_authorisation_descriptor*) d;
+}
+
+/**
+ * Iterator for entries in the auths field of a dvb_ait_external_application_authorisation_descriptor.
+ *
+ * @param d dvb_ait_external_application_authorisation_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_ait_external_application_authorisation.
+ */
+#define dvb_ait_external_application_authorisation_descriptor_auths_for_each(d, pos) \
+ for ((pos) = dvb_ait_external_application_authorisation_descriptor_auths_first(d); \
+ (pos); \
+ (pos) = dvb_ait_external_application_authorisation_descriptor_auths_next(d, pos))
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_ait_external_application_authorisation*
+ dvb_ait_external_application_authorisation_descriptor_auths_first(struct dvb_ait_external_application_authorisation_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_ait_external_application_authorisation *)
+ ((uint8_t*) d + sizeof(struct dvb_ait_external_application_authorisation_descriptor));
+}
+
+static inline struct dvb_ait_external_application_authorisation*
+ dvb_ait_external_application_authorisation_descriptor_auths_next(struct dvb_ait_external_application_authorisation_descriptor *d,
+ struct dvb_ait_external_application_authorisation *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_ait_external_application_authorisation);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_ait_external_application_authorisation *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h
new file mode 100644
index 0000000..7a0280d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ancillary_data_descriptor.h
@@ -0,0 +1,67 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_ANCILLARY_DATA_DESCRIPTOR
+#define _UCSI_DVB_ANCILLARY_DATA_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_ancillary_data_descriptor structure.
+ */
+struct dvb_ancillary_data_descriptor {
+ struct descriptor d;
+ EBIT8(uint8_t reserved : 1; ,
+ uint8_t rds_via_udcp : 1; ,
+ uint8_t mpeg4_ancillary_data : 1; ,
+ uint8_t scale_factor_error_check : 1; ,
+ uint8_t dab_ancillary_data : 1; ,
+ uint8_t announcement_switching_data : 1; ,
+ uint8_t extended_ancillary_data : 1; ,
+ uint8_t dvd_video_ancillary_data : 1; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_ancillary_data_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_ancillary_data_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_ancillary_data_descriptor*
+ dvb_ancillary_data_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_ancillary_data_descriptor) - 2))
+ return NULL;
+
+ return (struct dvb_ancillary_data_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h
new file mode 100644
index 0000000..55a570b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/announcement_support_descriptor.h
@@ -0,0 +1,219 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_ANNOUNCEMENT_SUPPORT_DESCRIPTOR
+#define _UCSI_DVB_ANNOUNCEMENT_SUPPORT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for announcement_support_indicator.
+ */
+enum {
+ DVB_ANNOUNCEMENT_SUPPORT_EMERGENCY = 0x01,
+ DVB_ANNOUNCEMENT_SUPPORT_ROAD_TRAFFIC_FLASH = 0x02,
+ DVB_ANNOUNCEMENT_SUPPORT_PUBLIC_TRANSPORT_FLASH = 0x04,
+ DVB_ANNOUNCEMENT_SUPPORT_WARNING_MESSAGE = 0x08,
+ DVB_ANNOUNCEMENT_SUPPORT_NEWS_FLASH = 0x10,
+ DVB_ANNOUNCEMENT_SUPPORT_WEATHER_FLASH = 0x20,
+ DVB_ANNOUNCEMENT_SUPPORT_EVENT_ANNOUNCEMENT = 0x40,
+ DVB_ANNOUNCEMENT_SUPPORT_PERSONAL_CALL = 0x80
+};
+
+/**
+ * Possible values for announcement_type.
+ */
+enum {
+ DVB_ANNOUNCEMENT_TYPE_EMERGENCY = 0x00,
+ DVB_ANNOUNCEMENT_TYPE_ROAD_TRAFFIC_FLASH = 0x01,
+ DVB_ANNOUNCEMENT_TYPE_PUBLIC_TRANSPORT_FLASH = 0x02,
+ DVB_ANNOUNCEMENT_TYPE_WARNING_MESSAGE = 0x03,
+ DVB_ANNOUNCEMENT_TYPE_NEWS_FLASH = 0x04,
+ DVB_ANNOUNCEMENT_TYPE_WEATHER_FLASH = 0x05,
+ DVB_ANNOUNCEMENT_TYPE_EVENT_ANNOUNCEMENT = 0x06,
+ DVB_ANNOUNCEMENT_TYPE_PERSONAL_CALL = 0x07
+};
+
+/**
+ * Possible values for reference_type.
+ */
+enum {
+ DVB_REFERENCE_TYPE_AUDIO = 0x00,
+ DVB_REFERENCE_TYPE_OTHER_AUDIO = 0x01,
+ DVB_REFERENCE_TYPE_OTHER_SERVICE = 0x02,
+ DVB_REFERENCE_TYPE_OTHER_TS = 0x03
+};
+
+/**
+ * dvb_announcement_support_descriptor structure.
+ */
+struct dvb_announcement_support_descriptor {
+ struct descriptor d;
+ uint16_t announcement_support_indicator;
+ /* struct dvb_announcement_support_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the entries field of a dvb_announcement_support_descriptor.
+ */
+struct dvb_announcement_support_entry {
+ EBIT3(uint8_t announcement_type : 4; ,
+ uint8_t reserved : 1; ,
+ uint8_t reference_type : 3; )
+ /* Only if reference_type == 1, 2 or 3:
+ * struct dvb_announcement_support_reference reference */
+} __ucsi_packed;
+
+/**
+ * The optional reference field only present in a dvb_announcement_support_descriptor if
+ * its reference_type field is 1,2 or 3.
+ */
+struct dvb_announcement_support_reference {
+ uint16_t original_network_id;
+ uint16_t transport_stream_id;
+ uint16_t service_id;
+ uint8_t component_tag;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_announcement_support_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_announcement_support_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_announcement_support_descriptor*
+ dvb_announcement_support_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+
+ if (len < (sizeof(struct dvb_announcement_support_descriptor) - 2))
+ return NULL;
+
+ bswap16(buf+pos);
+
+ pos += 2;
+
+ while(pos < len) {
+ struct dvb_announcement_support_entry *e =
+ (struct dvb_announcement_support_entry*) (buf+pos);
+
+ pos += sizeof(struct dvb_announcement_support_entry);
+
+ if (pos > len)
+ return NULL;
+
+ if ((e->reference_type == 1) ||
+ (e->reference_type == 2) ||
+ (e->reference_type == 3)) {
+ if ((pos + sizeof(struct dvb_announcement_support_reference)) > len)
+ return NULL;
+
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ bswap16(buf+pos+4);
+
+ pos += sizeof(struct dvb_announcement_support_reference);
+ }
+ }
+
+ return (struct dvb_announcement_support_descriptor*) d;
+}
+
+/**
+ * Iterator for the entries field of a dvb_announcement_support_descriptor.
+ *
+ * @param d dvb_announcement_support_descriptor pointer.
+ * @param pod Variable holding a pointer to the current dvb_announcement_support_entry.
+ */
+#define dvb_announcement_support_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_announcement_support_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_announcement_support_descriptor_entries_next(d, pos))
+
+/**
+ * Accessor for the reference field of a dvb_announcement_support_entry if present.
+ *
+ * @param entry dvb_announcement_support_entry pointer.
+ * @return dvb_announcement_support_reference pointer, or NULL on error.
+ */
+static inline struct dvb_announcement_support_reference*
+ dvb_announcement_support_entry_reference(struct dvb_announcement_support_entry* entry)
+{
+ if ((entry->reference_type != 0x01) &&
+ (entry->reference_type != 0x02) &&
+ (entry->reference_type != 0x03))
+ return NULL;
+
+ return (struct dvb_announcement_support_reference*)
+ ((uint8_t*) entry + sizeof(struct dvb_announcement_support_entry));
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_announcement_support_entry*
+ dvb_announcement_support_descriptor_entries_first(struct dvb_announcement_support_descriptor *d)
+{
+ if (d->d.len == 2)
+ return NULL;
+
+ return (struct dvb_announcement_support_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_announcement_support_descriptor));
+}
+
+static inline struct dvb_announcement_support_entry*
+ dvb_announcement_support_descriptor_entries_next(struct dvb_announcement_support_descriptor *d,
+ struct dvb_announcement_support_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t* next = (uint8_t*) pos + sizeof(struct dvb_announcement_support_entry);
+ struct dvb_announcement_support_reference* reference =
+ dvb_announcement_support_entry_reference(pos);
+
+ if (reference)
+ next += sizeof(struct dvb_announcement_support_reference);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_announcement_support_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h
new file mode 100644
index 0000000..c1d50ff
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/application_signalling_descriptor.h
@@ -0,0 +1,124 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_APPLICATION_SIGNALLING_DESCRIPTOR
+#define _UCSI_DVB_APPLICATION_SIGNALLING_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_application_signalling_descriptor structure.
+ */
+struct dvb_application_signalling_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_application_signalling_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the entries field of a dvb_application_signalling_descriptor.
+ */
+struct dvb_application_signalling_entry {
+ uint16_t application_type;
+ EBIT2(uint8_t reserved : 3; ,
+ uint8_t AIT_version_number : 5; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_application_signalling_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_application_signalling_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_application_signalling_descriptor*
+ dvb_application_signalling_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+ uint8_t* buf = (uint8_t*) d + 2;
+
+ pos += sizeof(struct dvb_application_signalling_descriptor) - 2;
+ if (len % sizeof(struct dvb_application_signalling_entry))
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ pos+=3;
+ }
+
+ return (struct dvb_application_signalling_descriptor*) d;
+}
+
+/**
+ * Iterator for the entries field of a dvb_application_signalling_descriptor.
+ *
+ * @param d dvb_application_signalling_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_application_signalling_entry.
+ */
+#define dvb_application_signalling_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_application_signalling_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_application_signalling_descriptor_entries_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_application_signalling_entry*
+ dvb_application_signalling_descriptor_entries_first(struct dvb_application_signalling_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_application_signalling_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_application_signalling_descriptor));
+}
+
+static inline struct dvb_application_signalling_entry*
+ dvb_application_signalling_descriptor_countries_next(struct dvb_application_signalling_descriptor *d,
+ struct dvb_application_signalling_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_application_signalling_entry);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_application_signalling_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c
new file mode 100644
index 0000000..afbeb0f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.c
@@ -0,0 +1,77 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/bat_section.h>
+
+struct dvb_bat_section * dvb_bat_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *) ext;
+ unsigned int pos = sizeof(struct section_ext);
+ unsigned int len = section_ext_length(ext);
+ struct dvb_bat_section * ret = (struct dvb_bat_section *) ext;
+
+ if (len < sizeof(struct dvb_bat_section))
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += 2;
+
+ if ((pos + ret->bouquet_descriptors_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, ret->bouquet_descriptors_length))
+ return NULL;
+ pos += ret->bouquet_descriptors_length;
+
+ if ((pos + sizeof(struct dvb_bat_section_part2)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += sizeof(struct dvb_bat_section_part2);
+
+ while (pos < len) {
+ struct dvb_bat_transport * transport =
+ (struct dvb_bat_transport *) (buf + pos);
+
+ if ((pos + sizeof(struct dvb_bat_transport)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ bswap16(buf + pos + 2);
+ bswap16(buf + pos + 4);
+
+ pos += sizeof(struct dvb_bat_transport);
+
+ if ((pos + transport->transport_descriptors_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos,
+ transport->transport_descriptors_length))
+ return NULL;
+
+ pos += transport->transport_descriptors_length;
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h
new file mode 100644
index 0000000..277d5ab
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bat_section.h
@@ -0,0 +1,211 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_BAT_SECTION_H
+#define _UCSI_DVB_BAT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_bat_section structure.
+ */
+struct dvb_bat_section {
+ struct section_ext head;
+
+ EBIT2(uint16_t reserved_1 : 4; ,
+ uint16_t bouquet_descriptors_length :12; );
+ /* struct descriptor descriptors[] */
+ /* struct dvb_bat_section_part2 part2 */
+};
+
+/**
+ * Second part of a dvb_bat_section, following the variable length descriptors field.
+ */
+struct dvb_bat_section_part2 {
+ EBIT2(uint16_t reserved_2 : 4; ,
+ uint16_t transport_stream_loop_length :12; );
+ /* struct dvb_bat_transport transports[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the transports field of a dvb_bat_section_part2.
+ */
+struct dvb_bat_transport {
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ EBIT2(uint16_t reserved : 4; ,
+ uint16_t transport_descriptors_length :12; );
+ /* struct descriptor descriptors[] */
+};
+
+/**
+ * Process a dvb_bat_section.
+ *
+ * @param section Generic section pointer.
+ * @return dvb_bat_section pointer, or NULL on error.
+ */
+struct dvb_bat_section *dvb_bat_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the bouquet_id field of a BAT.
+ *
+ * @param bat BAT pointer.
+ * @return The bouquet_id.
+ */
+static inline uint16_t dvb_bat_section_bouquet_id(struct dvb_bat_section *bat)
+{
+ return bat->head.table_id_ext;
+}
+
+/**
+ * Iterator for the descriptors field in a dvb_bat_section.
+ *
+ * @param bat dvb_bat_section pointer.
+ * @param pos Variable containing a pointer to the current descriptor.
+ */
+#define dvb_bat_section_descriptors_for_each(bat, pos) \
+ for ((pos) = dvb_bat_section_descriptors_first(bat); \
+ (pos); \
+ (pos) = dvb_bat_section_descriptors_next(bat, pos))
+
+/**
+ * Accessor for the second part of a dvb_bat_section.
+ *
+ * @param bat dvb_bat_section pointer.
+ * @return dvb_bat_section_part2 pointer.
+ */
+static inline struct dvb_bat_section_part2 *
+ dvb_bat_section_part2(struct dvb_bat_section *bat)
+{
+ return (struct dvb_bat_section_part2 *)
+ ((uint8_t*) bat +
+ sizeof(struct dvb_bat_section) +
+ bat->bouquet_descriptors_length);
+
+}
+
+/**
+ * Iterator for the transports field of a dvb_bat_section_part2.
+ *
+ * @param part2 dvb_bat_section_part2 pointer.
+ * @param pos Variable containing a pointer to the current dvb_bat_transport.
+ */
+#define dvb_bat_section_transports_for_each(part2, pos) \
+ for ((pos) = dvb_bat_section_transports_first(part2); \
+ (pos); \
+ (pos) = dvb_bat_section_transports_next(part2, pos))
+
+/**
+ * Iterator for the descriptors field of a dvb_bat_transport.
+ *
+ * @param transport dvb_bat_transport pointer.
+ * @param pos Variable containing a pointer to the current descriptor.
+ */
+#define dvb_bat_transport_descriptors_for_each(transport, pos) \
+ for ((pos) = dvb_bat_transport_descriptors_first(transport); \
+ (pos); \
+ (pos) = dvb_bat_transport_descriptors_next(transport, pos))
+
+
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ dvb_bat_section_descriptors_first(struct dvb_bat_section *bat)
+{
+ if (bat->bouquet_descriptors_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) bat + sizeof(struct dvb_bat_section));
+}
+
+static inline struct descriptor *
+ dvb_bat_section_descriptors_next(struct dvb_bat_section *bat,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) bat + sizeof(struct dvb_bat_section),
+ bat->bouquet_descriptors_length,
+ pos);
+}
+
+static inline struct dvb_bat_transport *
+ dvb_bat_section_transports_first(struct dvb_bat_section_part2 *part2)
+{
+ if (part2->transport_stream_loop_length == 0)
+ return NULL;
+
+ return (struct dvb_bat_transport *)
+ ((uint8_t *) part2 + sizeof(struct dvb_bat_section_part2));
+}
+
+static inline struct dvb_bat_transport *
+ dvb_bat_section_transports_next(struct dvb_bat_section_part2 *part2,
+ struct dvb_bat_transport *pos)
+{
+ uint8_t *end = (uint8_t*) part2 + sizeof(struct dvb_bat_section_part2) +
+ part2->transport_stream_loop_length;
+ uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_bat_transport) +
+ pos->transport_descriptors_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_bat_transport *) next;
+}
+
+static inline struct descriptor *
+ dvb_bat_transport_descriptors_first(struct dvb_bat_transport *t)
+{
+ if (t->transport_descriptors_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t*)t + sizeof(struct dvb_bat_transport));
+}
+
+static inline struct descriptor *
+ dvb_bat_transport_descriptors_next(struct dvb_bat_transport *t,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) t + sizeof(struct dvb_bat_transport),
+ t->transport_descriptors_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/bouquet_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/bouquet_name_descriptor.h
new file mode 100644
index 0000000..a298849
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/bouquet_name_descriptor.h
@@ -0,0 +1,82 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_BOUQUET_NAME_DESCRIPTOR
+#define _UCSI_DVB_BOUQUET_NAME_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_bouquet_name_descriptor structure.
+ */
+struct dvb_bouquet_name_descriptor {
+ struct descriptor d;
+
+ /* uint8_t name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_bouquet_name_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_bouquet_name_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_bouquet_name_descriptor*
+ dvb_bouquet_name_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_bouquet_name_descriptor*) d;
+}
+
+/**
+ * Accessor for the name field of a dvb_bouquet_name_descriptor.
+ *
+ * @param d dvb_bouquet_name_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_bouquet_name_descriptor_name(struct dvb_bouquet_name_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_bouquet_name_descriptor);
+}
+
+/**
+ * Determine the length of the name field of a dvb_bouquet_name_descriptor in bytes.
+ *
+ * @param d dvb_bouquet_name_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_bouquet_name_descriptor_name_length(struct dvb_bouquet_name_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/ca_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/ca_identifier_descriptor.h
new file mode 100644
index 0000000..ac670a9
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/ca_identifier_descriptor.h
@@ -0,0 +1,94 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_CA_IDENTIFIER_DESCRIPTOR
+#define _UCSI_DVB_CA_IDENTIFIER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_ca_identifier_descriptor structure.
+ */
+struct dvb_ca_identifier_descriptor {
+ struct descriptor d;
+
+ /* uint16_t ca_system_ids[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_ca_identifier_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_ca_identifier_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_ca_identifier_descriptor*
+ dvb_ca_identifier_descriptor_codec(struct descriptor* d)
+{
+ uint32_t len = d->len;
+ uint8_t *buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+
+ if (len % 2)
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ pos+=2;
+ }
+
+ return (struct dvb_ca_identifier_descriptor*) d;
+}
+
+/**
+ * Accessor for the ca_system_ids field of a dvb_ca_identifier_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint16_t *
+ dvb_ca_identifier_descriptor_ca_system_ids(struct dvb_ca_identifier_descriptor *d)
+{
+ return (uint16_t *) ((uint8_t *) d + sizeof(struct dvb_ca_identifier_descriptor));
+}
+
+/**
+ * Calculate the number of entries in the ca_system_ids field of a dvb_ca_identifier_descriptor.
+ *
+ * @param d dvb_ca_identifier_descriptor pointer.
+ * @return Number of entries.
+ */
+static inline int
+ dvb_ca_identifier_descriptor_ca_system_ids_count(struct dvb_ca_identifier_descriptor *d)
+{
+ return d->d.len >> 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h
new file mode 100644
index 0000000..70b0c98
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cable_delivery_descriptor.h
@@ -0,0 +1,70 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_CABLE_DELIVERY_DESCRIPTOR
+#define _UCSI_DVB_CABLE_DELIVERY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_cable_delivery_descriptor structure.
+ */
+struct dvb_cable_delivery_descriptor {
+ struct descriptor d;
+
+ uint32_t frequency; // BCD, units 100Hz
+ EBIT2(uint16_t reserved : 12; ,
+ uint16_t fec_outer : 4; )
+ uint8_t modulation;
+ EBIT2(uint32_t symbol_rate : 28; , // BCD, units 100Hz
+ uint32_t fec_inner : 4; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_cable_delivery_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_cable_delivery_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_cable_delivery_descriptor*
+ dvb_cable_delivery_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_cable_delivery_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+ bswap16((uint8_t*) d + 6);
+ bswap32((uint8_t*) d + 9);
+
+ return (struct dvb_cable_delivery_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h
new file mode 100644
index 0000000..b6285bd
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_frequency_link_descriptor.h
@@ -0,0 +1,190 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_CELL_FREQUENCY_LINK_DESCRIPTOR
+#define _UCSI_DVB_CELL_FREQUENCY_LINK_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_cell_frequency_link_descriptor structure.
+ */
+struct dvb_cell_frequency_link_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_cell_frequency_link_cell cells[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the cells field of a dvb_cell_frequency_link_descriptor.
+ */
+struct dvb_cell_frequency_link_cell {
+ uint16_t cell_id;
+ uint32_t frequency;
+ uint8_t subcell_loop_info_length;
+ /* struct dvb_cell_frequency_link_subcell subcells[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the subcells field of a dvb_cell_frequency_link_cell.
+ */
+struct dvb_cell_frequency_link_cell_subcell {
+ uint8_t cell_id_extension;
+ uint32_t transposer_frequency;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_cell_frequency_link_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_cell_frequency_link_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_cell_frequency_link_descriptor*
+ dvb_cell_frequency_link_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint32_t pos2 = 0;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+
+ while(pos < len) {
+ struct dvb_cell_frequency_link_cell *e =
+ (struct dvb_cell_frequency_link_cell*) (buf+pos);
+
+ if ((pos + sizeof(struct dvb_cell_frequency_link_cell)) > len)
+ return NULL;
+
+ bswap16(buf+pos);
+ bswap32(buf+pos+2);
+
+ pos += sizeof(struct dvb_cell_frequency_link_cell);
+
+ if ((pos + e->subcell_loop_info_length) > len)
+ return NULL;
+
+ if (e->subcell_loop_info_length % sizeof(struct dvb_cell_frequency_link_cell_subcell))
+ return NULL;
+
+ pos2 = 0;
+ while(pos2 < e->subcell_loop_info_length) {
+ bswap32(buf+pos+pos2+1);
+
+ pos2 += sizeof(struct dvb_cell_frequency_link_cell_subcell);
+ }
+
+ pos += e->subcell_loop_info_length;
+ }
+
+ return (struct dvb_cell_frequency_link_descriptor*) d;
+}
+
+/**
+ * Iterator for the cells field of a dvb_cell_frequency_link_descriptor.
+ *
+ * @param d dvb_cell_frequency_link_descriptor pointer.
+ * @param pos Variable holding a pointer to the current dvb_cell_frequency_link_cell.
+ */
+#define dvb_cell_frequency_link_descriptor_cells_for_each(d, pos) \
+ for ((pos) = dvb_cell_frequency_link_descriptor_cells_first(d); \
+ (pos); \
+ (pos) = dvb_cell_frequency_link_descriptor_cells_next(d, pos))
+
+/**
+ * Iterator for the subcells field of a dvb_cell_frequency_link_cell.
+ *
+ * @param cell dvb_cell_frequency_link_cell pointer.
+ * @param pos Variable holding a pointer to the current dvb_cell_frequency_link_cell_subcell.
+ */
+#define dvb_cell_frequency_link_cell_subcells_for_each(cell, pos) \
+ for ((pos) = dvb_cell_frequency_link_cell_subcells_first(cell); \
+ (pos); \
+ (pos) = dvb_cell_frequency_link_cell_subcells_next(cell, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_cell_frequency_link_cell*
+ dvb_cell_frequency_link_descriptor_cells_first(struct dvb_cell_frequency_link_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_cell_frequency_link_cell *)
+ ((uint8_t*) d + sizeof(struct dvb_cell_frequency_link_descriptor));
+}
+
+static inline struct dvb_cell_frequency_link_cell*
+ dvb_cell_frequency_link_descriptor_cells_next(struct dvb_cell_frequency_link_descriptor *d,
+ struct dvb_cell_frequency_link_cell *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_cell_frequency_link_cell) +
+ pos->subcell_loop_info_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_cell_frequency_link_cell *) next;
+}
+
+static inline struct dvb_cell_frequency_link_cell_subcell*
+ dvb_cell_frequency_cell_subcells_first(struct dvb_cell_frequency_link_cell *d)
+{
+ if (d->subcell_loop_info_length == 0)
+ return NULL;
+
+ return (struct dvb_cell_frequency_link_cell_subcell*)
+ ((uint8_t*) d + sizeof(struct dvb_cell_frequency_link_cell));
+}
+
+static inline struct dvb_cell_frequency_link_cell_subcell*
+ dvb_cell_frequency_cell_subcells_next(struct dvb_cell_frequency_link_cell *cell,
+ struct dvb_cell_frequency_link_cell_subcell *pos)
+{
+ uint8_t *end = (uint8_t*) cell + cell->subcell_loop_info_length;
+ uint8_t *next = (uint8_t*) pos +
+ sizeof(struct dvb_cell_frequency_link_cell_subcell);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_cell_frequency_link_cell_subcell *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h
new file mode 100644
index 0000000..6a42ce4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/cell_list_descriptor.h
@@ -0,0 +1,201 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_CELL_LIST_DESCRIPTOR
+#define _UCSI_DVB_CELL_LIST_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_cell_list_descriptor structure.
+ */
+struct dvb_cell_list_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_cell_list_entry cells[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the cells field of a dvb_cell_list_descriptor.
+ */
+struct dvb_cell_list_entry {
+ uint16_t cell_id;
+ uint16_t cell_latitude;
+ uint16_t cell_longitude;
+ EBIT3(uint32_t cell_extend_of_latitude :12; ,
+ uint32_t cell_extend_of_longitude :12; ,
+ uint32_t subcell_info_loop_length : 8; )
+ /* struct dvb_subcell_list_entry subcells[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the subcells field of a dvb_cell_list_entry.
+ */
+struct dvb_subcell_list_entry {
+ uint8_t cell_id_extension;
+ uint16_t subcell_latitude;
+ uint16_t subcell_longitude;
+ EBIT2(uint32_t subcell_extend_of_latitude :12; ,
+ uint32_t subcell_extend_of_longitude :12; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_cell_list_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_cell_list_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_cell_list_descriptor*
+ dvb_cell_list_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint32_t pos2 = 0;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+
+ while(pos < len) {
+ struct dvb_cell_list_entry *e =
+ (struct dvb_cell_list_entry*) (buf+pos);
+
+ if ((pos + sizeof(struct dvb_cell_list_entry)) > len)
+ return NULL;
+
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ bswap16(buf+pos+4);
+ bswap32(buf+pos+6);
+
+ pos += sizeof(struct dvb_cell_list_entry);
+
+ if ((pos + e->subcell_info_loop_length) > len)
+ return NULL;
+
+ if (e->subcell_info_loop_length % sizeof(struct dvb_subcell_list_entry))
+ return NULL;
+
+ pos2 = 0;
+ while(pos2 < e->subcell_info_loop_length) {
+ bswap16(buf+pos+pos2+1);
+ bswap16(buf+pos+pos2+3);
+ bswap24(buf+pos+pos2+5);
+
+ pos2 += sizeof(struct dvb_subcell_list_entry);
+ }
+
+ pos += e->subcell_info_loop_length;
+ }
+
+ return (struct dvb_cell_list_descriptor*) d;
+}
+
+/**
+ * Iterator for the cells field of a dvb_cell_list_descriptor.
+ *
+ * @param d dvb_cell_list_descriptor pointer.
+ * @param pos Variable holding a pointer to the current dvb_cell_list_entry.
+ */
+#define dvb_cell_list_descriptor_cells_for_each(d, pos) \
+ for ((pos) = dvb_cell_list_descriptor_cells_first(d); \
+ (pos); \
+ (pos) = dvb_cell_list_descriptor_cells_next(d, pos))
+
+/**
+ * Iterator for the subcells field of a dvb_cell_list_entry.
+ *
+ * @param cell dvb_cell_list_entry pointer.
+ * @param pos Variable holding a pointer to the current dvb_subcell_list_entry.
+ */
+#define dvb_cell_list_entry_subcells_for_each(cell, pos) \
+ for ((pos) = dvb_cell_list_entry_subcells_first(cell); \
+ (pos); \
+ (pos) = dvb_cell_list_entry_subcells_next(cell, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_cell_list_entry*
+ dvb_cell_list_descriptor_cells_first(struct dvb_cell_list_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_cell_list_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_cell_list_descriptor));
+}
+
+static inline struct dvb_cell_list_entry*
+ dvb_cell_list_descriptor_cells_next(struct dvb_cell_list_descriptor *d,
+ struct dvb_cell_list_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_cell_list_entry) +
+ pos->subcell_info_loop_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_cell_list_entry *) next;
+}
+
+static inline struct dvb_subcell_list_entry*
+ dvb_cell_list_entry_subcells_first(struct dvb_cell_list_entry *d)
+{
+ if (d->subcell_info_loop_length == 0)
+ return NULL;
+
+ return (struct dvb_subcell_list_entry*)
+ ((uint8_t*) d + sizeof(struct dvb_cell_list_entry));
+}
+
+static inline struct dvb_subcell_list_entry*
+ dvb_cell_list_entry_subcells_next(struct dvb_cell_list_entry *d,
+ struct dvb_subcell_list_entry *pos)
+{
+ uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_subcell_list_entry);
+ uint8_t *end = (uint8_t*) d +
+ sizeof(struct dvb_cell_list_entry) +
+ d->subcell_info_loop_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_subcell_list_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h
new file mode 100644
index 0000000..154e235
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/component_descriptor.h
@@ -0,0 +1,147 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_COMPONENT_DESCRIPTOR
+#define _UCSI_DVB_COMPONENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * Possible values for stream_content.
+ */
+enum {
+ DVB_STREAM_CONTENT_VIDEO = 0x01,
+ DVB_STREAM_CONTENT_AUDIO = 0x02,
+ DVB_STREAM_CONTENT_SUBTITLE = 0x03,
+ DVB_STREAM_CONTENT_AC3 = 0x04
+};
+
+/**
+ * Possible values for component_type.
+ */
+enum {
+ DVB_COMPONENT_TYPE_VIDEO_43_25Hz = 0x01,
+ DVB_COMPONENT_TYPE_VIDEO_169_PAN_25Hz = 0x02,
+ DVB_COMPONENT_TYPE_VIDEO_169_NOPAN_25Hz = 0x03,
+ DVB_COMPONENT_TYPE_VIDEO_GT169_25Hz = 0x04,
+
+ DVB_COMPONENT_TYPE_VIDEO_43_30Hz = 0x05,
+ DVB_COMPONENT_TYPE_VIDEO_169_PAN_30Hz = 0x06,
+ DVB_COMPONENT_TYPE_VIDEO_169_NOPAN_30Hz = 0x07,
+ DVB_COMPONENT_TYPE_VIDEO_GT169_30Hz = 0x08,
+
+ DVB_COMPONENT_TYPE_HDVIDEO_43_25Hz = 0x09,
+ DVB_COMPONENT_TYPE_HDVIDEO_169_PAN_25Hz = 0x0a,
+ DVB_COMPONENT_TYPE_HDVIDEO_169_NOPAN_25Hz = 0x0b,
+ DVB_COMPONENT_TYPE_HDVIDEO_GT169_25Hz = 0x0c,
+
+ DVB_COMPONENT_TYPE_HDVIDEO_43_30Hz = 0x0d,
+ DVB_COMPONENT_TYPE_HDVIDEO_169_PAN_30Hz = 0x0e,
+ DVB_COMPONENT_TYPE_HDVIDEO_169_NOPAN_30Hz = 0x0f,
+ DVB_COMPONENT_TYPE_HDVIDEO_GT169_30Hz = 0x10,
+
+ DVB_COMPONENT_TYPE_AUDIO_SINGLE_MONO = 0x01,
+ DVB_COMPONENT_TYPE_AUDIO_DUAL_MONO = 0x02,
+ DVB_COMPONENT_TYPE_AUDIO_STEREO = 0x03,
+ DVB_COMPONENT_TYPE_AUDIO_MULTI_LINGUAL_MULTI_CHAN= 0x04,
+ DVB_COMPONENT_TYPE_AUDIO_SURROUND = 0x05,
+ DVB_COMPONENT_TYPE_AUDIO_VISUAL_IMPAIRED = 0x40,
+ DVB_COMPONENT_TYPE_AUDIO_HARDHEAR = 0x41,
+ DVB_COMPONENT_TYPE_AUDIO_SUPPLEMENTARY = 0x42,
+
+ DVB_COMPONENT_TYPE_SUBTITLE_TELETEXT = 0x01,
+ DVB_COMPONENT_TYPE_SUBTITLE_ASSOC_TELETEXT = 0x02,
+ DVB_COMPONENT_TYPE_SUBTITLE_VBI = 0x03,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB = 0x10,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB_43 = 0x11,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB_169 = 0x12,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB_2211 = 0x13,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR = 0x20,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_43 = 0x21,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_169 = 0x22,
+ DVB_COMPONENT_TYPE_SUBTITLE_DVB_HARDHEAR_2211 = 0x23
+};
+
+/**
+ * dvb_component_descriptor structure.
+ */
+struct dvb_component_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t reserved : 4; ,
+ uint8_t stream_content : 4; )
+ uint8_t component_type;
+ uint8_t component_tag;
+ iso639lang_t language_code;
+ /* uint8_t text[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_component_descriptor.
+ *
+ * @param d Pointer to a generic descriptor.
+ * @return dvb_component_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_component_descriptor*
+ dvb_component_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct dvb_component_descriptor) - 2))
+ return NULL;
+
+ return (struct dvb_component_descriptor*) d;
+}
+
+/**
+ * Accessor for the text field of a dvb_component_descriptor.
+ *
+ * @param d dvb_component_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_component_descriptor_text(struct dvb_component_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_component_descriptor);
+}
+
+/**
+ * Determine the length of the text field of a dvb_component_descriptor.
+ *
+ * @param d dvb_component_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_component_descriptor_text_length(struct dvb_component_descriptor *d)
+{
+ return d->d.len - 6;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h
new file mode 100644
index 0000000..5cc16dc
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_descriptor.h
@@ -0,0 +1,116 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_CONTENT_DESCRIPTOR
+#define _UCSI_DVB_CONTENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+// FIXME: the nibbles
+
+/**
+ * dvb_content_descriptor structure.
+ */
+struct dvb_content_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_content_nibble nibbles[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the nibbles field of a dvb_content_descriptor.
+ */
+struct dvb_content_nibble {
+ EBIT2(uint8_t content_nibble_level_1 : 4; ,
+ uint8_t content_nibble_level_2 : 4; )
+ EBIT2(uint8_t user_nibble_1 : 4; ,
+ uint8_t user_nibble_2 : 4; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_content_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_content_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_content_descriptor*
+ dvb_content_descriptor_codec(struct descriptor* d)
+{
+ if (d->len % sizeof(struct dvb_content_nibble))
+ return NULL;
+
+ return (struct dvb_content_descriptor*) d;
+}
+
+/**
+ * Iterator for the nibbles field of a dvb_content_descriptor.
+ *
+ * @param d dvb_content_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_content_nibble.
+ */
+#define dvb_content_descriptor_nibbles_for_each(d, pos) \
+ for ((pos) = dvb_content_descriptor_nibbles_first(d); \
+ (pos); \
+ (pos) = dvb_content_descriptor_nibbles_next(d, pos))
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_content_nibble*
+ dvb_content_descriptor_nibbles_first(struct dvb_content_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_content_nibble *)
+ ((uint8_t*) d + sizeof(struct dvb_content_descriptor));
+}
+
+static inline struct dvb_content_nibble*
+ dvb_content_descriptor_nibbles_next(struct dvb_content_descriptor *d,
+ struct dvb_content_nibble *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_content_nibble);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_content_nibble *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h
new file mode 100644
index 0000000..63d24a1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/content_identifier_descriptor.h
@@ -0,0 +1,222 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_CONTENT_IDENTIFIER_DESCRIPTOR
+#define _UCSI_DVB_CONTENT_IDENTIFIER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+
+/**
+ * Possible values for the crid_type.
+ */
+enum {
+ DVB_CRID_TYPE_NONE = 0x00,
+ DVB_CRID_TYPE_ITEM = 0x01,
+ DVB_CRID_TYPE_SERIES = 0x02,
+ DVB_CRID_TYPE_RECOMMENDATION = 0x03
+};
+
+/**
+ * Possible values for the crid_location.
+ */
+enum {
+ DVB_CRID_LOCATION_THIS_DESCRIPTOR = 0x00,
+ DVB_CRID_LOCATION_CIT = 0x01
+};
+
+/**
+ * dvb_content_identifier_descriptor structure.
+ */
+struct dvb_content_identifier_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_content_identifier_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the entries field of a dvb_content_identifier_descriptor.
+ */
+struct dvb_content_identifier_entry {
+ EBIT2(uint8_t crid_type : 6; ,
+ uint8_t crid_location : 2; )
+ /* struct dvb_content_identifier_data_00 data0 */
+ /* struct dvb_content_identifier_data_01 data1 */
+} __ucsi_packed;
+
+/**
+ * The data if crid_location == 0
+ */
+struct dvb_content_identifier_entry_data_0 {
+ uint8_t crid_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * The data if crid_location == 1
+ */
+struct dvb_content_identifier_entry_data_1 {
+ uint16_t crid_ref;
+} __ucsi_packed;
+
+
+/**
+ * Process a dvb_content_identifier_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return dvb_content_identifier_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_content_identifier_descriptor*
+ dvb_content_identifier_descriptor_codec(struct descriptor* d)
+{
+ uint32_t len = d->len + 2;
+ uint32_t pos = 2;
+ uint8_t *buf = (uint8_t*) d;
+
+ while(pos < len) {
+ struct dvb_content_identifier_entry *e =
+ (struct dvb_content_identifier_entry*) (buf + pos);
+
+ if (len < (pos+1))
+ return NULL;
+ pos++;
+
+ switch(e->crid_location) {
+ case 0:
+ if (len < (pos + 1))
+ return NULL;
+ if (len < (pos + 1 + buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ break;
+
+ case 1:
+ if (len < (pos+2))
+ return NULL;
+ bswap16(buf+pos);
+ break;
+ }
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return (struct dvb_content_identifier_descriptor*) d;
+}
+
+/**
+ * Iterator for entries field of a dvb_content_identifier_descriptor.
+ *
+ * @param d dvb_content_identifier_descriptor pointer.
+ * @param pos Variable holding a pointer to the current dvb_content_identifier_entry.
+ */
+#define dvb_content_identifier_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_content_identifier_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_content_identifier_descriptor_entries_next(d, pos))
+
+/**
+ * Accessor for the data0 field of a dvb_content_identifier_entry.
+ *
+ * @param d dvb_content_identifier_entry pointer.
+ * @return Pointer, or NULL on error.
+ */
+static inline struct dvb_content_identifier_entry_data_0*
+ dvb_content_identifier_entry_data_0(struct dvb_content_identifier_entry *d)
+{
+ if (d->crid_location != 0)
+ return NULL;
+ return (struct dvb_content_identifier_entry_data_0*)
+ ((uint8_t*) d + sizeof(struct dvb_content_identifier_entry));
+}
+
+/**
+ * Accessor for the data1 field of a dvb_content_identifier_entry.
+ *
+ * @param d dvb_content_identifier_entry pointer.
+ * @return Pointer, or NULL on error.
+ */
+static inline struct dvb_content_identifier_entry_data_1*
+ dvb_content_identifier_entry_data_1(struct dvb_content_identifier_entry *d)
+{
+ if (d->crid_location != 1)
+ return NULL;
+ return (struct dvb_content_identifier_entry_data_1*)
+ ((uint8_t*) d + sizeof(struct dvb_content_identifier_entry));
+}
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_content_identifier_entry*
+ dvb_content_identifier_descriptor_entries_first(struct dvb_content_identifier_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_content_identifier_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_content_identifier_descriptor));
+}
+
+static inline struct dvb_content_identifier_entry*
+ dvb_content_identifier_descriptor_entries_next(struct dvb_content_identifier_descriptor *d,
+ struct dvb_content_identifier_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_content_identifier_entry);
+
+ if (next >= end)
+ return NULL;
+
+ switch(pos->crid_location) {
+ case 0:
+ if ((next+2) >= end)
+ return NULL;
+ if ((next+2+next[1]) >= end)
+ return NULL;
+ break;
+
+ case 1:
+ if ((next+3) >= end)
+ return NULL;
+ break;
+ }
+
+ return (struct dvb_content_identifier_entry*) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h
new file mode 100644
index 0000000..29a6b9a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/country_availability_descriptor.h
@@ -0,0 +1,120 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_COUNTRY_AVAILABILITY_DESCRIPTOR
+#define _UCSI_DVB_COUNTRY_AVAILABILITY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_country_availability_descriptor structure.
+ */
+struct dvb_country_availability_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t country_availability_flag : 1; ,
+ uint8_t reserved : 7; )
+ /* struct dvb_country_availability_entry countries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the countries field of a dvb_country_availability_descriptor.
+ */
+struct dvb_country_availability_entry {
+ iso639country_t country_code;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_country_availability_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_country_availability_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_country_availability_descriptor*
+ dvb_country_availability_descriptor_codec(struct descriptor* d)
+{
+ uint32_t len = d->len;
+
+ if (len < (sizeof(struct dvb_country_availability_descriptor) - 2))
+ return NULL;
+
+ if ((len - 1) % sizeof(struct dvb_country_availability_entry))
+ return NULL;
+
+ return (struct dvb_country_availability_descriptor*) d;
+}
+
+/**
+ * Iterator for the countries field of a dvb_country_availability_descriptor.
+ *
+ * @param d dvb_country_availability_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_country_availability_entry.
+ */
+#define dvb_country_availability_descriptor_countries_for_each(d, pos) \
+ for ((pos) = dvb_country_availability_descriptor_countries_first(d); \
+ (pos); \
+ (pos) = dvb_country_availability_descriptor_countries_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_country_availability_entry*
+ dvb_country_availability_descriptor_countries_first(struct dvb_country_availability_descriptor *d)
+{
+ if (d->d.len == 1)
+ return NULL;
+
+ return (struct dvb_country_availability_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_country_availability_descriptor));
+}
+
+static inline struct dvb_country_availability_entry*
+ dvb_country_availability_descriptor_countries_next(struct dvb_country_availability_descriptor *d,
+ struct dvb_country_availability_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_country_availability_entry);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_country_availability_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_descriptor.h
new file mode 100644
index 0000000..069e1db
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_descriptor.h
@@ -0,0 +1,139 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_DATA_BROADCAST_DESCRIPTOR
+#define _UCSI_DVB_DATA_BROADCAST_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_data_broadcast_descriptor structure.
+ */
+struct dvb_data_broadcast_descriptor {
+ struct descriptor d;
+
+ uint16_t data_broadcast_id;
+ uint8_t component_tag;
+ uint8_t selector_length;
+ /* uint8_t selector[] */
+ /* struct dvb_data_broadcast_descriptor_part2 part2 */
+} __ucsi_packed;
+
+/**
+ * Second part of a dvb_data_broadcast_descriptor following the variable length selector field.
+ */
+struct dvb_data_broadcast_descriptor_part2 {
+ iso639lang_t language_code;
+ uint8_t text_length;
+ /* uint8_t text[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_data_broadcast_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_data_broadcast_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_data_broadcast_descriptor*
+ dvb_data_broadcast_descriptor_codec(struct descriptor* d)
+{
+ struct dvb_data_broadcast_descriptor *p =
+ (struct dvb_data_broadcast_descriptor *) d;
+ struct dvb_data_broadcast_descriptor_part2 *p2;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = sizeof(struct dvb_data_broadcast_descriptor) - 2;
+ uint32_t len = d->len;
+
+ if (pos > len)
+ return NULL;
+
+ bswap16(buf + 2);
+
+ pos += p->selector_length;
+
+ if (pos > len)
+ return NULL;
+
+ p2 = (struct dvb_data_broadcast_descriptor_part2*) (buf + 2 + pos);
+
+ pos += sizeof(struct dvb_data_broadcast_descriptor_part2);
+
+ if (pos > len)
+ return NULL;
+
+ pos += p2->text_length;
+
+ if (pos != len)
+ return NULL;
+
+ return p;
+}
+
+/**
+ * Accessor for the selector field of a dvb_data_broadcast_descriptor.
+ *
+ * @param d dvb_data_broadcast_descriptor pointer.
+ * @return pointer to the field.
+ */
+static inline uint8_t *
+ dvb_data_broadcast_descriptor_selector(struct dvb_data_broadcast_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_data_broadcast_descriptor);
+}
+
+/**
+ * Accessor for the second part of a dvb_data_broadcast_descriptor.
+ *
+ * @param d dvb_data_broadcast_descriptor pointer.
+ * @return dvb_data_broadcast_descriptor_part2 pointer.
+ */
+static inline struct dvb_data_broadcast_descriptor_part2 *
+ dvb_data_broadcast_descriptor_part2(struct dvb_data_broadcast_descriptor *d)
+{
+ return (struct dvb_data_broadcast_descriptor_part2*)
+ ((uint8_t*) d + sizeof(struct dvb_data_broadcast_descriptor) +
+ d->selector_length);
+}
+
+/**
+ * Accessor for the text field in a dvb_data_broadcast_descriptor_part2.
+ *
+ * @param d dvb_data_broadcast_descriptor_part2 pointer.
+ * @return pointer to the field.
+ */
+static inline uint8_t *
+ dvb_data_broadcast_descriptor_part2_text(struct dvb_data_broadcast_descriptor_part2 *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_data_broadcast_descriptor_part2);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h
new file mode 100644
index 0000000..8547d8f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/data_broadcast_id_descriptor.h
@@ -0,0 +1,90 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_DATA_BROADCAST_ID_DESCRIPTOR
+#define _UCSI_DVB_DATA_BROADCAST_ID_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_data_broadcast_id_descriptor structure.
+ */
+struct dvb_data_broadcast_id_descriptor {
+ struct descriptor d;
+
+ uint16_t data_broadcast_id;
+ /* uint8_t id_selector_byte[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_data_broadcast_id_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_data_broadcast_id_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_data_broadcast_id_descriptor*
+ dvb_data_broadcast_id_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct dvb_data_broadcast_id_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+
+ return (struct dvb_data_broadcast_id_descriptor*) d;
+}
+
+/**
+ * Accessor for the selector_byte field of a dvb_data_broadcast_id_descriptor.
+ *
+ * @param d dvb_data_broadcast_id_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_data_broadcast_id_descriptor_id_selector_byte(struct dvb_data_broadcast_id_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_data_broadcast_id_descriptor);
+}
+
+/**
+ * Determine the length of the selector_byte field of a dvb_data_broadcast_id_descriptor.
+ *
+ * @param d dvb_data_broadcast_id_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_data_broadcast_id_descriptor_id_selector_byte_length(struct dvb_data_broadcast_id_descriptor *d)
+{
+ return d->d.len - 2;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#include <libucsi/dvb/mhp_data_broadcast_id_descriptor.h>
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/default_authority_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/default_authority_descriptor.h
new file mode 100644
index 0000000..0b0ba73
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/default_authority_descriptor.h
@@ -0,0 +1,82 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_DEFAULT_AUTHORITY_DESCRIPTOR
+#define _UCSI_DVB_DEFAULT_AUTHORITY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_default_authority_descriptor structure.
+ */
+struct dvb_default_authority_descriptor {
+ struct descriptor d;
+
+ /* char name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_default_authority_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_default_authority_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_default_authority_descriptor*
+ dvb_default_authority_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_default_authority_descriptor*) d;
+}
+
+/**
+ * Accessor for the name field in a dvb_default_authority_descriptor.
+ *
+ * @param d dvb_default_authority_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_default_authority_descriptor_name(struct dvb_default_authority_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_default_authority_descriptor);
+}
+
+/**
+ * Calculate the length of the name field in a dvb_default_authority_descriptor.
+ *
+ * @param d dvb_default_authority_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_default_authority_descriptor_name_length(struct dvb_default_authority_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h
new file mode 100644
index 0000000..0772601
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/descriptor.h
@@ -0,0 +1,198 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_DESCRIPTOR_H
+#define _UCSI_DVB_DESCRIPTOR_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/dvb/ac3_descriptor.h>
+#include <libucsi/dvb/adaptation_field_data_descriptor.h>
+#include <libucsi/dvb/ancillary_data_descriptor.h>
+#include <libucsi/dvb/announcement_support_descriptor.h>
+#include <libucsi/dvb/application_signalling_descriptor.h>
+#include <libucsi/dvb/bouquet_name_descriptor.h>
+#include <libucsi/dvb/ca_identifier_descriptor.h>
+#include <libucsi/dvb/cable_delivery_descriptor.h>
+#include <libucsi/dvb/cell_frequency_link_descriptor.h>
+#include <libucsi/dvb/cell_list_descriptor.h>
+#include <libucsi/dvb/component_descriptor.h>
+#include <libucsi/dvb/content_descriptor.h>
+#include <libucsi/dvb/content_identifier_descriptor.h>
+#include <libucsi/dvb/country_availability_descriptor.h>
+#include <libucsi/dvb/data_broadcast_descriptor.h>
+#include <libucsi/dvb/data_broadcast_id_descriptor.h>
+#include <libucsi/dvb/default_authority_descriptor.h>
+#include <libucsi/dvb/dsng_descriptor.h>
+#include <libucsi/dvb/extended_event_descriptor.h>
+#include <libucsi/dvb/frequency_list_descriptor.h>
+#include <libucsi/dvb/linkage_descriptor.h>
+#include <libucsi/dvb/local_time_offset_descriptor.h>
+#include <libucsi/dvb/mosaic_descriptor.h>
+#include <libucsi/dvb/multilingual_bouquet_name_descriptor.h>
+#include <libucsi/dvb/multilingual_component_descriptor.h>
+#include <libucsi/dvb/multilingual_network_name_descriptor.h>
+#include <libucsi/dvb/multilingual_service_name_descriptor.h>
+#include <libucsi/dvb/network_name_descriptor.h>
+#include <libucsi/dvb/nvod_reference_descriptor.h>
+#include <libucsi/dvb/parental_rating_descriptor.h>
+#include <libucsi/dvb/partial_transport_stream_descriptor.h>
+#include <libucsi/dvb/pdc_descriptor.h>
+#include <libucsi/dvb/private_data_specifier_descriptor.h>
+#include <libucsi/dvb/related_content_descriptor.h>
+#include <libucsi/dvb/satellite_delivery_descriptor.h>
+#include <libucsi/dvb/s2_satellite_delivery_descriptor.h>
+#include <libucsi/dvb/scrambling_descriptor.h>
+#include <libucsi/dvb/service_availability_descriptor.h>
+#include <libucsi/dvb/service_descriptor.h>
+#include <libucsi/dvb/service_identifier_descriptor.h>
+#include <libucsi/dvb/service_list_descriptor.h>
+#include <libucsi/dvb/service_move_descriptor.h>
+#include <libucsi/dvb/short_event_descriptor.h>
+#include <libucsi/dvb/short_smoothing_buffer_descriptor.h>
+#include <libucsi/dvb/stream_identifier_descriptor.h>
+#include <libucsi/dvb/stuffing_descriptor.h>
+#include <libucsi/dvb/subtitling_descriptor.h>
+#include <libucsi/dvb/telephone_descriptor.h>
+#include <libucsi/dvb/teletext_descriptor.h>
+#include <libucsi/dvb/terrestrial_delivery_descriptor.h>
+#include <libucsi/dvb/time_shifted_event_descriptor.h>
+#include <libucsi/dvb/time_shifted_service_descriptor.h>
+#include <libucsi/dvb/transport_stream_descriptor.h>
+#include <libucsi/dvb/tva_id_descriptor.h>
+#include <libucsi/dvb/vbi_data_descriptor.h>
+#include <libucsi/dvb/vbi_teletext_descriptor.h>
+#include <libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h>
+#include <libucsi/dvb/rnt_rar_over_ip_descriptor.h>
+#include <libucsi/dvb/rnt_rnt_scan_descriptor.h>
+#include <libucsi/dvb/ait_application_descriptor.h>
+#include <libucsi/dvb/ait_application_name_descriptor.h>
+#include <libucsi/dvb/ait_external_application_authorisation_descriptor.h>
+#include <libucsi/dvb/ait_application_icons_descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * The following are not implemented just now
+ */
+/*
+#include <libucsi/dvb/ait_transport_protocol_descriptor.h>
+#include <libucsi/dvb/ait_dvb_j_application_descriptor.h>
+#include <libucsi/dvb/ait_dvb_j_application_location_descriptor.h>
+#include <libucsi/dvb/ait_dvb_html_application_descriptor.h>
+#include <libucsi/dvb/ait_dvb_html_application_location_descriptor.h>
+#include <libucsi/dvb/ait_dvb_html_application_boundary_descriptor.h>
+#include <libucsi/dvb/ait_prefetch_descriptor.h>
+#include <libucsi/dvb/ait_dii_location_descriptor.h>
+#include <libucsi/dvb/ait_ip_signalling_descriptor.h>
+*/
+
+/**
+ * Enumeration of DVB descriptor tags.
+ */
+enum dvb_descriptor_tag {
+ dtag_dvb_network_name = 0x40,
+ dtag_dvb_service_list = 0x41,
+ dtag_dvb_stuffing = 0x42,
+ dtag_dvb_satellite_delivery_system = 0x43,
+ dtag_dvb_cable_delivery_system = 0x44,
+ dtag_dvb_vbi_data = 0x45,
+ dtag_dvb_vbi_teletext = 0x46,
+ dtag_dvb_bouquet_name = 0x47,
+ dtag_dvb_service = 0x48,
+ dtag_dvb_country_availability = 0x49,
+ dtag_dvb_linkage = 0x4a,
+ dtag_dvb_nvod_reference = 0x4b,
+ dtag_dvb_time_shifted_service = 0x4c,
+ dtag_dvb_short_event = 0x4d,
+ dtag_dvb_extended_event = 0x4e,
+ dtag_dvb_time_shifted_event = 0x4f,
+ dtag_dvb_component = 0x50,
+ dtag_dvb_mosaic = 0x51,
+ dtag_dvb_stream_identifier = 0x52,
+ dtag_dvb_ca_identifier = 0x53,
+ dtag_dvb_content = 0x54,
+ dtag_dvb_parental_rating = 0x55,
+ dtag_dvb_teletext = 0x56,
+ dtag_dvb_telephone = 0x57,
+ dtag_dvb_local_time_offset = 0x58,
+ dtag_dvb_subtitling = 0x59,
+ dtag_dvb_terrestial_delivery_system = 0x5a,
+ dtag_dvb_multilingual_network_name = 0x5b,
+ dtag_dvb_multilingual_bouquet_name = 0x5c,
+ dtag_dvb_multilingual_service_name = 0x5d,
+ dtag_dvb_multilingual_component = 0x5e,
+ dtag_dvb_private_data_specifier = 0x5f,
+ dtag_dvb_service_move = 0x60,
+ dtag_dvb_short_smoothing_buffer = 0x61,
+ dtag_dvb_frequency_list = 0x62,
+ dtag_dvb_partial_transport_stream = 0x63,
+ dtag_dvb_data_broadcast = 0x64,
+ dtag_dvb_scrambling = 0x65,
+ dtag_dvb_data_broadcast_id = 0x66,
+ dtag_dvb_transport_stream = 0x67,
+ dtag_dvb_dsng = 0x68,
+ dtag_dvb_pdc = 0x69,
+ dtag_dvb_ac3 = 0x6a,
+ dtag_dvb_ancillary_data = 0x6b,
+ dtag_dvb_cell_list = 0x6c,
+ dtag_dvb_cell_frequency_link = 0x6d,
+ dtag_dvb_announcement_support = 0x6e,
+ dtag_dvb_application_signalling = 0x6f,
+ dtag_dvb_adaptation_field_data = 0x70,
+ dtag_dvb_service_identifier = 0x71,
+ dtag_dvb_service_availability = 0x72,
+ dtag_dvb_default_authority = 0x73,
+ dtag_dvb_related_content = 0x74,
+ dtag_dvb_tva_id = 0x75,
+ dtag_dvb_content_identifier = 0x76,
+ dtag_dvb_time_slice_fec_identifier = 0x77,
+ dtag_dvb_ecm_repetition_rate = 0x78,
+ dtag_dvb_s2_satellite_delivery_descriptor= 0x79,
+
+ /* descriptors which may only appear in an RNT */
+ dtag_dvb_rnt_rar_over_dvb_stream = 0x40,
+ dtag_dvb_rnt_rar_over_ip = 0x41,
+ dtag_dvb_rnt_rnt_scan = 0x42,
+
+ /* descriptors which may only appear in an AIT */
+ dtag_dvb_ait_application = 0x00,
+ dtag_dvb_ait_application_name = 0x01,
+ dtag_dvb_ait_transport_protocol = 0x02,
+ dtag_dvb_ait_dvb_j_application = 0x03,
+ dtag_dvb_ait_dvb_j_application_location = 0x04,
+ dtag_dvb_ait_external_application_authorisation = 0x05,
+ dtag_dvb_ait_dvb_html_application = 0x08,
+ dtag_dvb_ait_dvb_html_application_location = 0x09,
+ dtab_dvb_ait_dvb_html_application_boundary = 0x0a,
+ dtag_dvb_ait_application_icons = 0x0b,
+ dtag_dvb_ait_prefetch = 0x0c,
+ dtag_dvb_ait_dii_location = 0x0d,
+ dtag_dvb_ait_ip_signalling = 0x11
+};/*__ucsi_packed;*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.c
new file mode 100644
index 0000000..4f69d4e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.c
@@ -0,0 +1,32 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/dit_section.h>
+
+struct dvb_dit_section * dvb_dit_section_codec(struct section * section)
+{
+ struct dvb_dit_section * ret = (struct dvb_dit_section *)section;
+
+ if (section->length < 1)
+ return NULL;
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.h
new file mode 100644
index 0000000..69fce4f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/dit_section.h
@@ -0,0 +1,54 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_DIT_SECTION_H
+#define _UCSI_DVB_DIT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_dit_section structure.
+ */
+struct dvb_dit_section {
+ struct section head;
+
+ EBIT2(uint8_t transition_flag : 1; ,
+ uint8_t reserved : 7; );
+};
+
+/**
+ * Process a dvb_dit_section.
+ *
+ * @param section Pointer to a generic section header.
+ * @return Pointer to a dvb_dit_section, or NULL on error.
+ */
+struct dvb_dit_section * dvb_dit_section_codec(struct section *section);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/dsng_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/dsng_descriptor.h
new file mode 100644
index 0000000..6fd369b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/dsng_descriptor.h
@@ -0,0 +1,80 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_DSNG_DESCRIPTOR
+#define _UCSI_DVB_DSNG_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_dsng_descriptor structure.
+ */
+struct dvb_dsng_descriptor {
+ struct descriptor d;
+
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_dsng_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to a dvb_dsng_descriptor, or NULL on error.
+ */
+static inline struct dvb_dsng_descriptor*
+ dvb_dsng_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_dsng_descriptor*) d;
+}
+
+/**
+ * Accessor for the data field in a dvb_dsng_descriptor.
+ *
+ * @param d dvb_dsng_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *dvb_dsng_descriptor_data(struct dvb_dsng_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_dsng_descriptor);
+}
+
+/**
+ * Determine the length of the data field in a dvb_dsng_descriptor.
+ *
+ * @param d dvb_dsng_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int dvb_dsng_descriptor_data_length(struct dvb_dsng_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c
new file mode 100644
index 0000000..ce22a58
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.c
@@ -0,0 +1,63 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/eit_section.h>
+
+struct dvb_eit_section *dvb_eit_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *) ext;
+ unsigned int pos = sizeof(struct section_ext);
+ unsigned int len = section_ext_length(ext);
+
+ if (len < sizeof(struct dvb_eit_section))
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += 2;
+ bswap16(buf + pos);
+ pos += 4;
+
+ while (pos < len) {
+ struct dvb_eit_event * event =
+ (struct dvb_eit_event *) (buf + pos);
+
+ if ((pos + sizeof(struct dvb_eit_event)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ bswap16(buf + pos + 10);
+
+ pos += sizeof(struct dvb_eit_event);
+
+ if ((pos + event->descriptors_loop_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, event->descriptors_loop_length))
+ return NULL;
+
+ pos += event->descriptors_loop_length;
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return (struct dvb_eit_section *) ext;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h
new file mode 100644
index 0000000..9064224
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/eit_section.h
@@ -0,0 +1,160 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_EIT_SECTION_H
+#define _UCSI_DVB_EIT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+#include <libucsi/dvb/types.h>
+
+
+/**
+ * dvb_eit_section structure.
+ */
+struct dvb_eit_section {
+ struct section_ext head;
+
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ uint8_t segment_last_section_number;
+ uint8_t last_table_id;
+ /* struct eit_event events[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the events field of a dvb_eit_section.
+ */
+struct dvb_eit_event {
+ uint16_t event_id;
+ dvbdate_t start_time;
+ dvbduration_t duration;
+ EBIT3(uint16_t running_status : 3; ,
+ uint16_t free_ca_mode : 1; ,
+ uint16_t descriptors_loop_length:12; );
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_eit_section.
+ *
+ * @param section Pointer to a generic section_ext structure.
+ * @return Pointer to a dvb_eit_section, or NULL on error.
+ */
+struct dvb_eit_section *dvb_eit_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the service_id field of an EIT.
+ *
+ * @param eit EIT pointer.
+ * @return The service_id.
+ */
+static inline uint16_t dvb_eit_section_service_id(struct dvb_eit_section *eit)
+{
+ return eit->head.table_id_ext;
+}
+
+/**
+ * Iterator for the events field of a dvb_eit_section.
+ *
+ * @param eit dvb_eit_section pointer.
+ * @param pos Variable containing a pointer to the current dvb_eit_event.
+ */
+#define dvb_eit_section_events_for_each(eit, pos) \
+ for ((pos) = dvb_eit_section_events_first(eit); \
+ (pos); \
+ (pos) = dvb_eit_section_events_next(eit, pos))
+
+/**
+ * Iterator for the descriptors field of a dvb_eit_event.
+ *
+ * @param eit dvb_eit_event pointer.
+ * @param pos Variable containing a pointer to the current descriptor.
+ */
+#define dvb_eit_event_descriptors_for_each(event, pos) \
+ for ((pos) = dvb_eit_event_descriptors_first(event); \
+ (pos); \
+ (pos) = dvb_eit_event_descriptors_next(event, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_eit_event *
+ dvb_eit_section_events_first(struct dvb_eit_section *eit)
+{
+ int pos = sizeof(struct dvb_eit_section);
+
+ if (pos >= section_ext_length(&eit->head))
+ return NULL;
+
+ return (struct dvb_eit_event*) ((uint8_t *) eit + pos);
+}
+
+static inline struct dvb_eit_event *
+ dvb_eit_section_events_next(struct dvb_eit_section *eit,
+ struct dvb_eit_event *pos)
+{
+ uint8_t *end = (uint8_t*) eit + section_ext_length(&eit->head);
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_eit_event) +
+ pos->descriptors_loop_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_eit_event *) next;
+}
+
+static inline struct descriptor *
+ dvb_eit_event_descriptors_first(struct dvb_eit_event * t)
+{
+ if (t->descriptors_loop_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) t + sizeof(struct dvb_eit_event));
+}
+
+static inline struct descriptor *
+ dvb_eit_event_descriptors_next(struct dvb_eit_event * t,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) t + sizeof(struct dvb_eit_event),
+ t->descriptors_loop_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h
new file mode 100644
index 0000000..82d580b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/extended_event_descriptor.h
@@ -0,0 +1,232 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_EXTENDED_EVENT_DESCRIPTOR
+#define _UCSI_DVB_EXTENDED_EVENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_extended_event_descriptor structure.
+ */
+struct dvb_extended_event_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t descriptor_number : 4; ,
+ uint8_t last_descriptor_number : 4; )
+ iso639lang_t language_code;
+ uint8_t length_of_items;
+ /* struct dvb_extended_event_item items[] */
+ /* struct dvb_extended_event_descriptor_part2 part2 */
+} __ucsi_packed;
+
+/**
+ * An entry in the items field of a dvb_extended_event_descriptor.
+ */
+struct dvb_extended_event_item {
+ uint8_t item_description_length;
+ /* uint8_t item_description[] */
+ /* struct dvb_extended_event_item_part2 part2 */
+} __ucsi_packed;
+
+/**
+ * The second part of a dvb_extended_event_item, following the variable length
+ * description field.
+ */
+struct dvb_extended_event_item_part2 {
+ uint8_t item_length;
+ /* uint8_t item[] */
+} __ucsi_packed;
+
+/**
+ * The second part of a dvb_extended_event_descriptor, following the variable
+ * length items field.
+ */
+struct dvb_extended_event_descriptor_part2 {
+ uint8_t text_length;
+ /* uint8_t text[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_extended_event_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_extended_event_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_extended_event_descriptor*
+ dvb_extended_event_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+ struct dvb_extended_event_descriptor * p =
+ (struct dvb_extended_event_descriptor *) d;
+ struct dvb_extended_event_descriptor_part2 *p2;
+
+ pos += sizeof(struct dvb_extended_event_descriptor) - 2;
+
+ if (pos > len)
+ return NULL;
+
+ pos += p->length_of_items;
+
+ if (pos > len)
+ return NULL;
+
+ p2 = (struct dvb_extended_event_descriptor_part2*) (buf+pos);
+
+ pos += sizeof(struct dvb_extended_event_descriptor_part2);
+
+ if (pos > len)
+ return NULL;
+
+ pos += p2->text_length;
+
+ if (pos != len)
+ return NULL;
+
+ return p;
+}
+
+/**
+ * Iterator for the items field of a dvb_extended_event_descriptor.
+ *
+ * @param d dvb_extended_event_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_extended_event_item.
+ */
+#define dvb_extended_event_descriptor_items_for_each(d, pos) \
+ for ((pos) = dvb_extended_event_descriptor_items_first(d); \
+ (pos); \
+ (pos) = dvb_extended_event_descriptor_items_next(d, pos))
+
+/**
+ * Accessor for the description field of a dvb_extended_event_item.
+ *
+ * @param d dvb_extended_event_item pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ dvb_extended_event_item_description(struct dvb_extended_event_item *d)
+{
+ return (uint8_t*) d + sizeof(struct dvb_extended_event_item);
+}
+
+/**
+ * Accessor for the second part of a dvb_extended_event_item.
+ *
+ * @param dvb_extended_event_item pointer.
+ * @return dvb_extended_event_item_part2 pointer.
+ */
+static inline struct dvb_extended_event_item_part2*
+ dvb_extended_event_item_part2(struct dvb_extended_event_item *d)
+{
+ return (struct dvb_extended_event_item_part2*)
+ ((uint8_t*) d + sizeof(struct dvb_extended_event_item) +
+ d->item_description_length);
+}
+
+/**
+ * Accessor for the item field of a dvb_extended_event_item_part2.
+ *
+ * @param d dvb_extended_event_item_part2 pointer.
+ * @return Pointer to the item field.
+ */
+static inline uint8_t*
+ dvb_extended_event_item_part2_item(struct dvb_extended_event_item_part2 *d)
+{
+ return (uint8_t*) d + sizeof(struct dvb_extended_event_item_part2);
+}
+
+/**
+ * Accessor for the second part of a dvb_extended_event_descriptor.
+ *
+ * @param d dvb_extended_event_descriptor pointer.
+ * @return dvb_extended_event_descriptor_part2 pointer.
+ */
+static inline struct dvb_extended_event_descriptor_part2*
+ dvb_extended_event_descriptor_part2(struct dvb_extended_event_descriptor *d)
+{
+ return (struct dvb_extended_event_descriptor_part2*)
+ ((uint8_t*) d + sizeof(struct dvb_extended_event_descriptor) +
+ d->length_of_items);
+}
+
+/**
+ * Accessor for the text field of an dvb_extended_event_descriptor_part2.
+ *
+ * @param d dvb_extended_event_descriptor_part2 pointer.
+ * @return Pointer to the text field.
+ */
+static inline uint8_t*
+ dvb_extended_event_descriptor_part2_text(struct dvb_extended_event_descriptor_part2 *d)
+{
+ return (uint8_t*)
+ ((uint8_t*) d + sizeof(struct dvb_extended_event_descriptor_part2));
+}
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_extended_event_item*
+ dvb_extended_event_descriptor_items_first(struct dvb_extended_event_descriptor *d)
+{
+ if (d->length_of_items == 0)
+ return NULL;
+
+ return (struct dvb_extended_event_item *)
+ ((uint8_t*) d + sizeof(struct dvb_extended_event_descriptor));
+}
+
+static inline struct dvb_extended_event_item*
+ dvb_extended_event_descriptor_items_next(struct dvb_extended_event_descriptor *d,
+ struct dvb_extended_event_item *pos)
+{
+ struct dvb_extended_event_item_part2* part2 =
+ dvb_extended_event_item_part2(pos);
+ uint8_t *end = (uint8_t*) d + sizeof(struct dvb_extended_event_descriptor) + d->length_of_items;
+ uint8_t *next = (uint8_t *) part2 +
+ sizeof(struct dvb_extended_event_item_part2) +
+ part2->item_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_extended_event_item *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h
new file mode 100644
index 0000000..4fca751
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/frequency_list_descriptor.h
@@ -0,0 +1,107 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_FREQUENCY_LIST_DESCRIPTOR
+#define _UCSI_DVB_FREQUENCY_LIST_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for coding_type.
+ */
+enum {
+ DVB_CODING_TYPE_SATELLITE = 0x01,
+ DVB_CODING_TYPE_CABLE = 0x02,
+ DVB_CODING_TYPE_TERRESTRIAL = 0x03
+};
+
+/**
+ * dvb_frequency_list_descriptor structure.
+ */
+struct dvb_frequency_list_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t reserved : 6; ,
+ uint8_t coding_type : 2; )
+ /* uint32_t centre_frequencies [] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_frequency_list_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ * @return dvb_frequency_list_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_frequency_list_descriptor*
+ dvb_frequency_list_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+
+ pos += sizeof(struct dvb_frequency_list_descriptor) - 2;
+
+ if ((len - pos) % 4)
+ return NULL;
+
+ while(pos < len) {
+ bswap32(buf+pos);
+ pos += 4;
+ }
+
+ return (struct dvb_frequency_list_descriptor*) d;
+}
+
+/**
+ * Accessor for the centre_frequencies field of a dvb_frequency_list_descriptor.
+ *
+ * @param d dvb_frequency_list_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint32_t *
+ dvb_frequency_list_descriptor_centre_frequencies(struct dvb_frequency_list_descriptor *d)
+{
+ return (uint32_t *) ((uint8_t *) d + sizeof(struct dvb_frequency_list_descriptor));
+}
+
+/**
+ * Determine the number of entries in the centre_frequencies field of a dvb_frequency_list_descriptor.
+ *
+ * @param d dvb_frequency_list_descriptor pointer.
+ * @return The number of entries.
+ */
+static inline int
+ dvb_frequency_list_descriptor_centre_frequencies_count(struct dvb_frequency_list_descriptor *d)
+{
+ return (d->d.len - 1) >> 2;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c
new file mode 100644
index 0000000..a6ddd6e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.c
@@ -0,0 +1,80 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ * Copyright (C) 2005 Patrick Boettcher (pb@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/int_section.h>
+
+struct dvb_int_section * dvb_int_section_codec(struct section_ext *ext)
+{
+ uint8_t *buf = (uint8_t *) ext;
+ struct dvb_int_section *in = (struct dvb_int_section *) ext;
+
+ unsigned int pos = sizeof(struct section_ext);
+ unsigned int len = section_ext_length(ext);
+
+ if (len < sizeof(struct dvb_int_section))
+ return NULL;
+
+ bswap32(buf+8);
+ bswap16(buf+12);
+ pos += 9;
+
+ if (len - pos < in->platform_descriptors_length)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, in->platform_descriptors_length))
+ return NULL;
+
+ pos += in->platform_descriptors_length;
+
+ while (pos < len) {
+ struct dvb_int_target *s2 = (struct dvb_int_target *) (buf + pos);
+ struct dvb_int_operational_loop *s3;
+
+ bswap16(buf + pos); /* target_descriptor_loop_length swap */
+
+ if (len - pos < s2->target_descriptors_length)
+ return NULL;
+
+ pos += sizeof(struct dvb_int_target);
+
+ if (verify_descriptors(buf + pos, s2->target_descriptors_length))
+ return NULL;
+
+ pos += s2->target_descriptors_length;
+
+ s3 = (struct dvb_int_operational_loop *) (buf + pos);
+
+ bswap16(buf + pos); /* operational_descriptor_loop_length swap */
+
+ if (len - pos < s3->operational_descriptors_length)
+ return NULL;
+
+ pos += sizeof(struct dvb_int_operational_loop);
+
+ if (verify_descriptors(buf + pos, s3->operational_descriptors_length))
+ return NULL;
+
+ pos += s3->operational_descriptors_length;
+ }
+
+ return (struct dvb_int_section *) ext;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h
new file mode 100644
index 0000000..71ba1e8
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/int_section.h
@@ -0,0 +1,245 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ * Copyright (C) 2005 Patrick Boettcher (pb@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#ifndef _UCSI_DVB_INT_SECTION_H
+#define _UCSI_DVB_INT_SECTION_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_int_section structure - IP/MAC notification section.
+ */
+struct dvb_int_section {
+ struct section_ext head;
+
+ EBIT2(uint32_t platform_id :24; ,
+ uint32_t processing_order : 8; );
+ EBIT2(uint16_t reserved2 : 4; ,
+ uint16_t platform_descriptors_length :12; );
+ /* struct descriptor platform_descriptors[] */
+ /* struct dvb_int_target target_loop[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the target_loop field of a dvb_int_section.
+ */
+struct dvb_int_target {
+ EBIT2(uint16_t reserved3 : 4; ,
+ uint16_t target_descriptors_length :12; );
+ /* struct descriptor target_descriptors[] */
+ /* struct dvb_int_operational_loop operational_loop */
+} __ucsi_packed;
+
+/**
+ * The operational_loop field in a dvb_int_target.
+ */
+struct dvb_int_operational_loop {
+ EBIT2(uint16_t reserved4 : 4; ,
+ uint16_t operational_descriptors_length :12; );
+ /* struct descriptor operational_descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_int_section.
+ *
+ * @param section Generic section_ext pointer.
+ * @return dvb_int_section pointer, or NULL on error.
+ */
+extern struct dvb_int_section * dvb_int_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the action_type field of an INT.
+ *
+ * @param intp INT pointer.
+ * @return The action_type.
+ */
+static inline uint8_t dvb_int_section_action_type(struct dvb_int_section *intp)
+{
+ return intp->head.table_id_ext >> 8;
+}
+
+/**
+ * Accessor for the platform_id_hash field of an INT.
+ *
+ * @param intp INT pointer.
+ * @return The platform_id_hash.
+ */
+static inline uint8_t dvb_int_section_platform_id_hash(struct dvb_int_section *intp)
+{
+ return intp->head.table_id_ext & 0xff;
+}
+
+/**
+ * Iterator for platform_descriptors field in a dvb_int_section.
+ *
+ * @param intp dvb_int_section pointer.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define dvb_int_section_platform_descriptors_for_each(intp, pos) \
+ for ((pos) = dvb_int_section_platform_descriptors_first(intp); \
+ (pos); \
+ (pos) = dvb_int_section_platform_descriptors_next(intp, pos))
+
+/**
+ * Iterator for the target_loop field in a dvb_int_section.
+ *
+ * @param intp dvb_int_section pointer.
+ * @param pos Variable holding a pointer to the current dvb_int_target.
+ */
+#define dvb_int_section_target_loop_for_each(intp,pos) \
+ for ((pos) = dvb_int_section_target_loop_first(intp); \
+ (pos); \
+ (pos) = dvb_int_section_target_loop_next(intp, pos))
+
+/**
+ * Iterator for the target_descriptors field in a dvb_int_target.
+ *
+ * @param target dvb_int_target pointer.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define dvb_int_target_target_descriptors_for_each(target, pos) \
+ for ((pos) = dvb_int_target_target_descriptors_first(target); \
+ (pos); \
+ (pos) = dvb_int_target_target_descriptors_next(target, pos))
+
+/**
+ * Accessor for the operational_loop field of a dvb_int_target.
+ *
+ * @param target dvb_int_target pointer.
+ * @return Pointer to a dvb_int_operational_loop.
+ */
+static inline struct dvb_int_operational_loop *
+ dvb_int_target_operational_loop(struct dvb_int_target *target)
+{
+ return (struct dvb_int_operational_loop *)
+ ((uint8_t *) target + sizeof(struct dvb_int_target) + target->target_descriptors_length);
+}
+
+/**
+ * Iterator for the operational_descriptors field in a dvb_int_operational_loop.
+ *
+ * @param oploop dvb_int_operational_loop pointer.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define dvb_int_operational_loop_operational_descriptors_for_each(oploop, pos) \
+ for ((pos) = dvb_int_operational_loop_operational_descriptors_first(oploop); \
+ (pos); \
+ (pos) = dvb_int_operational_loop_operational_descriptors_next(oploop, pos))
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ dvb_int_section_platform_descriptors_first(struct dvb_int_section *in)
+{
+ if (in->platform_descriptors_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) in + sizeof(struct dvb_int_section));
+}
+
+static inline struct descriptor *
+ dvb_int_section_platform_descriptors_next(struct dvb_int_section *in,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) in + sizeof(struct dvb_int_section),
+ in->platform_descriptors_length,
+ pos);
+}
+
+static inline struct dvb_int_target *
+ dvb_int_section_target_loop_first(struct dvb_int_section *in)
+{
+ if (sizeof(struct dvb_int_section) + in->platform_descriptors_length >= (uint32_t) section_ext_length((struct section_ext *) in))
+ return NULL;
+
+ return (struct dvb_int_target *)
+ ((uint8_t *) in + sizeof(struct dvb_int_section) + in->platform_descriptors_length);
+}
+
+static inline struct dvb_int_target *
+ dvb_int_section_target_loop_next(struct dvb_int_section *in,
+ struct dvb_int_target *pos)
+{
+ struct dvb_int_operational_loop *ol = dvb_int_target_operational_loop(pos);
+ struct dvb_int_target *next =
+ (struct dvb_int_target *) ( (uint8_t *) pos +
+ sizeof(struct dvb_int_target) + pos->target_descriptors_length +
+ sizeof(struct dvb_int_operational_loop) + ol->operational_descriptors_length);
+ struct dvb_int_target *end =
+ (struct dvb_int_target *) ((uint8_t *) in + section_ext_length((struct section_ext *) in) );
+
+ if (next >= end)
+ return 0;
+ return next;
+}
+
+static inline struct descriptor *
+ dvb_int_target_target_descriptors_first(struct dvb_int_target *tl)
+{
+ if (tl->target_descriptors_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) tl + sizeof(struct dvb_int_target));
+}
+
+static inline struct descriptor *
+ dvb_int_target_target_descriptors_next(struct dvb_int_target *tl,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) tl + sizeof(struct dvb_int_target),
+ tl->target_descriptors_length,
+ pos);
+}
+
+static inline struct descriptor *
+ dvb_int_operational_loop_operational_descriptors_first(struct dvb_int_operational_loop *ol)
+{
+ if (ol->operational_descriptors_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) ol + sizeof(struct dvb_int_operational_loop));
+}
+
+static inline struct descriptor *
+ dvb_int_operational_loop_operational_descriptors_next(struct dvb_int_operational_loop *ol,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) ol + sizeof(struct dvb_int_operational_loop),
+ ol->operational_descriptors_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h
new file mode 100644
index 0000000..f3370c8
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/linkage_descriptor.h
@@ -0,0 +1,478 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_LINKAGE_DESCRIPTOR
+#define _UCSI_DVB_LINKAGE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * Possible values for linkage_type.
+ */
+enum {
+ DVB_LINKAGE_TYPE_INFORMATION = 0x01,
+ DVB_LINKAGE_TYPE_EPG = 0x02,
+ DVB_LINKAGE_TYPE_CA_REPLACEMENT = 0x03,
+ DVB_LINKAGE_TYPE_TS_WITH_BAT_NIT = 0x04,
+ DVB_LINKAGE_TYPE_SERVICE_REPLACMENT = 0x05,
+ DVB_LINKAGE_TYPE_DATA_BCAST = 0x06,
+ DVB_LINKAGE_TYPE_RCS_MAP = 0x07,
+ DVB_LINKAGE_TYPE_MOBILE_HANDOVER = 0x08,
+ DVB_LINKAGE_TYPE_SOFTWARE_UPDATE = 0x09,
+ DVB_LINKAGE_TYPE_TS_WITH_SSU_BAT_NIT = 0x0a,
+ DVB_LINKAGE_TYPE_IP_MAC_NOTIFICATION = 0x0b,
+ DVB_LINKAGE_TYPE_TS_WITH_INT_BAT_NIT = 0x0c
+};
+
+/**
+ * Possible values for hand_over_type.
+ */
+enum {
+ DVB_HAND_OVER_TYPE_IDENTICAL_NEIGHBOURING_COUNTRY = 0x01,
+ DVB_HAND_OVER_TYPE_LOCAL_VARIATION = 0x02,
+ DVB_HAND_OVER_TYPE_ASSOCIATED_SERVICE = 0x03
+};
+
+/**
+ * Possible values for origin_type.
+ */
+enum {
+ DVB_ORIGIN_TYPE_NIT = 0x00,
+ DVB_ORIGIN_TYPE_SDT = 0x01
+};
+
+/**
+ * dvb_linkage_descriptor structure.
+ */
+struct dvb_linkage_descriptor {
+ struct descriptor d;
+
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ uint16_t service_id;
+ uint8_t linkage_type;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Data for a linkage_type of 0x08.
+ */
+struct dvb_linkage_data_08 {
+ EBIT3(uint8_t hand_over_type : 4; ,
+ uint8_t reserved : 3; ,
+ uint8_t origin_type : 1; )
+ /* uint16_t network_id if hand_over_type == 1,2,3 */
+ /* uint16_t initial_service_id if origin_type = 0 */
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Data for an linkage_type of 0x0b (IP/MAC Notification Table).
+ */
+struct dvb_linkage_data_0b {
+ uint8_t platform_id_data_length;
+ /* struct platform_id ids[] */
+} __ucsi_packed;
+
+/**
+ * Entries in the ids field of a dvb_linkage_data_0b.
+ */
+struct dvb_platform_id {
+ EBIT2(uint32_t platform_id : 24; ,
+ uint32_t platform_name_loop_length : 8; )
+ /* struct platform_name names[] */
+} __ucsi_packed;
+
+/**
+ * Entries in the names field of a dvb_platform_id.
+ */
+struct dvb_platform_name {
+ iso639lang_t language_code;
+ uint8_t platform_name_length;
+ /* uint8_t text[] */
+} __ucsi_packed;
+
+/**
+ * Data for a linkage_type of 0x0c (IP/MAC Notification Table).
+ */
+struct dvb_linkage_data_0c {
+ uint8_t table_type;
+ /* uint16_t bouquet_id if table_type == 0x02 */
+} __ucsi_packed;
+
+
+/**
+ * Process a dvb_linkage_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_linkage_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_linkage_descriptor*
+ dvb_linkage_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+ struct dvb_linkage_descriptor *p =
+ (struct dvb_linkage_descriptor*) d;
+
+ if (len < (sizeof(struct dvb_linkage_descriptor) - 2))
+ return NULL;
+
+ bswap16(buf);
+ bswap16(buf+2);
+ bswap16(buf+4);
+
+ pos += sizeof(struct dvb_linkage_descriptor) - 2;
+
+ if (p->linkage_type == 0x08) {
+ struct dvb_linkage_data_08 *d08;
+
+ if ((len - pos) < sizeof(struct dvb_linkage_data_08))
+ return NULL;
+ d08 = (struct dvb_linkage_data_08 *) (buf+pos);
+ pos += sizeof(struct dvb_linkage_data_08);
+
+ switch(d08->hand_over_type) {
+ case 1:
+ case 2:
+ case 3:
+ if ((len - pos) < 2)
+ return NULL;
+ bswap16(buf+pos);
+ pos += 2;
+ break;
+ }
+ if (d08->origin_type == 0) {
+ if ((len - pos) < 2)
+ return NULL;
+ bswap16(buf+pos);
+ pos+=2;
+ }
+
+ } else if (p->linkage_type == 0x0b) {
+ uint32_t pos2=0;
+ struct dvb_linkage_data_0b *l_0b = (struct dvb_linkage_data_0b *) (buf + pos);
+
+ if ((len - pos) < sizeof(struct dvb_linkage_data_0b))
+ return NULL;
+
+ pos += sizeof(struct dvb_linkage_data_0b);
+ if ((len - pos) < l_0b->platform_id_data_length)
+ return NULL;
+
+ while (pos2 < l_0b->platform_id_data_length) {
+ struct dvb_platform_id *p_id = (struct dvb_platform_id *) (buf + pos + pos2);
+ if ((len - pos - pos2) < p_id->platform_name_loop_length)
+ return NULL;
+
+ pos2 += sizeof(struct dvb_platform_id) + p_id->platform_name_loop_length;
+ }
+
+ pos += pos2;
+ } else if (p->linkage_type == 0x0c) {
+ struct dvb_linkage_data_0c *l_0c = (struct dvb_linkage_data_0c *) (buf + pos);
+
+ if ((len - pos) < sizeof(struct dvb_linkage_data_0c))
+ return NULL;
+ pos += sizeof(struct dvb_linkage_data_0c);
+
+ if (l_0c->table_type == 0x02) {
+ if ((len - pos) < 2)
+ return NULL;
+ bswap16(buf+pos);
+ }
+ }
+
+ return (struct dvb_linkage_descriptor*) d;
+}
+
+/**
+ * Accessor for the data field of a dvb_linkage_descriptor.
+ *
+ * @param d dvb_linkage_descriptor pointer.
+ * @return Pointer to the data field.
+ */
+static inline uint8_t *
+ dvb_linkage_descriptor_data(struct dvb_linkage_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_linkage_descriptor);
+}
+
+/**
+ * Determine the length of the data field of a dvb_linkage_descriptor.
+ *
+ * @param d dvb_linkage_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_linkage_descriptor_data_length(struct dvb_linkage_descriptor *d)
+{
+ return d->d.len - 7;
+}
+
+/**
+ * Accessor for a dvb_linkage_data_08 pointer.
+ *
+ * @param d dvb_linkage_descriptor pointer.
+ * @return Pointer to the data field.
+ */
+static inline struct dvb_linkage_data_08 *
+ dvb_linkage_data_08(struct dvb_linkage_descriptor *d)
+{
+ if (d->linkage_type != 0x08)
+ return NULL;
+ return (struct dvb_linkage_data_08 *) dvb_linkage_descriptor_data(d);
+}
+
+/**
+ * Accessor for the network_id field of a dvb_linkage_data_08.
+ *
+ * @param d dvb_linkage_descriptor pointer
+ * @param d08 dvb_linkage_data_08 pointer.
+ * @return network_id, or -1 if not present
+ */
+static inline int
+ dvb_linkage_data_08_network_id(struct dvb_linkage_descriptor *d, struct dvb_linkage_data_08 *d08)
+{
+ if (d->linkage_type != 0x08)
+ return -1;
+
+ switch(d08->hand_over_type) {
+ case 1:
+ case 2:
+ case 3:
+ return *((uint16_t*) ((uint8_t*) d08 + sizeof(struct dvb_linkage_data_08)));
+ }
+
+ return -1;
+}
+
+/**
+ * Accessor for the initial_service_id field of a dvb_linkage_data_08.
+ *
+ * @param d dvb_linkage_descriptor pointer
+ * @param d08 dvb_linkage_data_08 pointer.
+ * @return initial_service_id, or -1 if not present
+ */
+static inline int
+ dvb_linkage_data_08_initial_service_id(struct dvb_linkage_descriptor *d, struct dvb_linkage_data_08 *d08)
+{
+ uint8_t *pos;
+
+ if (d->linkage_type != 0x08)
+ return -1;
+ if (d08->origin_type != 0)
+ return -1;
+
+ pos = ((uint8_t*) d08) + sizeof(struct dvb_linkage_data_08);
+ switch(d08->hand_over_type) {
+ case 1:
+ case 2:
+ case 3:
+ pos +=2;
+ break;
+ }
+
+ return *((uint16_t*) pos);
+}
+
+/**
+ * Accessor for the data field of a dvb_linkage_data_08.
+ *
+ * @param d dvb_linkage_descriptor pointer
+ * @param d08 dvb_linkage_data_08 pointer.
+ * @param length Pointer to int destination for data length.
+ * @return Pointer to the data field, or NULL if invalid
+ */
+static inline uint8_t *
+ dvb_linkage_data_08_data(struct dvb_linkage_descriptor *d, struct dvb_linkage_data_08 *d08, int *length)
+{
+ uint8_t *pos;
+ int used = 0;
+
+ if (d->linkage_type != 0x08) {
+ *length = 0;
+ return NULL;
+ }
+
+ pos = ((uint8_t*) d08) + sizeof(struct dvb_linkage_data_08);
+ switch(d08->hand_over_type) {
+ case 1:
+ case 2:
+ case 3:
+ pos += 2;
+ used += 2;
+ break;
+ }
+ if (d08->origin_type == 0) {
+ pos+=2;
+ used+=2;
+ }
+
+ *length = dvb_linkage_descriptor_data_length(d) - (sizeof(struct dvb_linkage_data_08) + used);
+ return pos;
+}
+
+/**
+ * Accessor for a dvb_linkage_data_0b pointer.
+ *
+ * @param d dvb_linkage_descriptor pointer.
+ * @return Pointer to the data field.
+ */
+static inline struct dvb_linkage_data_0b *
+ dvb_linkage_data_0b(struct dvb_linkage_descriptor *d)
+{
+ if (d->linkage_type != 0x0b)
+ return NULL;
+ return (struct dvb_linkage_data_0b *) dvb_linkage_descriptor_data(d);
+}
+
+/**
+ * Iterator for the platform_id field of a dvb_linkage_data_0b.
+ *
+ * @param linkage dvb_linkage_data_0b pointer.
+ * @param pos Variable containing a pointer to the current dvb_platform_id.
+ */
+#define dvb_dvb_linkage_data_0b_platform_id_for_each(linkage, pos) \
+ for ((pos) = dvb_platform_id_first(linkage); \
+ (pos); \
+ (pos) = dvb_platform_id_next(linkage, pos))
+
+/**
+ * Iterator for the platform_name field of a dvb_platform_id.
+ *
+ * @param platid dvb_platform_id pointer.
+ * @param pos Variable containing a pointer to the current dvb_platform_name.
+ */
+#define dvb_platform_id_platform_name_for_each(platid, pos) \
+ for ((pos) = dvb_platform_name_first(platid); \
+ (pos); \
+ (pos) = dvb_platform_name_next(platid, pos))
+
+/**
+ * Accessor for the text field of a dvb_platform_name.
+ *
+ * @param p dvb_platform_name pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_platform_name_text(struct dvb_platform_name *p)
+{
+ return (uint8_t *) p + sizeof(struct dvb_platform_name);
+}
+
+/**
+ * Accessor for a dvb_linkage_data_0c pointer.
+ *
+ * @param d dvb_linkage_descriptor pointer.
+ * @return Pointer to the data field.
+ */
+static inline struct dvb_linkage_data_0c *
+ dvb_linkage_data_0c(struct dvb_linkage_descriptor *d)
+{
+ if (d->linkage_type != 0x0c)
+ return NULL;
+ return (struct dvb_linkage_data_0c *) dvb_linkage_descriptor_data(d);
+}
+
+/**
+ * Accessor for the bouquet_id field of a dvb_linkage_data_0c if table_id == 0x02.
+ *
+ * @param l_0c dvb_linkage_data_0c pointer.
+ * @return The bouquet field, or -1 on error.
+ */
+static inline int
+ dvb_linkage_data_0c_bouquet_id(struct dvb_linkage_data_0c *l_0c)
+{
+ if (l_0c->table_type != 0x02)
+ return -1;
+
+ return *((uint16_t *) ((uint8_t*) l_0c + 1));
+}
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_platform_id *
+ dvb_platform_id_first(struct dvb_linkage_data_0b *d)
+{
+ if (d->platform_id_data_length == 0)
+ return NULL;
+
+ return (struct dvb_platform_id *) ((uint8_t *) d + sizeof(struct dvb_linkage_data_0b));
+}
+
+static inline struct dvb_platform_id *
+ dvb_platform_id_next(struct dvb_linkage_data_0b *d,
+ struct dvb_platform_id *pos)
+{
+ uint8_t *end = (uint8_t *) d + d->platform_id_data_length;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_platform_id) +
+ pos->platform_name_loop_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_platform_id *) next;
+}
+
+static inline struct dvb_platform_name *
+ dvb_platform_name_first(struct dvb_platform_id *p)
+{
+ if (p->platform_name_loop_length == 0)
+ return NULL;
+
+ return (struct dvb_platform_name *) ((uint8_t *) p + sizeof(struct dvb_platform_id));
+}
+
+static inline struct dvb_platform_name *
+ dvb_platform_name_next(struct dvb_platform_id *p,
+ struct dvb_platform_name *pos)
+{
+ uint8_t *end = (uint8_t *) p + p->platform_name_loop_length;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_platform_name) +
+ pos->platform_name_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_platform_name *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h
new file mode 100644
index 0000000..94932ff
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/local_time_offset_descriptor.h
@@ -0,0 +1,127 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_LOCAL_TIME_OFFSET_DESCRIPTOR
+#define _UCSI_DVB_LOCAL_TIME_OFFSET_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+#include <libucsi/dvb/types.h>
+
+/**
+ * dvb_local_time_offset_descriptor parameter.
+ */
+struct dvb_local_time_offset_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_local_time_offset offsets[] */
+} __ucsi_packed;
+
+/**
+ * Entry in the offsets field of dvb_local_time_offset_descriptor.
+ */
+struct dvb_local_time_offset {
+ iso639country_t country_code;
+ EBIT3(uint8_t country_region_id : 6; ,
+ uint8_t reserved : 1; ,
+ uint8_t local_time_offset_polarity : 1; )
+ dvbhhmm_t local_time_offset;
+ dvbdate_t time_of_change;
+ dvbhhmm_t next_time_offset;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_local_time_offset_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_local_time_offset_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_local_time_offset_descriptor*
+ dvb_local_time_offset_descriptor_codec(struct descriptor* d)
+{
+ uint32_t len = d->len;
+ uint32_t pos = 0;
+
+ if (len % sizeof(struct dvb_local_time_offset))
+ return NULL;
+
+ while(pos < len) {
+ pos += sizeof(struct dvb_local_time_offset);
+ }
+
+ return (struct dvb_local_time_offset_descriptor*) d;
+}
+
+/**
+ * Iterator for the offsets field of a dvb_local_time_offset_descriptor.
+ *
+ * @param d dvb_local_time_offset_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_local_time_offset.
+ */
+#define dvb_local_time_offset_descriptor_offsets_for_each(d, pos) \
+ for ((pos) = dvb_local_time_offset_descriptor_offsets_first(d); \
+ (pos); \
+ (pos) = dvb_local_time_offset_descriptor_offsets_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_local_time_offset*
+ dvb_local_time_offset_descriptor_offsets_first(struct dvb_local_time_offset_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_local_time_offset *)
+ ((uint8_t*) d + sizeof(struct dvb_local_time_offset_descriptor));
+}
+
+static inline struct dvb_local_time_offset*
+ dvb_local_time_offset_descriptor_offsets_next(struct dvb_local_time_offset_descriptor *d,
+ struct dvb_local_time_offset *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_local_time_offset);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_local_time_offset *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h
new file mode 100644
index 0000000..d5cf435
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/mhp_data_broadcast_id_descriptor.h
@@ -0,0 +1,110 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_MHP_DATA_BROADCAST_ID_DESCRIPTOR
+#define _UCSI_DVB_MHP_DATA_BROADCAST_ID_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifndef _UCSI_DVB_DATA_BROADCAST_ID_DESCRIPTOR
+#error Must include dvb/data_broadcast_id_descriptor.h first
+#endif
+
+/**
+ * Broadcast IDs for MHP.
+ */
+enum {
+ DVB_BROADCAST_ID_MHP_OBJECT_CAROUSEL = 0x00f0,
+ DVB_BROADCAST_ID_MHP_MPE = 0x00f1
+};
+
+/**
+ * dvb_mhp_data_broadcast_id_descriptor structure.
+ */
+struct dvb_mhp_data_broadcast_id_descriptor {
+ struct dvb_data_broadcast_id_descriptor d;
+ /* uint16_t application_type[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_mhp_data_broadcast_id_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_mhp_data_broadcast_id_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_mhp_data_broadcast_id_descriptor*
+ dvb_mhp_data_broadcast_id_descriptor_codec(struct dvb_data_broadcast_id_descriptor* d)
+{
+ uint8_t * buf;
+ int len;
+ int pos = 0;
+ struct dvb_mhp_data_broadcast_id_descriptor *res =
+ (struct dvb_mhp_data_broadcast_id_descriptor *) d;
+
+ if ((res->d.data_broadcast_id < 0xf0) || (res->d.data_broadcast_id > 0xfe))
+ return NULL;
+
+ buf = dvb_data_broadcast_id_descriptor_id_selector_byte(d);
+ len = dvb_data_broadcast_id_descriptor_id_selector_byte_length(d);
+
+ if (len % 2)
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ pos+=2;
+ }
+
+ return res;
+}
+
+/**
+ * Accessor for the application_type field of a dvb_mhp_data_broadcast_id_descriptor.
+ *
+ * @param d dvb_mhp_data_broadcast_id_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint16_t *
+ dvb_mhp_data_broadcast_id_descriptor_id_application_type(struct dvb_mhp_data_broadcast_id_descriptor *d)
+{
+ return (uint16_t *) dvb_data_broadcast_id_descriptor_id_selector_byte((struct dvb_data_broadcast_id_descriptor*) d);
+}
+
+/**
+ * Determine the number of entries in the application_type field of a dvb_mhp_data_broadcast_id_descriptor.
+ *
+ * @param d dvb_data_broadcast_id_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_mhp_data_broadcast_id_descriptor_id_application_type_count(struct dvb_mhp_data_broadcast_id_descriptor *d)
+{
+ return dvb_data_broadcast_id_descriptor_id_selector_byte_length((struct dvb_data_broadcast_id_descriptor*) d) >> 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h
new file mode 100644
index 0000000..28838de
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/mosaic_descriptor.h
@@ -0,0 +1,324 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_MOSAIC_DESCRIPTOR
+#define _UCSI_DVB_MOSAIC_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_mosaic_descriptor structure.
+ */
+struct dvb_mosaic_descriptor {
+ struct descriptor d;
+
+ EBIT4(uint8_t mosaic_entry_point : 1; ,
+ uint8_t number_of_horiz_elementary_cells: 3; ,
+ uint8_t reserved : 1; ,
+ uint8_t number_of_vert_elementary_cells : 3; )
+ /* struct dvb_mosaic_info infos[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the infos field of a dvb_mosaic_descriptor.
+ */
+struct dvb_mosaic_info {
+ EBIT3(uint16_t logical_cell_id : 6; ,
+ uint16_t reserved : 7; ,
+ uint16_t logical_cell_presentation_info : 3; )
+ uint8_t elementary_cell_field_length;
+ /* struct dvb_mosaic_elementary_cell_field fields[] */
+ /* struct dvb_mosaic_info_part2 part2 */
+ /* struct dvb_mosaic_linkage linkage */
+} __ucsi_packed;
+
+/**
+ * An entry in the fields field of a dvb_mosaic_info.
+ */
+struct dvb_mosaic_elementary_cell_field {
+ EBIT2(uint8_t reserved : 2; ,
+ uint8_t elementary_cell_id : 6; )
+} __ucsi_packed;
+
+/**
+ * Part2 of dvb_mosaic_info, following the variable length fields field.
+ */
+struct dvb_mosaic_info_part2 {
+ uint8_t cell_linkage_info;
+} __ucsi_packed;
+
+struct dvb_mosaic_linkage_01 {
+ uint16_t bouquet_id;
+} __ucsi_packed;
+
+struct dvb_mosaic_linkage_02 {
+ uint16_t original_network_id;
+ uint16_t transport_stream_id;
+ uint16_t service_id;
+} __ucsi_packed;
+
+struct dvb_mosaic_linkage_03 {
+ uint16_t original_network_id;
+ uint16_t transport_stream_id;
+ uint16_t service_id;
+} __ucsi_packed;
+
+struct dvb_mosaic_linkage_04 {
+ uint16_t original_network_id;
+ uint16_t transport_stream_id;
+ uint16_t service_id;
+ uint16_t event_id;
+} __ucsi_packed;
+
+/**
+ * Structure describing the linkage field of a dvb_mosaic_info
+ */
+struct dvb_mosaic_linkage {
+ union {
+ struct dvb_mosaic_linkage_01 linkage_01;
+ struct dvb_mosaic_linkage_02 linkage_02;
+ struct dvb_mosaic_linkage_03 linkage_03;
+ struct dvb_mosaic_linkage_04 linkage_04;
+ } u;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_mosaic_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ */
+static inline struct dvb_mosaic_descriptor*
+ dvb_mosaic_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+ struct dvb_mosaic_descriptor * p =
+ (struct dvb_mosaic_descriptor *) d;
+
+ pos += (sizeof(struct dvb_mosaic_descriptor) - 2);
+
+ if (pos > len)
+ return NULL;
+
+ while(pos < len) {
+ struct dvb_mosaic_info *e =
+ (struct dvb_mosaic_info*) (buf+pos);
+ struct dvb_mosaic_info_part2 *e2;
+ struct dvb_mosaic_linkage *linkage;
+
+ if ((pos + sizeof(struct dvb_mosaic_info)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+
+ pos += sizeof(struct dvb_mosaic_info) +
+ e->elementary_cell_field_length;
+
+ if (pos > len)
+ return NULL;
+
+ e2 = (struct dvb_mosaic_info_part2*) (buf+pos);
+
+ pos += sizeof(struct dvb_mosaic_info_part2);
+
+ if (pos > len)
+ return NULL;
+
+ linkage = (struct dvb_mosaic_linkage*) (buf+pos);
+
+ switch(e2->cell_linkage_info) {
+ case 0x01:
+ if ((pos + sizeof(struct dvb_mosaic_linkage_01)) > len)
+ return NULL;
+ bswap16(buf+pos);
+ pos += sizeof(struct dvb_mosaic_linkage_01);
+ break;
+
+ case 0x02:
+ if ((pos + sizeof(struct dvb_mosaic_linkage_02)) > len)
+ return NULL;
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ bswap16(buf+pos+4);
+ pos += sizeof(struct dvb_mosaic_linkage_02);
+ break;
+
+ case 0x03:
+ if ((pos + sizeof(struct dvb_mosaic_linkage_03)) > len)
+ return NULL;
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ bswap16(buf+pos+4);
+ pos += sizeof(struct dvb_mosaic_linkage_03);
+ break;
+
+ case 0x04:
+ if ((pos + sizeof(struct dvb_mosaic_linkage_04)) > len)
+ return NULL;
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ bswap16(buf+pos+4);
+ bswap16(buf+pos+6);
+ pos += sizeof(struct dvb_mosaic_linkage_04);
+ break;
+ }
+ }
+
+ return p;
+}
+
+/**
+ * Iterator over the infos field of a dvb_mosaic_descriptor.
+ *
+ * @param d dvb_mosaic_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_mosaic_info.
+ */
+#define dvb_mosaic_descriptor_infos_for_each(d, pos) \
+ for ((pos) = dvb_mosaic_descriptor_infos_first(d); \
+ (pos); \
+ (pos) = dvb_mosaic_descriptor_infos_next(d, pos))
+
+/**
+ * Iterator over the fields field of a dvb_mosaic_info.
+ *
+ * @param info dvb_mosaic_info pointer.
+ * @param pos Variable containing a pointer to the current dvb_mosaic_elementary_cell_field.
+ */
+#define dvb_mosaic_info_fields_for_each(info, pos) \
+ for ((pos) = dvb_mosaic_info_fields_first(info); \
+ (pos); \
+ (pos) = dvb_mosaic_info_fields_next(info, pos))
+
+/**
+ * Accessor for the second part of the dvb_mosaic_info structure.
+ *
+ * @param entry dvb_mosaic_info pointer.
+ * @return dvb_mosaic_info_part2 pointer.
+ */
+static inline struct dvb_mosaic_info_part2*
+ dvb_mosaic_info_part2(struct dvb_mosaic_info* entry)
+{
+ return (struct dvb_mosaic_info_part2*)
+ ((uint8_t*) entry + sizeof(struct dvb_mosaic_info) +
+ entry->elementary_cell_field_length);
+}
+
+/**
+ * Accessor for the linkage field a dvb_mosaic_info structure.
+ *
+ * @param entry dvb_mosaic_info_part2 pointer.
+ * @return dvb_mosaic_linkage pointer, or NULL on error.
+ */
+static inline struct dvb_mosaic_linkage*
+ dvb_mosaic_linkage(struct dvb_mosaic_info_part2* entry)
+{
+ if ((entry->cell_linkage_info != 0x01) &&
+ (entry->cell_linkage_info != 0x02) &&
+ (entry->cell_linkage_info != 0x03) &&
+ (entry->cell_linkage_info != 0x04))
+ return NULL;
+
+ return (struct dvb_mosaic_linkage*)
+ ((uint8_t*) entry + sizeof(struct dvb_mosaic_info_part2));
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_mosaic_info*
+ dvb_mosaic_descriptor_infos_first(struct dvb_mosaic_descriptor *d)
+{
+ if (d->d.len == 1)
+ return NULL;
+
+ return (struct dvb_mosaic_info *)
+ ((uint8_t*) d + sizeof(struct dvb_mosaic_descriptor));
+}
+
+static inline struct dvb_mosaic_info*
+ dvb_mosaic_descriptor_infos_next(struct dvb_mosaic_descriptor *d,
+ struct dvb_mosaic_info *pos)
+{
+ struct dvb_mosaic_info_part2* part2 = dvb_mosaic_info_part2(pos);
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_mosaic_info) +
+ pos->elementary_cell_field_length +
+ sizeof(struct dvb_mosaic_info_part2);
+
+ if (part2->cell_linkage_info == 0x01)
+ next += sizeof(struct dvb_mosaic_linkage_01);
+ else if (part2->cell_linkage_info == 0x02)
+ next += sizeof(struct dvb_mosaic_linkage_02);
+ else if (part2->cell_linkage_info == 0x03)
+ next += sizeof(struct dvb_mosaic_linkage_03);
+ else if (part2->cell_linkage_info == 0x04)
+ next += sizeof(struct dvb_mosaic_linkage_04);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_mosaic_info *) next;
+}
+
+static inline struct dvb_mosaic_elementary_cell_field*
+ dvb_mosaic_info_fields_first(struct dvb_mosaic_info *d)
+{
+ if (d->elementary_cell_field_length == 0)
+ return NULL;
+
+ return (struct dvb_mosaic_elementary_cell_field*)
+ ((uint8_t*) d + sizeof(struct dvb_mosaic_info));
+}
+
+static inline struct dvb_mosaic_elementary_cell_field*
+ dvb_mosaic_info_fields_next(struct dvb_mosaic_info *d,
+ struct dvb_mosaic_elementary_cell_field* pos)
+{
+ uint8_t *end = (uint8_t*) d + sizeof(struct dvb_mosaic_info) +
+ d->elementary_cell_field_length;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_mosaic_elementary_cell_field);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_mosaic_elementary_cell_field *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_bouquet_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_bouquet_name_descriptor.h
new file mode 100644
index 0000000..0d8deb1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_bouquet_name_descriptor.h
@@ -0,0 +1,145 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_MULTILINGUAL_BOUQUET_NAME_DESCRIPTOR
+#define _UCSI_DVB_MULTILINGUAL_BOUQUET_NAME_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_multilingual_bouquet_name_descriptor structure.
+ */
+struct dvb_multilingual_bouquet_name_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_multilingual_bouquet_name names[]*/
+} __ucsi_packed;
+
+/**
+ * An entry in the names field of a dvb_multilingual_bouquet_name_descriptor.
+ */
+struct dvb_multilingual_bouquet_name {
+ iso639lang_t language_code;
+ uint8_t bouquet_name_length;
+ /* uint8_t name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_multilingual_bouquet_name_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_multilingual_bouquet_name_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_multilingual_bouquet_name_descriptor*
+ dvb_multilingual_bouquet_name_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+
+ while(pos < len) {
+ struct dvb_multilingual_bouquet_name *e =
+ (struct dvb_multilingual_bouquet_name*) (buf+pos);
+
+ pos += sizeof(struct dvb_multilingual_bouquet_name);
+
+ if (pos > len)
+ return NULL;
+
+ pos += e->bouquet_name_length;
+
+ if (pos > len)
+ return NULL;
+ }
+
+ return (struct dvb_multilingual_bouquet_name_descriptor*) d;
+}
+
+/**
+ * Iterator for entries in the names field of a dvb_multilingual_bouquet_name_descriptor.
+ *
+ * @param d dvb_multilingual_bouquet_name_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_multilingual_bouquet_name.
+ */
+#define dvb_multilingual_bouquet_name_descriptor_names_for_each(d, pos) \
+ for ((pos) = dvb_multilingual_bouquet_name_descriptor_names_first(d); \
+ (pos); \
+ (pos) = dvb_multilingual_bouquet_name_descriptor_names_next(d, pos))
+
+/**
+ * Accessor for the name field of a dvb_multilingual_bouquet_name.
+ *
+ * @param e dvb_multilingual_bouquet_name pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_multilingual_bouquet_name_name(struct dvb_multilingual_bouquet_name *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_multilingual_bouquet_name);
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_multilingual_bouquet_name*
+ dvb_multilingual_bouquet_name_descriptor_names_first(struct dvb_multilingual_bouquet_name_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_multilingual_bouquet_name *)
+ ((uint8_t*) d + sizeof(struct dvb_multilingual_bouquet_name_descriptor));
+}
+
+static inline struct dvb_multilingual_bouquet_name*
+ dvb_multilingual_bouquet_name_descriptor_names_next(struct dvb_multilingual_bouquet_name_descriptor *d,
+ struct dvb_multilingual_bouquet_name *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_multilingual_bouquet_name) +
+ pos->bouquet_name_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_multilingual_bouquet_name *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_component_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_component_descriptor.h
new file mode 100644
index 0000000..ab156af
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_component_descriptor.h
@@ -0,0 +1,149 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_MULTILINGUAL_COMPONENT_DESCRIPTOR
+#define _UCSI_DVB_MULTILINGUAL_COMPONENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_multilingual_component_descriptor structure.
+ */
+struct dvb_multilingual_component_descriptor {
+ struct descriptor d;
+
+ uint8_t component_tag;
+ /* struct dvb_multilingual_component components[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the components field of a dvb_multilingual_component_descriptor.
+ */
+struct dvb_multilingual_component {
+ iso639lang_t language_code;
+ uint8_t text_description_length;
+ /* uint8_t text_char[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_multilingual_component_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_multilingual_component_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_multilingual_component_descriptor*
+ dvb_multilingual_component_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = sizeof(struct dvb_multilingual_component_descriptor) - 2;
+ uint32_t len = d->len;
+
+ if (pos > len)
+ return NULL;
+
+ while(pos < len) {
+ struct dvb_multilingual_component *e =
+ (struct dvb_multilingual_component*) (buf+pos);
+
+ pos += sizeof(struct dvb_multilingual_component);
+
+ if (pos > len)
+ return NULL;
+
+ pos += e->text_description_length;
+
+ if (pos > len)
+ return NULL;
+ }
+
+ return (struct dvb_multilingual_component_descriptor*) d;
+}
+
+/**
+ * Iterator for entries in the components field of a dvb_multilingual_component_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_multilingual_component.
+ */
+#define dvb_multilingual_component_descriptor_components_for_each(d, pos) \
+ for ((pos) = dvb_multilingual_component_descriptor_components_first(d); \
+ (pos); \
+ (pos) = dvb_multilingual_component_descriptor_components_next(d, pos))
+
+/**
+ * Accessor for the text_char field in a dvb_multilingual_component.
+ *
+ * @param e dvb_multilingual_component pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_multilingual_component_text_char(struct dvb_multilingual_component *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_multilingual_component);
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_multilingual_component*
+ dvb_multilingual_component_descriptor_components_first(struct dvb_multilingual_component_descriptor *d)
+{
+ if (d->d.len == 1)
+ return NULL;
+
+ return (struct dvb_multilingual_component *)
+ ((uint8_t*) d + sizeof(struct dvb_multilingual_component_descriptor));
+}
+
+static inline struct dvb_multilingual_component*
+ dvb_multilingual_component_descriptor_components_next(struct dvb_multilingual_component_descriptor *d,
+ struct dvb_multilingual_component *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_multilingual_component) +
+ pos->text_description_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_multilingual_component *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_network_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_network_name_descriptor.h
new file mode 100644
index 0000000..1a7b8c4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_network_name_descriptor.h
@@ -0,0 +1,145 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_MULTILINGUAL_NETWORK_NAME_DESCRIPTOR
+#define _UCSI_DVB_MULTILINGUAL_NETWORK_NAME_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_multilingual_network_name_descriptor structure.
+ */
+struct dvb_multilingual_network_name_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_multilingual_network_name names[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the names field of a dvb_multilingual_network_name_descriptor.
+ */
+struct dvb_multilingual_network_name {
+ iso639lang_t language_code;
+ uint8_t network_name_length;
+ /* uint8_t name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_multilingual_network_name_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_multilingual_network_name_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_multilingual_network_name_descriptor*
+ dvb_multilingual_network_name_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+
+ while(pos < len) {
+ struct dvb_multilingual_network_name *e =
+ (struct dvb_multilingual_network_name*) (buf + pos);
+
+ pos += sizeof(struct dvb_multilingual_network_name);
+
+ if (pos > len)
+ return NULL;
+
+ pos += e->network_name_length;
+
+ if (pos > len)
+ return NULL;
+ }
+
+ return (struct dvb_multilingual_network_name_descriptor*) d;
+}
+
+/**
+ * Iterator for entries in the names field of a dvb_multilingual_network_name_descriptor.
+ *
+ * @param d dvb_multilingual_network_name_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_multilingual_network_name.
+ */
+#define dvb_multilingual_network_name_descriptor_names_for_each(d, pos) \
+ for ((pos) = dvb_multilingual_network_name_descriptor_names_first(d); \
+ (pos); \
+ (pos) = dvb_multilingual_network_name_descriptor_names_next(d, pos))
+
+/**
+ * Accessor for the name field of a dvb_multilingual_network_name.
+ *
+ * @param e dvb_multilingual_network_name pointer.
+ * @return Pointer to the name field.
+ */
+static inline uint8_t *
+ dvb_multilingual_network_name_name(struct dvb_multilingual_network_name *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_multilingual_network_name);
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_multilingual_network_name*
+ dvb_multilingual_network_name_descriptor_names_first(struct dvb_multilingual_network_name_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_multilingual_network_name *)
+ ((uint8_t*) d + sizeof(struct dvb_multilingual_network_name_descriptor));
+}
+
+static inline struct dvb_multilingual_network_name*
+ dvb_multilingual_network_name_descriptor_names_next(struct dvb_multilingual_network_name_descriptor *d,
+ struct dvb_multilingual_network_name *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos +
+ sizeof(struct dvb_multilingual_network_name) +
+ pos->network_name_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_multilingual_network_name *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_service_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_service_name_descriptor.h
new file mode 100644
index 0000000..31bb9c3
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/multilingual_service_name_descriptor.h
@@ -0,0 +1,197 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_MULTILINGUAL_SERVICE_NAME_DESCRIPTOR
+#define _UCSI_DVB_MULTILINGUAL_SERVICE_NAME_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_multilingual_service_name_descriptor structure.
+ */
+struct dvb_multilingual_service_name_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_multilingual_service_name names[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the service_names field of a dvb_multilingual_service_name_descriptor.
+ */
+struct dvb_multilingual_service_name {
+ iso639lang_t language_code;
+ uint8_t service_provider_name_length;
+ /* uint8_t service_provider_name[] */
+ /* struct dvb_multilingual_service_name_part2 part2 */
+} __ucsi_packed;
+
+/**
+ * Second part of a dvb_multilingual_service_name following the variable length
+ * service_provider_name.
+ */
+struct dvb_multilingual_service_name_part2 {
+ uint8_t service_name_length;
+ /* uint8_t service_name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_multilingual_service_name_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_multilingual_service_name_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_multilingual_service_name_descriptor*
+ dvb_multilingual_service_name_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+
+ while(pos < len) {
+ struct dvb_multilingual_service_name *e =
+ (struct dvb_multilingual_service_name*) (buf+pos);
+ struct dvb_multilingual_service_name_part2 *e2;
+
+ pos += sizeof(struct dvb_multilingual_service_name);
+
+ if (pos > len)
+ return NULL;
+
+ pos += e->service_provider_name_length;
+
+ if (pos > len)
+ return NULL;
+
+ e2 = (struct dvb_multilingual_service_name_part2*) (buf+pos);
+
+ pos += sizeof(struct dvb_multilingual_service_name_part2);
+
+ if (pos > len)
+ return NULL;
+
+ pos += e2->service_name_length;
+
+ if (pos > len)
+ return NULL;
+ }
+
+ return (struct dvb_multilingual_service_name_descriptor*) d;
+}
+
+/**
+ * Iterator for entries in the service_name field of a dvb_multilingual_service_name_descriptor.
+ *
+ * @param d dvb_multilingual_service_name_descriptor pointer,
+ * @param pos Variable containing pointer to the current dvb_multilingual_service_name.
+ */
+#define dvb_multilingual_service_name_descriptor_names_for_each(d, pos) \
+ for ((pos) = dvb_multilingual_service_name_descriptor_names_first(d); \
+ (pos); \
+ (pos) = dvb_multilingual_service_name_descriptor_names_next(d, pos))
+
+/**
+ * Accessor for the service_provider_name field of a dvb_multilingual_service_name.
+ *
+ * @param e dvb_multilingual_service_name pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_multilingual_service_name_service_provider_name(struct dvb_multilingual_service_name *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_multilingual_service_name);
+}
+
+/**
+ * Accessor for the dvb_multilingual_service_name_part2 - second part of a
+ * dvb_multilingual_service_name following the service_name field.
+ *
+ * @param e dvb_multilingual_service_name Pointer.
+ * @return dvb_multilingual_service_name_part2 pointer.
+ */
+static inline struct dvb_multilingual_service_name_part2 *
+ dvb_multilingual_service_name_part2(struct dvb_multilingual_service_name *e)
+{
+ return (struct dvb_multilingual_service_name_part2 *)
+ ((uint8_t *) e + sizeof(struct dvb_multilingual_service_name) +
+ e->service_provider_name_length);
+}
+
+/**
+ * Accessor for the service_name field of a dvb_multilingual_service_name_part2.
+ *
+ * @param e dvb_multilingual_service_name_part2 pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_multilingual_service_name_service_name(struct dvb_multilingual_service_name_part2 *e)
+{
+ return (uint8_t *) e + sizeof(struct dvb_multilingual_service_name_part2);
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_multilingual_service_name*
+ dvb_multilingual_service_name_descriptor_names_first(struct dvb_multilingual_service_name_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_multilingual_service_name *)
+ ((uint8_t*) d + sizeof(struct dvb_multilingual_service_name_descriptor));
+}
+
+static inline struct dvb_multilingual_service_name*
+ dvb_multilingual_service_name_descriptor_names_next(struct dvb_multilingual_service_name_descriptor *d,
+ struct dvb_multilingual_service_name *pos)
+{
+ struct dvb_multilingual_service_name_part2 * part2 =
+ dvb_multilingual_service_name_part2(pos);
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) part2+
+ sizeof(struct dvb_multilingual_service_name_part2) +
+ part2->service_name_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_multilingual_service_name *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/network_name_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/network_name_descriptor.h
new file mode 100644
index 0000000..0754597
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/network_name_descriptor.h
@@ -0,0 +1,82 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_NETWORK_NAME_DESCRIPTOR
+#define _UCSI_DVB_NETWORK_NAME_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_network_name_descriptor structure.
+ */
+struct dvb_network_name_descriptor {
+ struct descriptor d;
+
+ /* char name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_network_name_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_network_name_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_network_name_descriptor*
+ dvb_network_name_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_network_name_descriptor*) d;
+}
+
+/**
+ * Accessor for the name field in a dvb_network_name_descriptor.
+ *
+ * @param d dvb_network_name_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_network_name_descriptor_name(struct dvb_network_name_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_network_name_descriptor);
+}
+
+/**
+ * Calculate the length of the name field in a dvb_network_name_descriptor.
+ *
+ * @param d dvb_network_name_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_network_name_descriptor_name_length(struct dvb_network_name_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c
new file mode 100644
index 0000000..d931926
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.c
@@ -0,0 +1,79 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/nit_section.h>
+
+struct dvb_nit_section *dvb_nit_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *) ext;
+ struct dvb_nit_section * ret = (struct dvb_nit_section *) ext;
+ unsigned int pos = sizeof(struct section_ext);
+ unsigned int len = section_ext_length(ext);
+
+ if (len < sizeof(struct dvb_nit_section))
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += 2;
+
+ if ((pos + ret->network_descriptors_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, ret->network_descriptors_length))
+ return NULL;
+
+ pos += ret->network_descriptors_length;
+
+ if ((pos + sizeof(struct dvb_nit_section_part2)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += 2;
+
+ while (pos < len) {
+ struct dvb_nit_transport *transport =
+ (struct dvb_nit_transport *)(buf + pos);
+
+ if ((pos + sizeof(struct dvb_nit_transport)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ bswap16(buf + pos + 2);
+ bswap16(buf + pos + 4);
+
+ pos += sizeof(struct dvb_nit_transport);
+
+ if ((pos + transport->transport_descriptors_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos,
+ transport->transport_descriptors_length))
+ return NULL;
+
+ pos += transport->transport_descriptors_length;
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return ret;
+}
+
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.h
new file mode 100644
index 0000000..77ab1a0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/nit_section.h
@@ -0,0 +1,207 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_NIT_SECTION_H
+#define _UCSI_DVB_NIT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_nit_section structure.
+ */
+struct dvb_nit_section {
+ struct section_ext head;
+
+ EBIT2(uint16_t reserved_1 : 4; ,
+ uint16_t network_descriptors_length :12; );
+ /* struct descriptor descriptors[] */
+ /* struct dvb_nit_section_part2 part2 */
+};
+
+/**
+ * Second part of a dvb_nit_section, following the variable length descriptors field.
+ */
+struct dvb_nit_section_part2 {
+ EBIT2(uint16_t reserved_2 : 4; ,
+ uint16_t transport_stream_loop_length :12; );
+ /* struct dvb_nit_transport transports[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the transports field of a dvb_nit_section_part2
+ */
+struct dvb_nit_transport {
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ EBIT2(uint16_t reserved : 4; ,
+ uint16_t transport_descriptors_length :12; );
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_nit_section.
+ *
+ * @param section Generic section_ext pointer.
+ * @return dvb_nit_section pointer, or NULL on error.
+ */
+struct dvb_nit_section * dvb_nit_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the network_id field of a NIT.
+ *
+ * @param nit NIT pointer.
+ * @return The network_id.
+ */
+static inline uint16_t dvb_nit_section_network_id(struct dvb_nit_section *nit)
+{
+ return nit->head.table_id_ext;
+}
+
+/**
+ * Iterator over the descriptors field in a dvb_nit_section.
+ *
+ * @param nit dvb_nit_section pointer.
+ * @param pos Variable containing a pointer to the current descriptor.
+ */
+#define dvb_nit_section_descriptors_for_each(nit, pos) \
+ for ((pos) = dvb_nit_section_descriptors_first(nit); \
+ (pos); \
+ (pos) = dvb_nit_section_descriptors_next(nit, pos))
+
+/**
+ * Accessor for a pointer to the dvb_nit_section_part2 structure.
+ *
+ * @param nit dvb_nit_section pointer.
+ * @return dvb_nit_section_part2 pointer.
+ */
+static inline struct dvb_nit_section_part2 *dvb_nit_section_part2(struct dvb_nit_section * nit)
+{
+ return (struct dvb_nit_section_part2 *)
+ ((uint8_t*) nit + sizeof(struct dvb_nit_section) +
+ nit->network_descriptors_length);
+}
+
+/**
+ * Iterator over the transports field in a dvb_nit_section_part2.
+ *
+ * @param nit dvb_nit_section pointer.
+ * @param part2 dvb_nit_section_part2 pointer.
+ * @param pos Pointer to the current dvb_nit_transport.
+ */
+#define dvb_nit_section_transports_for_each(nit, part2, pos) \
+ for ((pos) = dvb_nit_section_transports_first(part2); \
+ (pos); \
+ (pos) = dvb_nit_section_transports_next(part2, pos))
+
+/**
+ * Iterator over the descriptors field in a dvb_nit_transport.
+ *
+ * @param transport dvb_nit_transport pointer.
+ * @param pos Pointer to the current descriptor.
+ */
+#define dvb_nit_transport_descriptors_for_each(transport, pos) \
+ for ((pos) = dvb_nit_transport_descriptors_first(transport); \
+ (pos); \
+ (pos) = dvb_nit_transport_descriptors_next(transport, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ dvb_nit_section_descriptors_first(struct dvb_nit_section * nit)
+{
+ if (nit->network_descriptors_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) nit + sizeof(struct dvb_nit_section));
+}
+
+static inline struct descriptor *
+ dvb_nit_section_descriptors_next(struct dvb_nit_section * nit,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) nit + sizeof(struct dvb_nit_section),
+ nit->network_descriptors_length,
+ pos);
+}
+
+static inline struct dvb_nit_transport *
+ dvb_nit_section_transports_first(struct dvb_nit_section_part2 *part2)
+{
+ if (part2->transport_stream_loop_length == 0)
+ return NULL;
+
+ return (struct dvb_nit_transport *)
+ ((uint8_t *)part2 + sizeof(struct dvb_nit_section_part2));
+}
+
+static inline struct dvb_nit_transport *
+ dvb_nit_section_transports_next(struct dvb_nit_section_part2 *part2,
+ struct dvb_nit_transport *pos)
+{
+ uint8_t *end = (uint8_t*) part2 + sizeof(struct dvb_nit_section_part2) +
+ part2->transport_stream_loop_length;
+ uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_nit_transport) +
+ pos->transport_descriptors_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_nit_transport *) next;
+}
+
+static inline struct descriptor *
+ dvb_nit_transport_descriptors_first(struct dvb_nit_transport *t)
+{
+ if (t->transport_descriptors_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t*) t + sizeof(struct dvb_nit_transport));
+}
+
+static inline struct descriptor *
+ dvb_nit_transport_descriptors_next(struct dvb_nit_transport *t,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) t + sizeof(struct dvb_nit_transport),
+ t->transport_descriptors_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/nvod_reference_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/nvod_reference_descriptor.h
new file mode 100644
index 0000000..6180514
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/nvod_reference_descriptor.h
@@ -0,0 +1,125 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_NVOD_REFERENCE_DESCRIPTOR
+#define _UCSI_DVB_NVOD_REFERENCE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_nvod_reference_descriptor structure.
+ */
+struct dvb_nvod_reference_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_nvod_reference references[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the references field of a dvb_nvod_reference_descriptor.
+ */
+struct dvb_nvod_reference {
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ uint16_t service_id;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_nvod_reference_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure pointer.
+ * @return dvb_nvod_reference_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_nvod_reference_descriptor*
+ dvb_nvod_reference_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+
+ if (len % sizeof(struct dvb_nvod_reference))
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ bswap16(buf+pos+4);
+ pos += sizeof(struct dvb_nvod_reference);
+ }
+
+ return (struct dvb_nvod_reference_descriptor*) d;
+}
+
+/**
+ * Iterator over the references field in a dvb_nvod_reference_descriptor.
+ *
+ * @param d dvb_nvod_reference_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_nvod_reference.
+ */
+#define dvb_nvod_reference_descriptor_references_for_each(d, pos) \
+ for ((pos) = dvb_nvod_reference_descriptor_references_first(d); \
+ (pos); \
+ (pos) = dvb_nvod_reference_descriptor_references_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_nvod_reference*
+ dvb_nvod_reference_descriptor_references_first(struct dvb_nvod_reference_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_nvod_reference *)
+ ((uint8_t*) d + sizeof(struct dvb_nvod_reference_descriptor));
+}
+
+static inline struct dvb_nvod_reference*
+ dvb_nvod_reference_descriptor_references_next(struct dvb_nvod_reference_descriptor *d,
+ struct dvb_nvod_reference *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_nvod_reference);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_nvod_reference *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h
new file mode 100644
index 0000000..9acbcb0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/parental_rating_descriptor.h
@@ -0,0 +1,135 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_PARENTAL_RATING_DESCRIPTOR
+#define _UCSI_DVB_PARENTAL_RATING_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * Defined values for the rating field.
+ */
+enum {
+ DVB_PARENTAL_RATING_MIN_3YEARS = 0x01,
+ DVB_PARENTAL_RATING_MIN_4YEARS = 0x02,
+ DVB_PARENTAL_RATING_MIN_5YEARS = 0x03,
+ DVB_PARENTAL_RATING_MIN_6YEARS = 0x04,
+ DVB_PARENTAL_RATING_MIN_7YEARS = 0x05,
+ DVB_PARENTAL_RATING_MIN_8YEARS = 0x06,
+ DVB_PARENTAL_RATING_MIN_9YEARS = 0x07,
+ DVB_PARENTAL_RATING_MIN_10YEARS = 0x08,
+ DVB_PARENTAL_RATING_MIN_11YEARS = 0x09,
+ DVB_PARENTAL_RATING_MIN_12YEARS = 0x0a,
+ DVB_PARENTAL_RATING_MIN_13YEARS = 0x0b,
+ DVB_PARENTAL_RATING_MIN_14YEARS = 0x0c,
+ DVB_PARENTAL_RATING_MIN_15YEARS = 0x0d,
+ DVB_PARENTAL_RATING_MIN_16YEARS = 0x0e,
+ DVB_PARENTAL_RATING_MIN_17YEARS = 0x0f
+};
+
+/**
+ * dvb_parental_rating_descriptor structure.
+ */
+struct dvb_parental_rating_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_parental_rating ratings[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the ratings field of a dvb_parental_rating_descriptor.
+ */
+struct dvb_parental_rating {
+ iso639country_t country_code;
+ uint8_t rating;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_parental_rating_descriptor.
+ *
+ * @param d Generic descriptor structure pointer.
+ * @return dvb_parental_rating_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_parental_rating_descriptor*
+ dvb_parental_rating_descriptor_codec(struct descriptor* d)
+{
+ if (d->len % sizeof(struct dvb_parental_rating))
+ return NULL;
+
+ return (struct dvb_parental_rating_descriptor*) d;
+}
+
+/**
+ * Iterator for entries in the ratings field of a dvb_parental_rating_descriptor.
+ *
+ * @param d dvb_parental_rating_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_parental_rating.
+ */
+#define dvb_parental_rating_descriptor_ratings_for_each(d, pos) \
+ for ((pos) = dvb_parental_rating_descriptor_ratings_first(d); \
+ (pos); \
+ (pos) = dvb_parental_rating_descriptor_ratings_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_parental_rating*
+ dvb_parental_rating_descriptor_ratings_first(struct dvb_parental_rating_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_parental_rating *)
+ ((uint8_t*) d + sizeof(struct dvb_parental_rating_descriptor));
+}
+
+static inline struct dvb_parental_rating*
+ dvb_parental_rating_descriptor_ratings_next(struct dvb_parental_rating_descriptor *d,
+ struct dvb_parental_rating *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_parental_rating);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_parental_rating *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h
new file mode 100644
index 0000000..c8ba441
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/partial_transport_stream_descriptor.h
@@ -0,0 +1,68 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_PARTIAL_TRANSPORT_STREAM_DESCRIPTOR
+#define _UCSI_DVB_PARTIAL_TRANSPORT_STREAM_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_partial_transport_stream_descriptor structure.
+ */
+struct dvb_partial_transport_stream_descriptor {
+ struct descriptor d;
+
+ EBIT6(uint64_t reserved : 2; ,
+ uint64_t peak_rate :22; ,
+ uint64_t reserved_2 : 2; ,
+ uint64_t minimum_overall_smoothing_rate :22; ,
+ uint64_t reserved_3 : 2; ,
+ uint64_t maximum_overall_smoothing_rate :14; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_partial_transport_stream_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_partial_transport_stream_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_partial_transport_stream_descriptor*
+ dvb_partial_transport_stream_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_partial_transport_stream_descriptor) - 2))
+ return NULL;
+
+ bswap64((uint8_t*) d + 2);
+
+ return (struct dvb_partial_transport_stream_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h
new file mode 100644
index 0000000..49cc187
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/pdc_descriptor.h
@@ -0,0 +1,64 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_PDC_DESCRIPTOR
+#define _UCSI_DVB_PDC_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_pdc_descriptor structure.
+ */
+struct dvb_pdc_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint32_t reserved : 4; ,
+ uint32_t programme_id_label :20; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_pdc_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ * @return dvb_pdc_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_pdc_descriptor*
+ dvb_pdc_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_pdc_descriptor) - 2))
+ return NULL;
+
+ bswap24((uint8_t*) d + 2);
+
+ return (struct dvb_pdc_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/private_data_specifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/private_data_specifier_descriptor.h
new file mode 100644
index 0000000..f4cc03c
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/private_data_specifier_descriptor.h
@@ -0,0 +1,63 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_PRIVATE_DATA_SPECIFIER_DESCRIPTOR
+#define _UCSI_DVB_PRIVATE_DATA_SPECIFIER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_private_data_specifier_descriptor structure.
+ */
+struct dvb_private_data_specifier_descriptor {
+ struct descriptor d;
+
+ uint32_t private_data_specifier;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_private_data_specifier_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_private_data_specifier_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_private_data_specifier_descriptor*
+ dvb_private_data_specifier_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_private_data_specifier_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+
+ return (struct dvb_private_data_specifier_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/related_content_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/related_content_descriptor.h
new file mode 100644
index 0000000..fd6a358
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/related_content_descriptor.h
@@ -0,0 +1,56 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_RELATED_CONTENT_DESCRIPTOR
+#define _UCSI_DVB_RELATED_CONTENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_related_content_descriptor structure.
+ */
+struct dvb_related_content_descriptor {
+ struct descriptor d;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_related_content_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_related_content_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_related_content_descriptor*
+ dvb_related_content_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_related_content_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h
new file mode 100644
index 0000000..b67b0d9
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_dvb_stream_descriptor.h
@@ -0,0 +1,110 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_RNT_RAR_OVER_DVB_STREAM_DESCRIPTOR
+#define _UCSI_DVB_RNT_RAR_OVER_DVB_STREAM_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_rnt_rar_over_dvb_stream_descriptor structure.
+ */
+struct dvb_rnt_rar_over_dvb_stream_descriptor {
+ struct descriptor d;
+
+ dvbdate_t first_valid_date;
+ dvbdate_t last_valid_date;
+ EBIT3(uint8_t weighting : 6; ,
+ uint8_t complete_flag : 1; ,
+ uint8_t scheduled_flag : 1; )
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ uint16_t service_id;
+ uint8_t component_tag;
+ /* struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info scheduled_info */
+} __ucsi_packed;
+
+/**
+ * The scheduled_info field of a dvb_rnt_rar_over_dvb_stream_descriptor (only appears
+ * if scheduled_flag = 1).
+ */
+struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info {
+ dvbdate_t download_start_time;
+ uint8_t download_period_duration;
+ uint8_t download_cycle_time;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_rnt_rar_over_dvb_stream_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_rnt_rar_over_dvb_stream_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_rnt_rar_over_dvb_stream_descriptor*
+ dvb_rnt_rar_over_dvb_stream_descriptor_codec(struct descriptor* d)
+{
+ uint8_t *buf = (uint8_t*) d;
+ uint32_t len = d->len + 2;
+ struct dvb_rnt_rar_over_dvb_stream_descriptor *ret =
+ (struct dvb_rnt_rar_over_dvb_stream_descriptor *) buf;
+
+ if (len < sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor))
+ return NULL;
+
+ bswap16(buf + 13);
+ bswap16(buf + 15);
+ bswap16(buf + 17);
+
+ if (ret->scheduled_flag == 1) {
+ if (len < (sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor)+
+ sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info)))
+ return NULL;
+ }
+
+ return ret;
+}
+
+/**
+ * Accessor for the scheduled_info field of a dvb_rnt_rar_over_dvb_stream_descriptor.
+ *
+ * @param d dvb_rnt_rar_over_dvb_stream_descriptor pointer.
+ * @return Pointer, or NULL on error.
+ */
+static inline struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info*
+ dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info(struct dvb_rnt_rar_over_dvb_stream_descriptor *d)
+{
+ if (d->scheduled_flag != 1)
+ return NULL;
+ return (struct dvb_rnt_rar_over_dvb_stream_descriptor_scheduled_info*)
+ ((uint8_t*) d + sizeof(struct dvb_rnt_rar_over_dvb_stream_descriptor));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h
new file mode 100644
index 0000000..cc0ed58
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rar_over_ip_descriptor.h
@@ -0,0 +1,87 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_RNT_RAR_OVER_IP_DESCRIPTOR
+#define _UCSI_DVB_RNT_RAR_OVER_IP_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_rnt_rar_over_ip_descriptor structure.
+ */
+struct dvb_rnt_rar_over_ip_descriptor {
+ struct descriptor d;
+
+ dvbdate_t first_valid_date;
+ dvbdate_t last_valid_date;
+ EBIT3(uint8_t weighting : 6; ,
+ uint8_t complete_flag : 1; ,
+ uint8_t reserved : 1; )
+ uint8_t url_length;
+ /* uint8_t url[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_rnt_rar_over_ip_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_rnt_rar_over_ip_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_rnt_rar_over_ip_descriptor*
+ dvb_rnt_rar_over_ip_descriptor_codec(struct descriptor* d)
+{
+ uint8_t *buf = (uint8_t*) d;
+ uint32_t len = d->len + 2;
+ struct dvb_rnt_rar_over_ip_descriptor *ret =
+ (struct dvb_rnt_rar_over_ip_descriptor *) buf;
+
+ if (len < sizeof(struct dvb_rnt_rar_over_ip_descriptor))
+ return NULL;
+ if (len < (sizeof(struct dvb_rnt_rar_over_ip_descriptor) + buf[13]))
+ return NULL;
+
+ return ret;
+}
+
+/**
+ * Accessor for the url field of a dvb_rnt_rar_over_ip_descriptor.
+ *
+ * @param d dvb_rnt_rar_over_ip_descriptor pointer.
+ * @return Pointer.
+ */
+static inline uint8_t*
+ dvb_rnt_rar_over_ip_descriptor_url(struct dvb_rnt_rar_over_ip_descriptor *d)
+{
+ return (uint8_t*)
+ ((uint8_t*) d + sizeof(struct dvb_rnt_rar_over_ip_descriptor));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rnt_scan_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rnt_scan_descriptor.h
new file mode 100644
index 0000000..cb74f75
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rnt_rnt_scan_descriptor.h
@@ -0,0 +1,125 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_RNT_RNT_SCAN_DESCRIPTOR
+#define _UCSI_DVB_RNT_RNT_SCAN_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_rnt_rnt_scan_descriptor structure.
+ */
+struct dvb_rnt_rnt_scan_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_rnt_rnt_scan_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the entries field of a dvb_rnt_rnt_scan_descriptor.
+ */
+struct dvb_rnt_rnt_scan_entry {
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ uint8_t scan_weighting;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_rnt_rnt_scan_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return dvb_rnt_rnt_scan_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_rnt_rnt_scan_descriptor*
+ dvb_rnt_rnt_scan_descriptor_codec(struct descriptor* d)
+{
+ uint8_t *buf = (uint8_t*) d;
+ uint32_t len = d->len +2;
+ uint32_t pos = 2;
+
+ if ((len-2) % sizeof(struct dvb_rnt_rnt_scan_entry))
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ pos += sizeof(struct dvb_rnt_rnt_scan_entry);
+ }
+
+ return (struct dvb_rnt_rnt_scan_descriptor*) d;
+}
+
+/**
+ * Iterator for entries field of a dvb_rnt_rnt_scan_descriptor.
+ *
+ * @param d dvb_rnt_rnt_scan_descriptor pointer.
+ * @param pos Variable holding a pointer to the current dvb_rnt_rnt_scan_entry.
+ */
+#define dvb_rnt_rnt_scan_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_rnt_rnt_scan_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_rnt_rnt_scan_descriptor_entries_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_rnt_rnt_scan_entry*
+ dvb_rnt_rnt_scan_descriptor_entries_first(struct dvb_rnt_rnt_scan_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_rnt_rnt_scan_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_rnt_rnt_scan_descriptor));
+}
+
+static inline struct dvb_rnt_rnt_scan_entry*
+ dvb_rnt_rnt_scan_descriptor_entries_next(struct dvb_rnt_rnt_scan_descriptor *d,
+ struct dvb_rnt_rnt_scan_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_rnt_rnt_scan_entry);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_rnt_rnt_scan_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c
new file mode 100644
index 0000000..67fa0d3
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.c
@@ -0,0 +1,47 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/rst_section.h>
+
+struct dvb_rst_section * dvb_rst_section_codec(struct section *section)
+{
+ uint8_t * buf = (uint8_t *) section;
+ int pos = sizeof(struct section);
+ int len = section_length(section);
+ struct dvb_rst_section * ret = (struct dvb_rst_section *) section;
+
+ while (pos < len) {
+ if ((pos + sizeof(struct dvb_rst_status)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ bswap16(buf + pos + 2);
+ bswap16(buf + pos + 4);
+ bswap16(buf + pos + 6);
+
+ pos += sizeof(struct dvb_rst_status);
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h
new file mode 100644
index 0000000..b4269b8
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/rst_section.h
@@ -0,0 +1,111 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_RST_SECTION_H
+#define _UCSI_DVB_RST_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_rst_section structure.
+ */
+struct dvb_rst_section {
+ struct section head;
+
+ /* struct dvb_rst_status statuses[] */
+};
+
+/**
+ * An entry in the statuses field of a dvb_rst_section structure.
+ */
+struct dvb_rst_status {
+ uint16_t transport_stream_id;
+ uint16_t original_network_id;
+ uint16_t service_id;
+ uint16_t event_id;
+ EBIT2(uint8_t reserved : 5; ,
+ uint8_t running_status : 3; );
+};
+
+/**
+ * Process a dvb_rst_section.
+ *
+ * @param section Pointer to a generic section strcuture.
+ * @return dvb_rst_section pointer, or NULL on error.
+ */
+struct dvb_rst_section *dvb_rst_section_codec(struct section *section);
+
+/**
+ * Iterator for entries in the statuses field of a dvb_rst_section.
+ *
+ * @param rst dvb_rst_section pointer.
+ * @param pos Variable containing a pointer to the current dvb_rst_status.
+ */
+#define dvb_rst_section_statuses_for_each(rst, pos) \
+ for ((pos) = dvb_rst_section_statuses_first(rst); \
+ (pos); \
+ (pos) = dvb_rst_section_statuses_next(rst, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_rst_status *
+ dvb_rst_section_statuses_first(struct dvb_rst_section *rst)
+{
+ int pos = sizeof(struct dvb_rst_section);
+
+ if (pos >= section_length(&rst->head))
+ return NULL;
+
+ return (struct dvb_rst_status*) ((uint8_t *) rst + pos);
+}
+
+static inline struct dvb_rst_status *
+ dvb_rst_section_statuses_next(struct dvb_rst_section * rst,
+ struct dvb_rst_status * pos)
+{
+ uint8_t *end = (uint8_t*) rst + section_length(&rst->head);
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_rst_status);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_rst_status *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h
new file mode 100644
index 0000000..66c9288
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/s2_satellite_delivery_descriptor.h
@@ -0,0 +1,116 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_S2_SATELLITE_DELIVERY_DESCRIPTOR
+#define _UCSI_DVB_S2_SATELLITE_DELIVERY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_s2_satellite_delivery_descriptor structure.
+ */
+struct dvb_s2_satellite_delivery_descriptor {
+ struct descriptor d;
+
+ EBIT4(uint8_t scrambling_sequence_selector : 1; ,
+ uint8_t multiple_input_stream : 1; ,
+ uint8_t backwards_compatability : 1; ,
+ uint8_t reserved : 5; )
+ /* uint32_t scrambling_sequence_index if scrambling_sequence_selector = 1 */
+ /* uint8_t input_stream_id if multiple_input_stream = 1 */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_s2_satellite_delivery_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ * @return dvb_s2_satellite_delivery_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_s2_satellite_delivery_descriptor*
+ dvb_s2_satellite_delivery_descriptor_codec(struct descriptor* d)
+{
+ struct dvb_s2_satellite_delivery_descriptor *s2 =
+ (struct dvb_s2_satellite_delivery_descriptor*) d;
+
+ if (d->len < (sizeof(struct dvb_s2_satellite_delivery_descriptor) - 2))
+ return NULL;
+
+ int len = sizeof(struct dvb_s2_satellite_delivery_descriptor);
+ if (s2->scrambling_sequence_selector) {
+ len += 3;
+ }
+ if (s2->multiple_input_stream) {
+ len += 1;
+ }
+
+ if (d->len < len)
+ return NULL;
+
+ return s2;
+}
+
+/**
+ * Accessor for the scrambling_sequence_index field of a dvb_s2_satellite_delivery_descriptor.
+ *
+ * @param s2 dvb_s2_satellite_delivery_descriptor pointer.
+ * @return The scrambling_sequence_index.
+ */
+static inline uint32_t dvb_s2_satellite_delivery_descriptor_scrambling_sequence_index(struct dvb_s2_satellite_delivery_descriptor *s2)
+{
+ uint8_t *tmp = (uint8_t*) s2;
+
+ if (s2->scrambling_sequence_selector) {
+ return ((tmp[4] & 0x03) << 16) | (tmp[5] << 8) | tmp[6];
+ }
+ return 0;
+}
+
+/**
+ * Accessor for the input_stream_id field of a dvb_s2_satellite_delivery_descriptor.
+ *
+ * @param s2 dvb_s2_satellite_delivery_descriptor pointer.
+ * @return The input_stream_id.
+ */
+static inline uint8_t dvb_s2_satellite_delivery_descriptor_input_stream_id(struct dvb_s2_satellite_delivery_descriptor *s2)
+{
+ uint8_t *tmp = (uint8_t*) s2;
+
+ if (!s2->multiple_input_stream)
+ return 0;
+
+ int off = 3;
+ if (s2->scrambling_sequence_selector) {
+ off += 3;
+ }
+ return tmp[off];
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h
new file mode 100644
index 0000000..23be76e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/satellite_delivery_descriptor.h
@@ -0,0 +1,73 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SATELLITE_DELIVERY_DESCRIPTOR
+#define _UCSI_DVB_SATELLITE_DELIVERY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_satellite_delivery_descriptor structure.
+ */
+struct dvb_satellite_delivery_descriptor {
+ struct descriptor d;
+
+ uint32_t frequency; // BCD, units 10kHz
+ uint16_t orbital_position;
+ EBIT5(uint8_t west_east_flag : 1; ,
+ uint8_t polarization : 2; ,
+ uint8_t roll_off : 2; ,
+ uint8_t modulation_system : 1; ,
+ uint8_t modulation_type : 2; )
+ EBIT2(uint32_t symbol_rate : 28; , // BCD, units 100Hz
+ uint32_t fec_inner : 4; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_satellite_delivery_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ * @return dvb_satellite_delivery_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_satellite_delivery_descriptor*
+ dvb_satellite_delivery_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct dvb_satellite_delivery_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+ bswap16((uint8_t*) d + 6);
+ bswap32((uint8_t*) d + 9);
+
+ return (struct dvb_satellite_delivery_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/scrambling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/scrambling_descriptor.h
new file mode 100644
index 0000000..4669bc8
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/scrambling_descriptor.h
@@ -0,0 +1,61 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SCRAMBLING_DESCRIPTOR
+#define _UCSI_DVB_SCRAMBLING_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_scrambling_descriptor structure.
+ */
+struct dvb_scrambling_descriptor {
+ struct descriptor d;
+
+ uint8_t scrambling_mode;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_scrambling_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to dvb_scrambling_descriptor, or NULL on error.
+ */
+static inline struct dvb_scrambling_descriptor*
+ dvb_scrambling_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_scrambling_descriptor) - 2))
+ return NULL;
+
+ return (struct dvb_scrambling_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c
new file mode 100644
index 0000000..bdc8ce1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.c
@@ -0,0 +1,60 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/sdt_section.h>
+
+struct dvb_sdt_section * dvb_sdt_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *) ext;
+ unsigned int pos = sizeof(struct section_ext);
+ unsigned int len = section_ext_length(ext);
+
+ if (len < sizeof(struct dvb_sdt_section))
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += 3;
+
+ while (pos < len) {
+ struct dvb_sdt_service * service =
+ (struct dvb_sdt_service *)(buf + pos);
+
+ if ((pos + sizeof(struct dvb_sdt_service)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ bswap16(buf + pos + 3);
+ pos += sizeof(struct dvb_sdt_service);
+
+ if ((pos + service->descriptors_loop_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, service->descriptors_loop_length))
+ return NULL;
+
+ pos += service->descriptors_loop_length;
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return (struct dvb_sdt_section *) ext;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h
new file mode 100644
index 0000000..0130fe7
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sdt_section.h
@@ -0,0 +1,157 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SDT_SECTION_H
+#define _UCSI_DVB_SDT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_sdt_section structure.
+ */
+struct dvb_sdt_section {
+ struct section_ext head;
+
+ uint16_t original_network_id;
+ uint8_t reserved;
+ /* struct dvb_sdt_service services[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the services field of a dvb_sdt_section.
+ */
+struct dvb_sdt_service {
+ uint16_t service_id;
+ EBIT3(uint8_t reserved : 6; ,
+ uint8_t eit_schedule_flag : 1; ,
+ uint8_t eit_present_following_flag : 1; );
+ EBIT3(uint16_t running_status : 3; ,
+ uint16_t free_ca_mode : 1; ,
+ uint16_t descriptors_loop_length :12; );
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_sdt_section.
+ *
+ * @param section Pointer to a generic section_ext structure.
+ * @return dvb_sdt_section pointer, or NULL on error.
+ */
+struct dvb_sdt_section * dvb_sdt_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the transport_stream_id field of an SDT.
+ *
+ * @param sdt SDT pointer.
+ * @return The transport_stream_id.
+ */
+static inline uint16_t dvb_sdt_section_transport_stream_id(struct dvb_sdt_section *sdt)
+{
+ return sdt->head.table_id_ext;
+}
+
+/**
+ * Iterator for the services field in a dvb_sdt_section.
+ *
+ * @param sdt dvb_sdt_section pointer.
+ * @param pos Variable containing a pointer to the current dvb_sdt_service.
+ */
+#define dvb_sdt_section_services_for_each(sdt, pos) \
+ for ((pos) = dvb_sdt_section_services_first(sdt); \
+ (pos); \
+ (pos) = dvb_sdt_section_services_next(sdt, pos))
+
+/**
+ * Iterator for the descriptors field in a dvb_sdt_service.
+ *
+ * @param service dvb_sdt_service pointer.
+ * @param pos Variable containing a pointer to the current descriptor.
+ */
+#define dvb_sdt_service_descriptors_for_each(service, pos) \
+ for ((pos) = dvb_sdt_service_descriptors_first(service); \
+ (pos); \
+ (pos) = dvb_sdt_service_descriptors_next(service, pos))
+
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_sdt_service *
+ dvb_sdt_section_services_first(struct dvb_sdt_section * sdt)
+{
+ int pos = sizeof(struct dvb_sdt_section);
+
+ if (pos >= section_ext_length(&sdt->head))
+ return NULL;
+
+ return (struct dvb_sdt_service*) ((uint8_t *) sdt + pos);
+}
+
+static inline struct dvb_sdt_service *
+ dvb_sdt_section_services_next(struct dvb_sdt_section * sdt,
+ struct dvb_sdt_service * pos)
+{
+ uint8_t *end = (uint8_t*) sdt + section_ext_length(&sdt->head);
+ uint8_t *next = (uint8_t*) pos + sizeof(struct dvb_sdt_service) +
+ pos->descriptors_loop_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_sdt_service *) next;
+}
+
+static inline struct descriptor *
+ dvb_sdt_service_descriptors_first(struct dvb_sdt_service *svc)
+{
+ if (svc->descriptors_loop_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t*) svc + sizeof(struct dvb_sdt_service));
+}
+
+static inline struct descriptor *
+ dvb_sdt_service_descriptors_next(struct dvb_sdt_service *svc,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) svc + sizeof(struct dvb_sdt_service),
+ svc->descriptors_loop_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h
new file mode 100644
index 0000000..8488d71
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/section.h
@@ -0,0 +1,107 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SECTION_H
+#define _UCSI_DVB_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/dvb/bat_section.h>
+#include <libucsi/dvb/dit_section.h>
+#include <libucsi/dvb/eit_section.h>
+#include <libucsi/dvb/nit_section.h>
+#include <libucsi/dvb/rst_section.h>
+#include <libucsi/dvb/sdt_section.h>
+#include <libucsi/dvb/sit_section.h>
+#include <libucsi/dvb/st_section.h>
+#include <libucsi/dvb/tdt_section.h>
+#include <libucsi/dvb/tot_section.h>
+#include <libucsi/dvb/tva_container_section.h>
+#include <libucsi/dvb/int_section.h>
+
+/**
+ * The following are not implemented just now.
+ */
+/*
+#include <libucsi/dvb/tva_related_content_section.h>
+#include <libucsi/dvb/tva_content_identifier_section.h>
+#include <libucsi/dvb/tva_resolution_provider_notification_section.h>
+#include <libucsi/dvb/ait_section.h>
+#include <libucsi/dvb/cit_section.h>
+#include <libucsi/dvb/rct_section.h>
+#include <libucsi/dvb/rnt_section.h>
+*/
+
+#define TRANSPORT_NIT_PID 0x10
+#define TRANSPORT_SDT_PID 0x11
+#define TRANSPORT_BAT_PID 0x11
+#define TRANSPORT_EIT_PID 0x12
+#define TRANSPORT_CIT_PID 0x12
+#define TRANSPORT_RST_PID 0x13
+#define TRANSPORT_TDT_PID 0x14
+#define TRANSPORT_TOT_PID 0x14
+#define TRANSPORT_RNT_PID 0x16
+#define TRANSPORT_DIT_PID 0x1e
+#define TRANSPORT_SIT_PID 0x1f
+
+/**
+ * Enumeration of DVB section tags.
+ */
+enum dvb_section_tag {
+ stag_dvb_network_information_actual = 0x40,
+ stag_dvb_network_information_other = 0x41,
+
+ stag_dvb_service_description_actual = 0x42,
+ stag_dvb_service_description_other = 0x46,
+
+ stag_dvb_bouquet_association = 0x4a,
+ stag_dvb_update_notification = 0x4b, /* same syntax as IP_MAC */
+ stag_dvb_ip_mac_notification = 0x4c,
+
+ stag_dvb_event_information_nownext_actual = 0x4e,
+ stag_dvb_event_information_nownext_other = 0x4f,
+ stag_dvb_event_information_schedule_actual = 0x50, /* 0x50->0x5f */
+ stag_dvb_event_information_schedule_other = 0x60, /* 0x60->0x6f */
+
+ stag_dvb_time_date = 0x70,
+ stag_dvb_running_status = 0x71,
+ stag_dvb_stuffing = 0x72,
+ stag_dvb_time_offset = 0x73,
+ stag_dvb_application_information = 0x74,
+ stag_dvb_tva_container = 0x75,
+ stag_dvb_tva_related_content = 0x76,
+ stag_dvb_tva_content_identifier = 0x77,
+ stag_dvb_mpe_fec = 0x78,
+ stag_dvb_tva_resolution_provider_notification = 0x79,
+
+ stag_dvb_discontinuity_information = 0x7e,
+ stag_dvb_selection_information = 0x7f,
+
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h
new file mode 100644
index 0000000..f16781b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_availability_descriptor.h
@@ -0,0 +1,98 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SERVICE_AVAILABILITY_DESCRIPTOR
+#define _UCSI_DVB_SERVICE_AVAILABILITY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_service_availability_descriptor structure.
+ */
+struct dvb_service_availability_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t availability_flag : 1; ,
+ uint8_t reserved : 7; )
+ /* uint16_t cell_ids[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_service_availability_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ * @return dvb_service_availability_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_service_availability_descriptor*
+ dvb_service_availability_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint8_t* buf = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+
+ pos += sizeof(struct dvb_service_availability_descriptor) - 2;
+
+ if ((len - pos) % 2)
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ pos += 2;
+ }
+
+ return (struct dvb_service_availability_descriptor*) d;
+}
+
+/**
+ * Accessor for the cell_ids field of a dvb_service_availability_descriptor.
+ *
+ * @param d dvb_service_availability_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint32_t *
+ dvb_service_availability_descriptor_cell_ids(struct dvb_service_availability_descriptor *d)
+{
+ return (uint32_t *) ((uint8_t *) d + sizeof(struct dvb_service_availability_descriptor));
+}
+
+/**
+ * Determine the number of entries in the cell_ids field of a dvb_service_availability_descriptor.
+ *
+ * @param d dvb_service_availability_descriptor pointer.
+ * @return The number of entries.
+ */
+static inline int
+ dvb_service_availability_descriptor_cell_ids_count(struct dvb_service_availability_descriptor *d)
+{
+ return (d->d.len - 1) >> 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h
new file mode 100644
index 0000000..e116ffc
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_descriptor.h
@@ -0,0 +1,156 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SERVICE_DESCRIPTOR
+#define _UCSI_DVB_SERVICE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for service_type.
+ */
+enum {
+ DVB_SERVICE_TYPE_DIGITAL_TV = 0x01,
+ DVB_SERVICE_TYPE_DIGITAL_RADIO = 0x02,
+ DVB_SERVICE_TYPE_TELETEXT = 0x03,
+ DVB_SERVICE_TYPE_NVOD_REF = 0x04,
+ DVB_SERVICE_TYPE_NVOD_TIMESHIFT = 0x05,
+ DVB_SERVICE_TYPE_MOSAIC = 0x06,
+ DVB_SERVICE_TYPE_PAL = 0x07,
+ DVB_SERVICE_TYPE_SECAM = 0x08,
+ DVB_SERVICE_TYPE_D_D2_MAC = 0x09,
+ DVB_SERVICE_TYPE_FM_RADIO = 0x0a,
+ DVB_SERVICE_TYPE_NTSC = 0x0b,
+ DVB_SERVICE_TYPE_DATA_BCAST = 0x0c,
+ DVB_SERVICE_TYPE_EN50221 = 0x0d,
+ DVB_SERVICE_TYPE_RCS_MAP = 0x0e,
+ DVB_SERVICE_TYPE_RCS_FLS = 0x0f,
+ DVB_SERVICE_TYPE_MHP = 0x10
+};
+
+/**
+ * dvb_service_descriptor structure.
+ */
+struct dvb_service_descriptor {
+ struct descriptor d;
+
+ uint8_t service_type;
+ uint8_t service_provider_name_length;
+ /* uint8_t service_provider_name[] */
+ /* struct dvb_service_descriptor_part2 part2 */
+} __ucsi_packed;
+
+/**
+ * Second part of a dvb_service_descriptor following the variable length
+ * service_provider_name field.
+ */
+struct dvb_service_descriptor_part2 {
+ uint8_t service_name_length;
+ /* uint8_t service_name[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_service_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_service_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_service_descriptor*
+ dvb_service_descriptor_codec(struct descriptor* d)
+{
+ struct dvb_service_descriptor *p =
+ (struct dvb_service_descriptor *) d;
+ struct dvb_service_descriptor_part2 *p2;
+ uint32_t pos = sizeof(struct dvb_service_descriptor) - 2;
+ uint32_t len = d->len;
+
+ if (pos > len)
+ return NULL;
+
+ pos += p->service_provider_name_length;
+
+ if (pos > len)
+ return NULL;
+
+ p2 = (struct dvb_service_descriptor_part2*) ((uint8_t*) d + 2 + pos);
+
+ pos += sizeof(struct dvb_service_descriptor_part2);
+
+ if (pos > len)
+ return NULL;
+
+ pos += p2->service_name_length;
+
+ if (pos != len)
+ return NULL;
+
+ return p;
+}
+
+/**
+ * Accessor for the service_provider_name field of a dvb_service_descriptor.
+ *
+ * @param d dvb_service_descriptor pointer.
+ * @return Pointer to the service_provider_name field.
+ */
+static inline uint8_t *
+ dvb_service_descriptor_service_provider_name(struct dvb_service_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_service_descriptor);
+}
+
+/**
+ * Accessor for the second part of a dvb_service_descriptor.
+ *
+ * @param d dvb_service_descriptor pointer.
+ * @return dvb_service_descriptor_part2 pointer.
+ */
+static inline struct dvb_service_descriptor_part2 *
+ dvb_service_descriptor_part2(struct dvb_service_descriptor *d)
+{
+ return (struct dvb_service_descriptor_part2 *)
+ ((uint8_t*) d + sizeof(struct dvb_service_descriptor) +
+ d->service_provider_name_length);
+}
+
+/**
+ * Accessor for the service_name field of a dvb_service_descriptor_part2.
+ *
+ * @param d dvb_service_descriptor_part2 pointer.
+ * @return Pointer to the service_name field.
+ */
+static inline uint8_t *
+ dvb_service_descriptor_service_name(struct dvb_service_descriptor_part2 *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_service_descriptor_part2);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_identifier_descriptor.h
new file mode 100644
index 0000000..2037a05
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_identifier_descriptor.h
@@ -0,0 +1,82 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SERVICE_IDENTIFIER_DESCRIPTOR
+#define _UCSI_DVB_SERVICE_IDENTIFIER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_service_identifier_descriptor.
+ */
+struct dvb_service_identifier_descriptor {
+ struct descriptor d;
+
+ /* uint8_t identifier[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_service_identifier_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_service_identifier_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_service_identifier_descriptor*
+ dvb_service_identifier_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_service_identifier_descriptor*) d;
+}
+
+/**
+ * Retrieve a pointer to the identifier field of a dvb_service_identifier_descriptor.
+ *
+ * @param d dvb_service_identifier_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_service_identifier_descriptor_identifier(struct dvb_service_identifier_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_service_identifier_descriptor);
+}
+
+/**
+ * Calculate length of the identifier field of a dvb_service_identifier_descriptor.
+ *
+ * @param d dvb_service_identifier_descriptor pointer.
+ * @return The length in bytes.
+ */
+static inline int
+ dvb_service_identifier_descriptor_identifier_length(struct dvb_service_identifier_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_list_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_list_descriptor.h
new file mode 100644
index 0000000..0086b25
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_list_descriptor.h
@@ -0,0 +1,122 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SERVICE_LIST_DESCRIPTOR
+#define _UCSI_DVB_SERVICE_LIST_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_service_list_descriptor structure.
+ */
+struct dvb_service_list_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_service_list_service services[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the services field of a dvb_service_list_descriptor.
+ */
+struct dvb_service_list_service {
+ uint16_t service_id;
+ uint8_t service_type;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_service_list_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_service_list_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_service_list_descriptor*
+ dvb_service_list_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+ uint8_t *p = (uint8_t*) d + 2;
+
+ if (len % sizeof(struct dvb_service_list_service))
+ return NULL;
+
+ while(pos < len) {
+ bswap16(p+pos);
+ pos += sizeof(struct dvb_service_list_service);
+ }
+
+ return (struct dvb_service_list_descriptor*) d;
+}
+
+/**
+ * Iterator for services field in a dvb_service_list_descriptor.
+ *
+ * @param d dvb_service_list_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_service_list_service.
+ */
+#define dvb_service_list_descriptor_services_for_each(d, pos) \
+ for ((pos) = dvb_service_list_descriptor_services_first(d); \
+ (pos); \
+ (pos) = dvb_service_list_descriptor_services_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_service_list_service*
+ dvb_service_list_descriptor_services_first(struct dvb_service_list_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_service_list_service *)
+ ((uint8_t*) d + sizeof(struct dvb_service_list_descriptor));
+}
+
+static inline struct dvb_service_list_service*
+ dvb_service_list_descriptor_services_next(struct dvb_service_list_descriptor *d,
+ struct dvb_service_list_service *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_service_list_service);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_service_list_service *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/service_move_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_move_descriptor.h
new file mode 100644
index 0000000..7685e65
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/service_move_descriptor.h
@@ -0,0 +1,67 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SERVICE_MOVE_DESCRIPTOR
+#define _UCSI_DVB_SERVICE_MOVE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_service_move_descriptor structure.
+ */
+struct dvb_service_move_descriptor {
+ struct descriptor d;
+
+ uint16_t new_original_network_id;
+ uint16_t new_transport_stream_id;
+ uint16_t new_service_id;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_service_move_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to dvb_service_move_descriptor, or NULL on error.
+ */
+static inline struct dvb_service_move_descriptor*
+ dvb_service_move_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_service_move_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+ bswap16((uint8_t*) d + 4);
+ bswap16((uint8_t*) d + 6);
+
+ return (struct dvb_service_move_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/short_event_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_event_descriptor.h
new file mode 100644
index 0000000..449c6f0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_event_descriptor.h
@@ -0,0 +1,135 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SHORT_EVENT_DESCRIPTOR
+#define _UCSI_DVB_SHORT_EVENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_short_event_descriptor structure.
+ */
+struct dvb_short_event_descriptor {
+ struct descriptor d;
+
+ iso639lang_t language_code;
+ uint8_t event_name_length;
+ /* uint8_t event_name[] */
+ /* struct dvb_short_event_descriptor_part2 part2 */
+} __ucsi_packed;
+
+/**
+ * Second part of a dvb_short_event_descriptor, following the variable length
+ * name field.
+ */
+struct dvb_short_event_descriptor_part2 {
+ uint8_t text_length;
+ /* uint8_t text[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_short_event_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_short_event_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_short_event_descriptor*
+ dvb_short_event_descriptor_codec(struct descriptor* d)
+{
+ struct dvb_short_event_descriptor *p =
+ (struct dvb_short_event_descriptor*) d;
+ struct dvb_short_event_descriptor_part2 *p2;
+ uint32_t pos = sizeof(struct dvb_short_event_descriptor) - 2;
+ uint32_t len = d->len;
+
+ if (pos > len)
+ return NULL;
+
+ pos += p->event_name_length;
+
+ if (pos > len)
+ return NULL;
+
+ p2 = (struct dvb_short_event_descriptor_part2*) ((uint8_t*) d + 2 + pos);
+
+ pos += sizeof(struct dvb_short_event_descriptor_part2);
+
+ if (pos > len)
+ return NULL;
+
+ pos += p2->text_length;
+
+ if (pos != len)
+ return NULL;
+
+ return p;
+}
+
+/**
+ * Accessor for name field in a dvb_short_event_descriptor.
+ *
+ * @param d dvb_short_event_descriptor pointer.
+ * @return Pointer to name field.
+ */
+static inline uint8_t *
+ dvb_short_event_descriptor_event_name(struct dvb_short_event_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_short_event_descriptor);
+}
+
+/**
+ * Accessor for second part of a dvb_short_event_descriptor.
+ *
+ * @param d dvb_short_event_descriptor pointer.
+ * @return dvb_short_event_descriptor_part2 pointer.
+ */
+static inline struct dvb_short_event_descriptor_part2 *
+ dvb_short_event_descriptor_part2(struct dvb_short_event_descriptor *d)
+{
+ return (struct dvb_short_event_descriptor_part2 *)
+ ((uint8_t*) d + sizeof(struct dvb_short_event_descriptor) +
+ d->event_name_length);
+}
+
+/**
+ * Accessor for text field in a dvb_short_event_descriptor_part2.
+ *
+ * @param d dvb_short_event_descriptor_part2 pointer.
+ * @return Pointer to text field.
+ */
+static inline uint8_t *
+ dvb_short_event_descriptor_text(struct dvb_short_event_descriptor_part2 *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_short_event_descriptor_part2);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h
new file mode 100644
index 0000000..7deab9b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/short_smoothing_buffer_descriptor.h
@@ -0,0 +1,87 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SHORT_SMOOTHING_BUFFER_DESCRIPTOR
+#define _UCSI_DVB_SHORT_SMOOTHING_BUFFER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_short_smoothing_buffer_descriptor structure.
+ */
+struct dvb_short_smoothing_buffer_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t sb_size : 2; ,
+ uint8_t sb_leak_rate : 6; )
+ /* uint8_t reserved [] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_short_smoothing_buffer_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_short_smoothing_buffer_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_short_smoothing_buffer_descriptor*
+ dvb_short_smoothing_buffer_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct dvb_short_smoothing_buffer_descriptor) - 2))
+ return NULL;
+
+ return (struct dvb_short_smoothing_buffer_descriptor*) d;
+}
+
+/**
+ * Accessor for reserved field in a dvb_short_smoothing_buffer_descriptor.
+ *
+ * @param d dvb_short_smoothing_buffer_descriptor pointer.
+ * @return Pointer to reserved field.
+ */
+static inline uint8_t *
+ dvb_short_smoothing_buffer_descriptor_reserved(struct dvb_short_smoothing_buffer_descriptor *d)
+{
+ return (uint8_t*) d + sizeof(struct dvb_short_smoothing_buffer_descriptor);
+}
+
+/**
+ * Calculate length of reserved field in a dvb_short_smoothing_buffer_descriptor.
+ *
+ * @param d dvb_short_smoothing_buffer_descriptor pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ dvb_short_smoothing_buffer_descriptor_reserved_length(struct dvb_short_smoothing_buffer_descriptor *d)
+{
+ return d->d.len - 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c
new file mode 100644
index 0000000..61134d0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.c
@@ -0,0 +1,70 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/sit_section.h>
+
+struct dvb_sit_section * dvb_sit_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *) ext;
+ struct dvb_sit_section * ret = (struct dvb_sit_section *) ext;
+ unsigned int pos = sizeof(struct section_ext);
+ unsigned int len = section_ext_length(ext);
+
+ if (len < sizeof(struct dvb_sit_section))
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += 2;
+
+ if ((pos + ret->transmission_info_loop_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, ret->transmission_info_loop_length))
+ return NULL;
+
+ pos += ret->transmission_info_loop_length;
+
+ while (pos < len) {
+ struct dvb_sit_service * service = (void*)(buf + pos);
+
+ if ((pos + sizeof(struct dvb_sit_service)) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ bswap16(buf + pos + 2);
+ bswap16(buf + pos + 4);
+ pos += sizeof(struct dvb_sit_service);
+
+ if ((pos + service->service_loop_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, service->service_loop_length))
+ return NULL;
+
+ pos += service->service_loop_length;
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return ret;
+}
+
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h
new file mode 100644
index 0000000..d05989f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/sit_section.h
@@ -0,0 +1,173 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SIT_SECTION_H
+#define _UCSI_DVB_SIT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_sit_section structure.
+ */
+struct dvb_sit_section {
+ struct section_ext head;
+
+ EBIT2(uint16_t reserved : 4; ,
+ uint16_t transmission_info_loop_length :12; );
+ /* struct descriptor descriptors[] */
+ /* struct dvb_sit_service services[] */
+};
+
+/**
+ * An entry in the services field of a dvb_sit_section.
+ */
+struct dvb_sit_service {
+ uint16_t service_id;
+ EBIT3(uint16_t reserved : 1; ,
+ uint16_t running_status : 3; ,
+ uint16_t service_loop_length :12; );
+ /* struct descriptor descriptors[] */
+};
+
+/**
+ * Process a dvb_sit_section.
+ *
+ * @param section Generic section_ext structure.
+ * @return dvb_sit_section pointer, or NULL on error.
+ */
+struct dvb_sit_section * dvb_sit_section_codec(struct section_ext *section);
+
+/**
+ * Iterator for descriptors field in a dvb_sit_section.
+ *
+ * @param sit dvb_sit_section Pointer.
+ * @param pos Variable holding pointer to current descriptor.
+ */
+#define dvb_sit_section_descriptors_for_each(sit, pos) \
+ for ((pos) = dvb_sit_section_descriptors_first(sit); \
+ (pos); \
+ (pos) = dvb_sit_section_descriptors_first(sit))
+
+/**
+ * Iterator for services field in a dvb_sit_section.
+ *
+ * @param sit dvb_sit_section Pointer.
+ * @param pos Variable holding pointer to current dvb_sit_service.
+ */
+#define dvb_sit_section_services_for_each(sit, pos) \
+ for ((pos) = dvb_sit_section_services_first(sit); \
+ (pos); \
+ (pos) = dvb_sit_section_services_next(sit, pos))
+
+/**
+ * Iterator for descriptors field in a dvb_sit_service.
+ *
+ * @param service dvb_sit_service Pointer.
+ * @param pos Variable holding pointer to current descriptor.
+ */
+#define dvb_sit_service_descriptors_for_each(service, pos) \
+ for ((pos) = dvb_sit_service_descriptors_first(service); \
+ (pos); \
+ (pos) = dvb_sit_service_descriptors_next(service, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ dvb_sit_section_descriptors_first(struct dvb_sit_section *sit)
+{
+ if (sit->transmission_info_loop_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) sit + sizeof(struct dvb_sit_section));
+}
+
+static inline struct descriptor *
+ dvb_sit_section_descriptors_next(struct dvb_sit_section *sit,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) sit + sizeof(struct dvb_sit_section),
+ sit->transmission_info_loop_length,
+ pos);
+}
+
+static inline struct dvb_sit_service *
+ dvb_sit_section_services_first(struct dvb_sit_section *sit)
+{
+ int pos = sizeof(struct dvb_sit_section) + sit->transmission_info_loop_length;
+
+ if (pos >= section_ext_length(&sit->head))
+ return NULL;
+
+ return (struct dvb_sit_service*) ((uint8_t *) sit + pos);
+}
+
+static inline struct dvb_sit_service *
+ dvb_sit_section_services_next(struct dvb_sit_section *sit,
+ struct dvb_sit_service *pos)
+{
+ uint8_t *end = (uint8_t*) sit + section_ext_length(&sit->head);
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_sit_service) +
+ pos->service_loop_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_sit_service *) next;
+}
+
+static inline struct descriptor *
+ dvb_sit_service_descriptors_first(struct dvb_sit_service * t)
+{
+ if (t->service_loop_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) t + sizeof(struct dvb_sit_service));
+}
+
+static inline struct descriptor *
+ dvb_sit_service_descriptors_next(struct dvb_sit_service *t,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t*) t + sizeof(struct dvb_sit_service),
+ t->service_loop_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.c
new file mode 100644
index 0000000..0e60aa1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.c
@@ -0,0 +1,29 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/st_section.h>
+
+struct dvb_st_section * dvb_st_section_codec(struct section * section)
+{
+ struct dvb_st_section * ret = (struct dvb_st_section *)section;
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.h
new file mode 100644
index 0000000..52ba888
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/st_section.h
@@ -0,0 +1,77 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_ST_SECTION_H
+#define _UCSI_DVB_ST_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * dvb_st_section structure.
+ */
+struct dvb_st_section {
+ struct section head;
+
+ /* uint8_t data[] */
+};
+
+/**
+ * Process a dvb_st_section.
+ *
+ * @param section Generic section header.
+ * @return dvb_st_section pointer, or NULL on error.
+ */
+struct dvb_st_section *dvb_st_section_codec(struct section *section);
+
+/**
+ * Accessor for data field of dvb_st_section.
+ *
+ * @param st dvb_st_section Pointer.
+ * @return Pointer to field.
+ */
+static inline uint8_t*
+ dvb_st_section_data(struct dvb_st_section* st)
+{
+ return (uint8_t*) st + sizeof(struct dvb_st_section);
+}
+
+/**
+ * Calculate length of data field of dvb_st_section.
+ *
+ * @param st dvb_st_section Pointer.
+ * @return Length in bytes.
+ */
+static inline int
+ dvb_st_section_data_length(struct dvb_st_section* st)
+{
+ return st->head.length;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/stream_identifier_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/stream_identifier_descriptor.h
new file mode 100644
index 0000000..262c7e2
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/stream_identifier_descriptor.h
@@ -0,0 +1,61 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_STREAM_IDENTIFIER_DESCRIPTOR
+#define _UCSI_DVB_STREAM_IDENTIFIER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_stream_identifier_descriptor structure.
+ */
+struct dvb_stream_identifier_descriptor {
+ struct descriptor d;
+
+ uint8_t component_tag;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_stream_identifier_descriptor.
+ *
+ * @param d Pointer to generic descriptor structure.
+ * @return dvb_stream_identifier_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_stream_identifier_descriptor*
+ dvb_stream_identifier_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_stream_identifier_descriptor) - 2))
+ return NULL;
+
+ return (struct dvb_stream_identifier_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/stuffing_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/stuffing_descriptor.h
new file mode 100644
index 0000000..48e415d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/stuffing_descriptor.h
@@ -0,0 +1,82 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_STUFFING_DESCRIPTOR
+#define _UCSI_DVB_STUFFING_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_stuffing_descriptor.
+ */
+struct dvb_stuffing_descriptor {
+ struct descriptor d;
+
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_stuffing_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_stuffing_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_stuffing_descriptor*
+ dvb_stuffing_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_stuffing_descriptor*) d;
+}
+
+/**
+ * Retrieve a pointer to the data field of a dvb_stuffing_descriptor.
+ *
+ * @param d dvb_stuffing_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ dvb_stuffing_descriptor_data(struct dvb_stuffing_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_stuffing_descriptor);
+}
+
+/**
+ * Calculate length of the data field of a dvb_stuffing_descriptor.
+ *
+ * @param d dvb_stuffing_descriptor pointer.
+ * @return The length in bytes.
+ */
+static inline int
+ dvb_stuffing_descriptor_data_length(struct dvb_stuffing_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/subtitling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/subtitling_descriptor.h
new file mode 100644
index 0000000..74fc25a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/subtitling_descriptor.h
@@ -0,0 +1,126 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_SUBTITLING_DESCRIPTOR
+#define _UCSI_DVB_SUBTITLING_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_subtitling_descriptor structure.
+ */
+struct dvb_subtitling_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_subtitling_entry subtitles[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the subtitles field of the a dvb_subtitling_descriptor.
+ */
+struct dvb_subtitling_entry {
+ iso639lang_t language_code;
+ uint8_t subtitling_type;
+ uint16_t composition_page_id;
+ uint16_t ancillary_page_id;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_subtitling_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return dvb_subtitling_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_subtitling_descriptor*
+ dvb_subtitling_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint8_t* ptr = (uint8_t*) d + 2;
+ uint32_t len = d->len;
+
+ if (len % sizeof(struct dvb_subtitling_entry))
+ return NULL;
+
+ while(pos < len) {
+ bswap16(ptr+pos+4);
+ bswap16(ptr+pos+6);
+ pos += sizeof(struct dvb_subtitling_entry);
+ }
+
+ return (struct dvb_subtitling_descriptor*) d;
+}
+
+/**
+ * Iterator for subtitles field in dvb_subtitling_descriptor.
+ *
+ * @param d dvb_subtitling_descriptor pointer.
+ * @param pos Variable containing a pointer to current dvb_subtitling_entry.
+ */
+#define dvb_subtitling_descriptor_subtitles_for_each(d, pos) \
+ for ((pos) = dvb_subtitling_descriptor_subtitles_first(d); \
+ (pos); \
+ (pos) = dvb_subtitling_descriptor_subtitles_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_subtitling_entry*
+ dvb_subtitling_descriptor_subtitles_first(struct dvb_subtitling_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_subtitling_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_subtitling_descriptor));
+}
+
+static inline struct dvb_subtitling_entry*
+ dvb_subtitling_descriptor_subtitles_next(struct dvb_subtitling_descriptor *d,
+ struct dvb_subtitling_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_subtitling_entry);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_subtitling_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c
new file mode 100644
index 0000000..30a23cf
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.c
@@ -0,0 +1,33 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/tdt_section.h>
+
+struct dvb_tdt_section * dvb_tdt_section_codec(struct section * section)
+{
+ int len = section->length + sizeof(struct section);
+ struct dvb_tdt_section * ret = (struct dvb_tdt_section *) section;
+
+ if (len != sizeof(struct dvb_tdt_section))
+ return NULL;
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.h
new file mode 100644
index 0000000..fc2bcb8
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tdt_section.h
@@ -0,0 +1,54 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TDT_SECTION_H
+#define _UCSI_DVB_TDT_SECTION_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+#include <libucsi/dvb/types.h>
+
+/**
+ * dvb_tdt_section structure.
+ */
+struct dvb_tdt_section {
+ struct section head;
+
+ dvbdate_t utc_time;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_tdt_section.
+ *
+ * @param section Generic section header.
+ * @return dvb_tdt_section pointer, or NULL on error.
+ */
+struct dvb_tdt_section *dvb_tdt_section_codec(struct section *section);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h
new file mode 100644
index 0000000..46b39e4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/telephone_descriptor.h
@@ -0,0 +1,150 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TELEPHONE_DESCRIPTOR
+#define _UCSI_DVB_TELEPHONE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_telephone_descriptor stucture.
+ */
+struct dvb_telephone_descriptor {
+ struct descriptor d;
+
+ EBIT3(uint8_t reserved_1 : 2; ,
+ uint8_t foreign_availability : 1; ,
+ uint8_t connection_type : 5; )
+ EBIT4(uint8_t reserved_2 : 1; ,
+ uint8_t country_prefix_length : 2; ,
+ uint8_t international_area_code_length : 3; ,
+ uint8_t operator_code_length : 2; )
+ EBIT3(uint8_t reserved_3 : 1; ,
+ uint8_t national_area_code_length : 3; ,
+ uint8_t core_number_length : 4; )
+ /* uint8_t country_prefix[] */
+ /* uint8_t international_area_code[] */
+ /* uint8_t operator_code[] */
+ /* uint8_t national_area_code[] */
+ /* uint8_t core_number[] */
+} __ucsi_packed;
+
+
+/**
+ * Process a dvb_telephone_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return dvb_telephone_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_telephone_descriptor*
+ dvb_telephone_descriptor_codec(struct descriptor* d)
+{
+ struct dvb_telephone_descriptor* p =
+ (struct dvb_telephone_descriptor*) d;
+ uint32_t pos = sizeof(struct dvb_telephone_descriptor) - 2;
+ uint32_t len = d->len;
+
+ if (pos > len)
+ return NULL;
+
+ pos += p->country_prefix_length +
+ p->international_area_code_length +
+ p->operator_code_length +
+ p->national_area_code_length +
+ p->core_number_length;
+
+ if (pos != len)
+ return NULL;
+
+ return p;
+}
+
+/**
+ * Retrieve pointer to country_prefix field of a dvb_telephone_descriptor.
+ *
+ * @param d dvb_telephone_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ dvb_telephone_descriptor_country_prefix(struct dvb_telephone_descriptor* d)
+{
+ return (uint8_t*) d + sizeof(struct dvb_telephone_descriptor);
+}
+
+/**
+ * Retrieve pointer to international_area_code field of a dvb_telephone_descriptor.
+ *
+ * @param d dvb_telephone_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ dvb_telephone_descriptor_international_area_code(struct dvb_telephone_descriptor* d)
+{
+ return dvb_telephone_descriptor_country_prefix(d) + d->country_prefix_length;
+}
+
+/**
+ * Retrieve pointer to operator_code field of a dvb_telephone_descriptor.
+ *
+ * @param d dvb_telephone_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ dvb_telephone_descriptor_operator_code(struct dvb_telephone_descriptor* d)
+{
+ return dvb_telephone_descriptor_international_area_code(d) + d->international_area_code_length;
+}
+
+/**
+ * Retrieve pointer to national_area_code field of a dvb_telephone_descriptor.
+ *
+ * @param d dvb_telephone_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ dvb_telephone_descriptor_national_area_code(struct dvb_telephone_descriptor* d)
+{
+ return dvb_telephone_descriptor_operator_code(d) + d->operator_code_length;
+}
+
+/**
+ * Retrieve pointer to core_number field of a dvb_telephone_descriptor.
+ *
+ * @param d dvb_telephone_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ dvb_telephone_descriptor_core_number(struct dvb_telephone_descriptor* d)
+{
+ return dvb_telephone_descriptor_national_area_code(d) + d->national_area_code_length;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h
new file mode 100644
index 0000000..280b6eb
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/teletext_descriptor.h
@@ -0,0 +1,127 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TELETEXT_DESCRIPTOR
+#define _UCSI_DVB_TELETEXT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * Possible values for the type field.
+ */
+enum {
+ DVB_TELETEXT_TYPE_INITIAL = 0x01,
+ DVB_TELETEXT_TYPE_SUBTITLE = 0x02,
+ DVB_TELETEXT_TYPE_ADDITIONAL = 0x03,
+ DVB_TELETEXT_TYPE_SCHEDULE = 0x04,
+ DVB_TELETEXT_TYPE_SUBTITLE_HEARING_IMPAIRED= 0x05
+};
+
+/**
+ * dvb_teletext_descriptor structure.
+ */
+struct dvb_teletext_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_teletext_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the entries field of a dvb_teletext_descriptor.
+ */
+struct dvb_teletext_entry {
+ iso639lang_t language_code;
+ EBIT2(uint8_t type : 5; ,
+ uint8_t magazine_number: 3; )
+ uint8_t page_number;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_teletext_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return dvb_teletext_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_teletext_descriptor*
+ dvb_teletext_descriptor_codec(struct descriptor* d)
+{
+ if (d->len % sizeof(struct dvb_teletext_entry))
+ return NULL;
+
+ return (struct dvb_teletext_descriptor*) d;
+}
+
+/**
+ * Iterator for entries field of a dvb_teletext_descriptor.
+ *
+ * @param d dvb_teletext_descriptor pointer.
+ * @param pos Variable holding a pointer to the current dvb_teletext_entry.
+ */
+#define dvb_teletext_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_teletext_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_teletext_descriptor_entries_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_teletext_entry*
+ dvb_teletext_descriptor_entries_first(struct dvb_teletext_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_teletext_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_teletext_descriptor));
+}
+
+static inline struct dvb_teletext_entry*
+ dvb_teletext_descriptor_entries_next(struct dvb_teletext_descriptor *d,
+ struct dvb_teletext_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_teletext_entry);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_teletext_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h
new file mode 100644
index 0000000..b890178
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/terrestrial_delivery_descriptor.h
@@ -0,0 +1,77 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TERRESTRIAL_DELIVERY_DESCRIPTOR
+#define _UCSI_DVB_TERRESTRIAL_DELIVERY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_terrestrial_delivery_descriptor structure.
+ */
+struct dvb_terrestrial_delivery_descriptor {
+ struct descriptor d;
+
+ uint32_t centre_frequency; // Normal integer, units 10Hz
+ EBIT5(uint8_t bandwidth : 3; ,
+ uint8_t priority : 1; ,
+ uint8_t time_slicing_indicator : 1; ,
+ uint8_t mpe_fec_indicator : 1; ,
+ uint8_t reserved_1 : 2; )
+ EBIT3(uint8_t constellation : 2; ,
+ uint8_t hierarchy_information : 3; ,
+ uint8_t code_rate_hp_stream : 3; )
+ EBIT4(uint8_t code_rate_lp_stream : 3; ,
+ uint8_t guard_interval : 2; ,
+ uint8_t transmission_mode : 2; ,
+ uint8_t other_frequency_flag : 1; )
+ uint32_t reserved_2;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_terrestrial_delivery_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_terrestrial_delivery_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_terrestrial_delivery_descriptor*
+ dvb_terrestrial_delivery_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_terrestrial_delivery_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+ bswap32((uint8_t*) d + 9);
+
+ return (struct dvb_terrestrial_delivery_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_event_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_event_descriptor.h
new file mode 100644
index 0000000..6b4a9f6
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_event_descriptor.h
@@ -0,0 +1,65 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TIME_SHIFTED_EVENT_DESCRIPTOR
+#define _UCSI_DVB_TIME_SHIFTED_EVENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_time_shifted_event_descriptor structure.
+ */
+struct dvb_time_shifted_event_descriptor {
+ struct descriptor d;
+
+ uint16_t reference_service_id;
+ uint16_t reference_event_id;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_time_shifted_event_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return dvb_time_shifted_event_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_time_shifted_event_descriptor*
+ dvb_time_shifted_event_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_time_shifted_event_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+ bswap16((uint8_t*) d + 4);
+
+ return (struct dvb_time_shifted_event_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_service_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_service_descriptor.h
new file mode 100644
index 0000000..c8dcc0e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/time_shifted_service_descriptor.h
@@ -0,0 +1,63 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TIME_SHIFTED_SERVICE_DESCRIPTOR
+#define _UCSI_DVB_TIME_SHIFTED_SERVICE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_time_shifted_service_descriptor structure.
+ */
+struct dvb_time_shifted_service_descriptor {
+ struct descriptor d;
+
+ uint16_t reference_service_id;
+} __ucsi_packed;
+
+/**
+ * Process a dvb_time_shifted_service_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return Pointer to dvb_time_shifted_service_descriptor, or NULL on error.
+ */
+static inline struct dvb_time_shifted_service_descriptor*
+ dvb_time_shifted_service_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct dvb_time_shifted_service_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+
+ return (struct dvb_time_shifted_service_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c
new file mode 100644
index 0000000..3ce2c6d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.c
@@ -0,0 +1,50 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/tot_section.h>
+
+struct dvb_tot_section *dvb_tot_section_codec(struct section *section)
+{
+ uint8_t * buf = (uint8_t *)section;
+ int pos = sizeof(struct section);
+ int len = section->length + sizeof(struct section) - CRC_SIZE;
+ struct dvb_tot_section * ret = (struct dvb_tot_section *)section;
+
+ if (len < sizeof(struct dvb_tot_section))
+ return NULL;
+
+ pos += 5;
+ bswap16(buf + pos);
+ pos += 2;
+
+ if ((pos + ret->descriptors_loop_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, ret->descriptors_loop_length))
+ return NULL;
+
+ pos += ret->descriptors_loop_length;
+
+ if (pos != len)
+ return NULL;
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.h
new file mode 100644
index 0000000..3474da1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tot_section.h
@@ -0,0 +1,97 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TOT_SECTION_H
+#define _UCSI_DVB_TOT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+#include <libucsi/dvb/types.h>
+
+/**
+ * dvb_tot_section structure.
+ */
+struct dvb_tot_section {
+ struct section head;
+
+ dvbdate_t utc_time;
+ EBIT2(uint16_t reserved : 4; ,
+ uint16_t descriptors_loop_length:12; );
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_tot_section.
+ *
+ * @param section Pointer to generic section structure.
+ * @return dvb_tot_section pointer, or NULL on error.
+ */
+struct dvb_tot_section * dvb_tot_section_codec(struct section *section);
+
+/**
+ * Iterator for descriptors field of dvb_tot_section.
+ *
+ * @param tot dvb_tot_section pointer.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define dvb_tot_section_descriptors_for_each(tot, pos) \
+ for ((pos) = dvb_tot_section_descriptors_first(tot); \
+ (pos); \
+ (pos) = dvb_tot_section_descriptors_next(tot, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ dvb_tot_section_descriptors_first(struct dvb_tot_section * tot)
+{
+ if (tot->descriptors_loop_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) tot + sizeof(struct dvb_tot_section));
+}
+
+static inline struct descriptor *
+ dvb_tot_section_descriptors_next(struct dvb_tot_section *tot,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t *) tot + sizeof(struct dvb_tot_section),
+ tot->descriptors_loop_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/transport_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/transport_stream_descriptor.h
new file mode 100644
index 0000000..1797ec5
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/transport_stream_descriptor.h
@@ -0,0 +1,82 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TRANSPORT_STREAM_DESCRIPTOR
+#define _UCSI_DVB_TRANSPORT_STREAM_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_transport_stream_descriptor structure.
+ */
+struct dvb_transport_stream_descriptor {
+ struct descriptor d;
+
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Process dvb_transport_stream_descriptor structure.
+ *
+ * @param d Pointer to generic descriptor.
+ * @return dvb_transport_stream_descriptor structure or NULL on error.
+ */
+static inline struct dvb_transport_stream_descriptor*
+ dvb_transport_stream_descriptor_codec(struct descriptor* d)
+{
+ return (struct dvb_transport_stream_descriptor*) d;
+}
+
+/**
+ * Retrieve a pointer to the data field of a dvb_transport_stream_descriptor.
+ *
+ * @param d dvb_transport_stream_descriptor structure.
+ * @return Pointer to data field.
+ */
+static inline uint8_t *
+ dvb_transport_stream_descriptor_data(struct dvb_transport_stream_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_transport_stream_descriptor);
+}
+
+/**
+ * Calculate the length of the data field of a dvb_transport_stream_descriptor.
+ *
+ * @param d dvb_transport_stream_descriptor structure.
+ * @return length of data field in bytes.
+ */
+static inline int
+ dvb_transport_stream_descriptor_data_length(struct dvb_transport_stream_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c
new file mode 100644
index 0000000..32a5795
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.c
@@ -0,0 +1,33 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/dvb/tva_container_section.h>
+
+struct dvb_tva_container_section *dvb_tva_container_section_codec(struct section_ext *ext)
+{
+ int len = section_ext_length(ext);
+ struct dvb_tva_container_section* ret = (struct dvb_tva_container_section*) ext;
+
+ if (len < sizeof(struct dvb_tva_container_section))
+ return NULL;
+
+ return ret;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h
new file mode 100644
index 0000000..6519ded
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_container_section.h
@@ -0,0 +1,90 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TVA_CONTAINER_SECTION_H
+#define _UCSI_DVB_TVA_CONTAINER_SECTION_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+#include <libucsi/dvb/types.h>
+
+/**
+ * dvb_tva_container_section structure.
+ */
+struct dvb_tva_container_section {
+ struct section_ext head;
+
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Process a dvb_tva_container_section.
+ *
+ * @param section Generic section header.
+ * @return dvb_tdt_section pointer, or NULL on error.
+ */
+struct dvb_tva_container_section *dvb_tva_container_section_codec(struct section_ext *ext);
+
+/**
+ * Accessor for the container_id field of a tva container section.
+ *
+ * @param container dvb_tva_container_section pointer.
+ * @return The container_id.
+ */
+static inline uint16_t dvb_tva_container_section_container_id(struct dvb_tva_container_section *container)
+{
+ return container->head.table_id_ext;
+}
+
+/**
+ * Accessor for the selector_byte field of a dvb_data_broadcast_id_descriptor.
+ *
+ * @param d dvb_data_broadcast_id_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+dvb_tva_container_section_data(struct dvb_tva_container_section *s)
+{
+ return (uint8_t *) s + sizeof(struct dvb_tva_container_section);
+}
+
+/**
+ * Determine the number of bytes in the data field of a dvb_tva_container_section.
+ *
+ * @param d dvb_tva_container_section pointer.
+ * @return Length of the field in bytes.
+ */
+static inline int
+dvb_tva_container_section_data_length(struct dvb_tva_container_section *s)
+{
+ return section_ext_length(&s->head) - sizeof(struct dvb_tva_container_section);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h
new file mode 100644
index 0000000..c830259
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/tva_id_descriptor.h
@@ -0,0 +1,124 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TVA_ID_DESCRIPTOR
+#define _UCSI_DVB_TVA_ID_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * dvb_tva_id_descriptor structure.
+ */
+struct dvb_tva_id_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_tva_id_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the entries field of a dvb_tva_id_descriptor.
+ */
+struct dvb_tva_id_entry {
+ uint16_t tva_id;
+ EBIT2(uint8_t reserved : 5; ,
+ uint8_t running_status : 3; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_tva_id_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return dvb_tva_id_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_tva_id_descriptor*
+ dvb_tva_id_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+ uint8_t* buf = (uint8_t*) d + 2;
+
+ pos += sizeof(struct dvb_tva_id_descriptor) - 2;
+ if (len % sizeof(struct dvb_tva_id_entry))
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ pos+=3;
+ }
+
+ return (struct dvb_tva_id_descriptor*) d;
+}
+
+/**
+ * Iterator for the entries field of a dvb_tva_id_descriptor.
+ *
+ * @param d dvb_tva_id_descriptor pointer.
+ * @param pos Variable containing a pointer to the current dvb_tva_id_entry.
+ */
+#define dvb_tva_id_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_tva_id_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_tva_id_descriptor_entries_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_tva_id_entry*
+ dvb_tva_id_descriptor_entries_first(struct dvb_tva_id_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_tva_id_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_tva_id_descriptor));
+}
+
+static inline struct dvb_tva_id_entry*
+ dvb_tva_id_descriptor_countries_next(struct dvb_tva_id_descriptor *d,
+ struct dvb_tva_id_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_tva_id_entry);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_tva_id_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/types.c b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.c
new file mode 100644
index 0000000..c1cf583
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.c
@@ -0,0 +1,270 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <string.h>
+#include "types.h"
+
+time_t dvbdate_to_unixtime(dvbdate_t dvbdate)
+{
+ int k = 0;
+ struct tm tm;
+ double mjd;
+
+ /* check for the undefined value */
+ if ((dvbdate[0] == 0xff) &&
+ (dvbdate[1] == 0xff) &&
+ (dvbdate[2] == 0xff) &&
+ (dvbdate[3] == 0xff) &&
+ (dvbdate[4] == 0xff)) {
+ return -1;
+ }
+
+ memset(&tm, 0, sizeof(tm));
+ mjd = (dvbdate[0] << 8) | dvbdate[1];
+
+ tm.tm_year = (int) ((mjd - 15078.2) / 365.25);
+ tm.tm_mon = (int) (((mjd - 14956.1) - (int) (tm.tm_year * 365.25)) / 30.6001);
+ tm.tm_mday = (int) mjd - 14956 - (int) (tm.tm_year * 365.25) - (int) (tm.tm_mon * 30.6001);
+ if ((tm.tm_mon == 14) || (tm.tm_mon == 15)) k = 1;
+ tm.tm_year += k;
+ tm.tm_mon = tm.tm_mon - 2 - k * 12;
+ tm.tm_sec = bcd_to_integer(dvbdate[4]);
+ tm.tm_min = bcd_to_integer(dvbdate[3]);
+ tm.tm_hour = bcd_to_integer(dvbdate[2]);
+
+ return mktime(&tm);
+}
+
+void unixtime_to_dvbdate(time_t unixtime, dvbdate_t dvbdate)
+{
+ struct tm tm;
+ double l = 0;
+ int mjd;
+
+ /* the undefined value */
+ if (unixtime == -1) {
+ memset(dvbdate, 0xff, 5);
+ return;
+ }
+
+ gmtime_r(&unixtime, &tm);
+ tm.tm_mon++;
+ if ((tm.tm_mon == 1) || (tm.tm_mon == 2)) l = 1;
+ mjd = 14956 + tm.tm_mday + (int) ((tm.tm_year - l) * 365.25) + (int) ((tm.tm_mon + 1 + l * 12) * 30.6001);
+
+ dvbdate[0] = (mjd & 0xff00) >> 8;
+ dvbdate[1] = mjd & 0xff;
+ dvbdate[2] = integer_to_bcd(tm.tm_hour);
+ dvbdate[3] = integer_to_bcd(tm.tm_min);
+ dvbdate[4] = integer_to_bcd(tm.tm_sec);
+}
+
+int dvbduration_to_seconds(dvbduration_t dvbduration)
+{
+ int seconds = 0;
+
+ seconds += (bcd_to_integer(dvbduration[0]) * 60 * 60);
+ seconds += (bcd_to_integer(dvbduration[1]) * 60);
+ seconds += bcd_to_integer(dvbduration[2]);
+
+ return seconds;
+}
+
+void seconds_to_dvbduration(int seconds, dvbduration_t dvbduration)
+{
+ int hours, mins;
+
+ hours = seconds / (60*60);
+ seconds -= (hours * 60 * 60);
+ mins = seconds / 60;
+ seconds -= (mins * 60);
+
+ dvbduration[0] = integer_to_bcd(hours);
+ dvbduration[1] = integer_to_bcd(mins);
+ dvbduration[2] = integer_to_bcd(seconds);
+}
+
+int dvbhhmm_to_seconds(dvbhhmm_t dvbhhmm)
+{
+ int seconds = 0;
+
+ seconds += (bcd_to_integer(dvbhhmm[0]) * 60 * 60);
+ seconds += (bcd_to_integer(dvbhhmm[1]) * 60);
+
+ return seconds;
+}
+
+void seconds_to_dvbhhmm(int seconds, dvbhhmm_t dvbhhmm)
+{
+ int hours, mins;
+
+ hours = seconds / (60*60);
+ seconds -= (hours * 60 * 60);
+ mins = seconds / 60;
+
+ dvbhhmm[0] = integer_to_bcd(hours);
+ dvbhhmm[1] = integer_to_bcd(mins);
+}
+
+uint32_t integer_to_bcd(uint32_t intval)
+{
+ uint32_t val = 0;
+
+ int i;
+ for(i=0; i<=28;i+=4) {
+ val |= ((intval % 10) << i);
+ intval /= 10;
+ }
+
+ return val;
+}
+
+uint32_t bcd_to_integer(uint32_t bcdval)
+{
+ uint32_t val = 0;
+
+ int i;
+ for(i=28; i>=0;i-=4) {
+ val += ((bcdval >> i) & 0x0f);
+ if (i != 0) val *= 10;
+ }
+
+ return val;
+}
+
+const char *dvb_charset(char *dvb_text, int dvb_text_length, int *consumed)
+{
+ char *charset = "ISO6937";
+ int used = 0;
+
+ if (dvb_text_length == 0)
+ goto exit;
+ if (dvb_text[0] >= 32)
+ goto exit;
+ if (dvb_text[0] == 0x10) {
+ if (dvb_text_length < 3)
+ goto exit;
+
+ used = 3;
+ uint16_t ext = (dvb_text[1] << 8) | dvb_text[2];
+ switch(ext) {
+ case 0x01:
+ charset = "ISO8859-1";
+ break;
+ case 0x02:
+ charset = "ISO8859-2";
+ break;
+ case 0x03:
+ charset = "ISO8859-3";
+ break;
+ case 0x04:
+ charset = "ISO8859-4";
+ break;
+ case 0x05:
+ charset = "ISO8859-5";
+ break;
+ case 0x06:
+ charset = "ISO8859-6";
+ break;
+ case 0x07:
+ charset = "ISO8859-7";
+ break;
+ case 0x08:
+ charset = "ISO8859-8";
+ break;
+ case 0x09:
+ charset = "ISO8859-9";
+ break;
+ case 0x0a:
+ charset = "ISO8859-10";
+ break;
+ case 0x0b:
+ charset = "ISO8859-11";
+ break;
+ case 0x0d:
+ charset = "ISO8859-13";
+ break;
+ case 0x0e:
+ charset = "ISO8859-14";
+ break;
+ case 0x0f:
+ charset = "ISO8859-15";
+ break;
+ default:
+ used = 0;
+ break;
+ }
+ } else {
+ used = 1;
+ switch(dvb_text[0]) {
+ case 0x01:
+ charset = "ISO8859-5";
+ break;
+ case 0x02:
+ charset = "ISO8859-6";
+ break;
+ case 0x03:
+ charset = "ISO8859-7";
+ break;
+ case 0x04:
+ charset = "ISO8859-8";
+ break;
+ case 0x05:
+ charset = "ISO8859-9";
+ break;
+ case 0x06:
+ charset = "ISO8859-10";
+ break;
+ case 0x07:
+ charset = "ISO8859-11";
+ break;
+ case 0x09:
+ charset = "ISO8859-13";
+ break;
+ case 0x0a:
+ charset = "ISO8859-14";
+ break;
+ case 0x0b:
+ charset = "ISO8859-15";
+ break;
+ case 0x11:
+ charset = "UTF16";
+ break;
+ case 0x12:
+ charset = "EUC-KR";
+ break;
+ case 0x13:
+ charset = "GB2312";
+ break;
+ case 0x14:
+ charset = "GBK";
+ break;
+ case 0x15:
+ charset = "UTF8";
+ break;
+ default:
+ used = 0;
+ break;
+ }
+ }
+exit:
+ *consumed = used;
+ return charset;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h
new file mode 100644
index 0000000..f26ea6b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/types.h
@@ -0,0 +1,127 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_TYPES_H
+#define _UCSI_DVB_TYPES_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+#include <time.h>
+
+typedef uint8_t dvbdate_t[5];
+typedef uint8_t dvbduration_t[3];
+typedef uint8_t dvbhhmm_t[2];
+
+/**
+ * Running status values.
+ */
+enum {
+ DVB_RUNNING_STATUS_NOT_RUNNING = 0x01,
+ DVB_RUNNING_STATUS_FEW_SECONDS = 0x02,
+ DVB_RUNNING_STATUS_PAUSING = 0x03,
+ DVB_RUNNING_STATUS_RUNNING = 0x04
+};
+
+/**
+ * Convert from a 5 byte DVB UTC date to unix time.
+ * Note: this functions expects the DVB date in network byte order.
+ *
+ * @param d Pointer to DVB date.
+ * @return The unix timestamp, or -1 if the dvbdate was set to the 'undefined' value
+ */
+extern time_t dvbdate_to_unixtime(dvbdate_t dvbdate);
+
+/**
+ * Convert from a unix timestemp to a 5 byte DVB UTC date.
+ * Note: this function will always output the DVB date in
+ * network byte order.
+ *
+ * @param unixtime The unix timestamp, or -1 for the 'undefined' value.
+ * @param utc Pointer to 5 byte DVB date.
+ */
+extern void unixtime_to_dvbdate(time_t unixtime, dvbdate_t dvbdate);
+
+/**
+ * Convert from a DVB BCD duration to a number of seconds.
+ *
+ * @param dvbduration Pointer to 3 byte DVB duration.
+ * @return Number of seconds.
+ */
+extern int dvbduration_to_seconds(dvbduration_t dvbduration);
+
+/**
+ * Convert from a number of seconds to a DVB 3 byte BCD duration.
+ *
+ * @param seconds The number of seconds.
+ * @param dvbduration Pointer to 3 byte DVB duration.
+ */
+extern void seconds_to_dvbduration(int seconds, dvbduration_t dvbduration);
+
+/**
+ * Convert from a DVB BCD HHMM to a number of seconds.
+ *
+ * @param dvbduration Pointer to 2 byte DVB HHMM.
+ * @return Number of seconds.
+ */
+extern int dvbhhmm_to_seconds(dvbhhmm_t dvbhhmm);
+
+/**
+ * Convert from a number of seconds to a DVB 2 byte BCD HHMM.
+ *
+ * @param seconds The number of seconds.
+ * @param dvbduration Pointer to 2 byte DVB HHMM.
+ */
+extern void seconds_to_dvbhhmm(int seconds, dvbhhmm_t dvbhhmm);
+
+/**
+ * Convert a __ucsi_packed BCD value into a normal integer.
+ *
+ * @param bcd The value to convert.
+ * @return The value.
+ */
+extern uint32_t bcd_to_integer(uint32_t bcd);
+
+/**
+ * Convert a normal integer into a __ucsi_packed BCD value.
+ *
+ * @param integer The value to convert.
+ * @return The value.
+ */
+extern uint32_t integer_to_bcd(uint32_t integer);
+
+/**
+ * Determine the (iconv compatable) character set of a dvb string.
+ *
+ * @param dvb_text DVB text concerned.
+ * @param dvb_text_length Length of text.
+ * @param consumed Out parameter of number of bytes used to encode the character set.
+ * @return Name of the character set.
+ */
+extern const char *dvb_charset(char *dvb_text, int dvb_text_length, int *consumed);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h
new file mode 100644
index 0000000..9d41e0c
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_data_descriptor.h
@@ -0,0 +1,186 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_VBI_DATA_DESCRIPTOR
+#define _UCSI_DVB_VBI_DATA_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for the data_service_id field.
+ */
+enum {
+ DVB_VBI_DATA_SERVICE_ID_EBU = 0x01,
+ DVB_VBI_DATA_SERVICE_ID_INVERTED = 0x02,
+ DVB_VBI_DATA_SERVICE_ID_VPS = 0x04,
+ DVB_VBI_DATA_SERVICE_ID_WSS = 0x05,
+ DVB_VBI_DATA_SERVICE_ID_CC = 0x06,
+ DVB_VBI_DATA_SERVICE_ID_MONO_422 = 0x07
+};
+
+/**
+ * dvb_vbi_data_descriptor structure
+ */
+struct dvb_vbi_data_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_vbi_data_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the dvb_vbi_data_descriptor entries field.
+ */
+struct dvb_vbi_data_entry {
+ uint8_t data_service_id;
+ uint8_t data_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Format of the dvb_vbi_data_entry data field, if data_service_id == 1,2,4,5,6,7.
+ */
+struct dvb_vbi_data_x {
+ EBIT3(uint8_t reserved : 2; ,
+ uint8_t field_parity : 1; ,
+ uint8_t line_offset : 5; )
+} __ucsi_packed;
+
+/**
+ * Process a dvb_vbi_data_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return dvb_vbi_data_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_vbi_data_descriptor*
+ dvb_vbi_data_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* p = (uint8_t*) d + 2;
+ uint32_t pos = 0;
+ uint32_t len = d->len;
+
+ while(pos < len) {
+ struct dvb_vbi_data_entry *e =
+ (struct dvb_vbi_data_entry*) (p+pos);
+
+ pos += sizeof(struct dvb_vbi_data_entry);
+
+ if (pos > len)
+ return NULL;
+
+ pos += e->data_length;
+
+ if (pos > len)
+ return NULL;
+ }
+
+ return (struct dvb_vbi_data_descriptor*) d;
+}
+
+/**
+ * Iterator for entries field in a dvb_vbi_data_descriptor structure.
+ *
+ * @param d Pointer to dvb_vbi_data_descriptor structure.
+ * @param pos Variable holding pointer to the current dvb_vbi_data_entry structure.
+ */
+#define dvb_vbi_data_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_vbi_data_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_vbi_data_descriptor_entries_next(d, pos))
+
+/**
+ * Get a pointer to the data field of a dvb_vbi_data_entry.
+ *
+ * @param d dvb_vbi_data_entry structure.
+ * @return Pointer to the data field.
+ */
+static inline uint8_t *
+ dvb_vbi_data_entry_data(struct dvb_vbi_data_entry *d)
+{
+ return (uint8_t *) d + sizeof(struct dvb_vbi_data_entry);
+}
+
+/**
+ * Get a pointer to the data field of a dvb_vbi_data_x for id 1,2,4,5,6,7.
+ *
+ * @param d dvb_vbi_data_entry structure.
+ * @return Pointer to the data field, or NULL if invalid
+ */
+static inline struct dvb_vbi_data_x*
+ dvb_vbi_data_entry_data_x(struct dvb_vbi_data_entry *d)
+{
+ switch(d->data_service_id) {
+ case 1:
+ case 2:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return (struct dvb_vbi_data_x*) ((uint8_t *) d + sizeof(struct dvb_vbi_data_entry));
+ }
+
+ return NULL;
+}
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_vbi_data_entry*
+ dvb_vbi_data_descriptor_entries_first(struct dvb_vbi_data_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_vbi_data_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_vbi_data_descriptor));
+}
+
+static inline struct dvb_vbi_data_entry*
+ dvb_vbi_data_descriptor_entries_next(struct dvb_vbi_data_descriptor *d,
+ struct dvb_vbi_data_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_vbi_data_entry) +
+ pos->data_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_vbi_data_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h
new file mode 100644
index 0000000..6ae9791
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/dvb/vbi_teletext_descriptor.h
@@ -0,0 +1,116 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_DVB_VBI_TELETEXT_DESCRIPTOR
+#define _UCSI_DVB_VBI_TELETEXT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * dvb_vbi_teletext_descriptor structure
+ */
+struct dvb_vbi_teletext_descriptor {
+ struct descriptor d;
+
+ /* struct dvb_vbi_teletext_entry entries[] */
+} __ucsi_packed;
+
+/**
+ * An entry in a dvb_vbi_teletext_descriptor structure.
+ */
+struct dvb_vbi_teletext_entry {
+ iso639lang_t language_code;
+ EBIT2(uint8_t type : 5; ,
+ uint8_t magazine_number: 3; )
+ uint8_t page_number;
+} __ucsi_packed;
+
+/**
+ * Process an dvb_vbi_teletext_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return dvb_vbi_teletext_descriptor pointer, or NULL on error.
+ */
+static inline struct dvb_vbi_teletext_descriptor*
+ dvb_vbi_teletext_descriptor_codec(struct descriptor* d)
+{
+ if (d->len % sizeof(struct dvb_vbi_teletext_entry))
+ return NULL;
+
+ return (struct dvb_vbi_teletext_descriptor*) d;
+}
+
+/**
+ * Iterator for entries field of a dvb_vbi_teletext_descriptor.
+ *
+ * @param d Pointer to dvb_vbi_teletext_descriptor.
+ * @param pos Variable holding a pointer to the current dvb_vbi_teletext_entry.
+ */
+#define dvb_vbi_teletext_descriptor_entries_for_each(d, pos) \
+ for ((pos) = dvb_vbi_teletext_descriptor_entries_first(d); \
+ (pos); \
+ (pos) = dvb_vbi_teletext_descriptor_entries_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct dvb_vbi_teletext_entry*
+ dvb_vbi_teletext_descriptor_entries_first(struct dvb_vbi_teletext_descriptor *d)
+{
+ if (d->d.len == 0)
+ return NULL;
+
+ return (struct dvb_vbi_teletext_entry *)
+ ((uint8_t*) d + sizeof(struct dvb_vbi_teletext_descriptor));
+}
+
+static inline struct dvb_vbi_teletext_entry*
+ dvb_vbi_teletext_descriptor_entries_next(struct dvb_vbi_teletext_descriptor *d,
+ struct dvb_vbi_teletext_entry *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct dvb_vbi_teletext_entry);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct dvb_vbi_teletext_entry *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/endianops.h b/kaffeine/src/input/dvb/lib/libucsi/endianops.h
new file mode 100644
index 0000000..23b418b
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/endianops.h
@@ -0,0 +1,128 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_COMMON_H
+#define _UCSI_COMMON_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+#include <byteswap.h>
+#include <endian.h>
+
+#define __ucsi_packed __attribute__((packed))
+
+
+
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define EBIT2(x1,x2) x1 x2
+#define EBIT3(x1,x2,x3) x1 x2 x3
+#define EBIT4(x1,x2,x3,x4) x1 x2 x3 x4
+#define EBIT5(x1,x2,x3,x4,x5) x1 x2 x3 x4 x5
+#define EBIT6(x1,x2,x3,x4,x5,x6) x1 x2 x3 x4 x5 x6
+#define EBIT7(x1,x2,x3,x4,x5,x6,x7) x1 x2 x3 x4 x5 x6 x7
+#define EBIT8(x1,x2,x3,x4,x5,x6,x7,x8) x1 x2 x3 x4 x5 x6 x7 x8
+
+static inline void bswap16(uint8_t *buf) {
+ (void) buf;
+}
+
+static inline void bswap32(uint8_t *buf) {
+ (void) buf;
+}
+
+static inline void bswap64(uint8_t *buf) {
+ (void) buf;
+}
+
+static inline void bswap24(uint8_t *buf) {
+ (void) buf;
+}
+
+static inline void bswap40(uint8_t *buf) {
+ (void) buf;
+}
+
+static inline void bswap48(uint8_t *buf) {
+ (void) buf;
+}
+
+#else
+#define EBIT2(x1,x2) x2 x1
+#define EBIT3(x1,x2,x3) x3 x2 x1
+#define EBIT4(x1,x2,x3,x4) x4 x3 x2 x1
+#define EBIT5(x1,x2,x3,x4,x5) x5 x4 x3 x2 x1
+#define EBIT6(x1,x2,x3,x4,x5,x6) x6 x5 x4 x3 x2 x1
+#define EBIT7(x1,x2,x3,x4,x5,x6,x7) x7 x6 x5 x4 x3 x2 x1
+#define EBIT8(x1,x2,x3,x4,x5,x6,x7,x8) x8 x7 x6 x5 x4 x3 x2 x1
+
+static inline void bswap16(uint8_t * buf) {
+ *((uint16_t*)buf) = bswap_16((*(uint16_t*)buf));
+}
+
+static inline void bswap32(uint8_t * buf) {
+ *((uint32_t*)buf) = bswap_32((*(uint32_t*)buf));
+}
+
+static inline void bswap64(uint8_t * buf) {
+ *((uint64_t*)buf) = bswap_64((*(uint64_t*)buf));
+}
+
+static inline void bswap24(uint8_t * buf) {
+ uint8_t tmp0 = buf[0];
+
+ buf[0] = buf[2];
+ buf[2] = tmp0;
+}
+
+static inline void bswap40(uint8_t * buf) {
+ uint8_t tmp0 = buf[0];
+ uint8_t tmp1 = buf[1];
+
+ buf[0] = buf[4];
+ buf[1] = buf[3];
+ buf[3] = tmp1;
+ buf[4] = tmp0;
+}
+
+static inline void bswap48(uint8_t * buf) {
+ uint8_t tmp0 = buf[0];
+ uint8_t tmp1 = buf[1];
+ uint8_t tmp2 = buf[2];
+
+ buf[0] = buf[5];
+ buf[1] = buf[4];
+ buf[2] = buf[3];
+ buf[3] = tmp2;
+ buf[4] = tmp1;
+ buf[5] = tmp0;
+}
+
+#endif // __BYTE_ORDER
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile.am b/kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile.am
new file mode 100644
index 0000000..a8d0c32
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile.am
@@ -0,0 +1,12 @@
+noinst_LTLIBRARIES = libdvbmpeg.la
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib
+
+libdvbmpeg_la_SOURCES = cat_section.c \
+ metadata_section.c \
+ odsmt_section.c \
+ pat_section.c \
+ pmt_section.c \
+ tsdt_section.c
+
+CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/audio_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/audio_stream_descriptor.h
new file mode 100644
index 0000000..7e6ea07
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/audio_stream_descriptor.h
@@ -0,0 +1,65 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_AUDIO_STREAM_DESCRIPTOR
+#define _UCSI_MPEG_AUDIO_STREAM_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_audio_stream_descriptor structure
+ */
+struct mpeg_audio_stream_descriptor {
+ struct descriptor d;
+
+ EBIT5(uint8_t free_format_flag : 1; ,
+ uint8_t id : 1; ,
+ uint8_t layer : 2; ,
+ uint8_t variable_rate_audio_indicator : 1; ,
+ uint8_t reserved : 3; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_audio_stream_descriptor.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_audio_stream_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_audio_stream_descriptor*
+ mpeg_audio_stream_descriptor_codec(struct descriptor *d)
+{
+ if (d->len != (sizeof(struct mpeg_audio_stream_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg_audio_stream_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/ca_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ca_descriptor.h
new file mode 100644
index 0000000..88a65dd
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ca_descriptor.h
@@ -0,0 +1,91 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_CA_DESCRIPTOR
+#define _UCSI_MPEG_CA_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_ca_descriptor structure
+ */
+struct mpeg_ca_descriptor {
+ struct descriptor d;
+
+ uint16_t ca_system_id;
+ EBIT2(uint16_t reserved : 3; ,
+ uint16_t ca_pid : 13; );
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_ca_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return Pointer to an mpeg_ca_descriptor, or NULL on error.
+ */
+static inline struct mpeg_ca_descriptor*
+ mpeg_ca_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct mpeg_ca_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+ bswap16((uint8_t*) d + 4);
+
+ return (struct mpeg_ca_descriptor*) d;
+}
+
+/**
+ * Accessor for pointer to data field of an mpeg_ca_descriptor.
+ *
+ * @param d The mpeg_ca_descriptor structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ mpeg_ca_descriptor_data(struct mpeg_ca_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct mpeg_ca_descriptor);
+}
+
+/**
+ * Determine length of data field of an mpeg_ca_descriptor.
+ *
+ * @param d The mpeg_ca_descriptor structure.
+ * @return Length of the field in bytes.
+ */
+static inline int
+ mpeg_ca_descriptor_data_length(struct mpeg_ca_descriptor *d)
+{
+ return d->d.len - 4;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c
new file mode 100644
index 0000000..c72973e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.c
@@ -0,0 +1,34 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/mpeg/cat_section.h>
+
+struct mpeg_cat_section * mpeg_cat_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *)ext;
+ int pos = sizeof(struct section_ext);
+
+ if (verify_descriptors(buf + pos,
+ section_ext_length(ext) - sizeof(struct mpeg_cat_section)))
+ return NULL;
+
+ return (struct mpeg_cat_section *)ext;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h
new file mode 100644
index 0000000..864b19e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/cat_section.h
@@ -0,0 +1,94 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_CAT_SECTION_H
+#define _UCSI_MPEG_CAT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * mpeg_cat_section structure.
+ */
+struct mpeg_cat_section {
+ struct section_ext head;
+
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_cat_section.
+ *
+ * @param section The generic section_ext structure.
+ * @return Pointer to an mpeg_cat_section structure, or NULL on error.
+ */
+extern struct mpeg_cat_section *mpeg_cat_section_codec(struct section_ext *section);
+
+/**
+ * Convenience iterator for descriptors field of an mpeg_cat_section.
+ *
+ * @param cat The mpeg_cat_section pointer.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define mpeg_cat_section_descriptors_for_each(cat, pos) \
+ for ((pos) = mpeg_cat_section_descriptors_first(cat); \
+ (pos); \
+ (pos) = mpeg_cat_section_descriptors_next(cat, pos))
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ mpeg_cat_section_descriptors_first(struct mpeg_cat_section *cat)
+{
+ int pos = sizeof(struct mpeg_cat_section);
+
+ if (pos >= section_ext_length(&cat->head))
+ return NULL;
+
+ return (struct descriptor*)((uint8_t *) cat + pos);
+}
+
+
+static inline struct descriptor *
+ mpeg_cat_section_descriptors_next(struct mpeg_cat_section *cat,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t *) cat + sizeof(struct mpeg_cat_section),
+ section_ext_length(&cat->head) - sizeof(struct mpeg_cat_section),
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/content_labelling_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/content_labelling_descriptor.h
new file mode 100644
index 0000000..06738ab
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/content_labelling_descriptor.h
@@ -0,0 +1,356 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_CONTENT_LABELLING_DESCRIPTOR
+#define _UCSI_MPEG_CONTENT_LABELLING_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for content_time_base_indicator.
+ */
+enum {
+ MPEG_CONTENT_TIME_BASE_STC = 0x01,
+ MPEG_CONTENT_TIME_BASE_NPT = 0x02,
+};
+
+/**
+ * mpeg_content_labelling_descriptor structure.
+ */
+struct mpeg_content_labelling_descriptor {
+ struct descriptor d;
+
+ uint16_t metadata_application_format;
+ /* struct mpeg_content_labelling_descriptor_application_format_identifier id */
+ /* struct mpeg_content_labelling_descriptor_flags flags */
+ /* struct mpeg_content_labelling_descriptor_reference_id reference_id */
+ /* struct mpeg_content_labelling_descriptor_time_base time_base */
+ /* struct mpeg_content_labelling_descriptor_content_id content_id */
+ /* struct mpeg_content_labelling_descriptor_time_base_association time_base_assoc */
+ /* uint8_t private_data[] */
+} __ucsi_packed;
+
+/**
+ * id field of a content_labelling_descriptor.
+ */
+struct mpeg_content_labelling_descriptor_application_format_identifier {
+ uint32_t id;
+} __ucsi_packed;
+
+/**
+ * Flags field of a content_labelling_descriptor
+ */
+struct mpeg_content_labelling_descriptor_flags {
+ EBIT3(uint8_t content_reference_id_record_flag : 1; ,
+ uint8_t content_time_base_indicator : 4; ,
+ uint8_t reserved : 3; );
+} __ucsi_packed;
+
+/**
+ * Reference_id field of a content_labelling_descriptor.
+ */
+struct mpeg_content_labelling_descriptor_reference_id {
+ uint8_t content_reference_id_record_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * time_base field of a content_labelling_descriptor.
+ */
+struct mpeg_content_labelling_descriptor_time_base {
+ EBIT2(uint64_t reserved_1 : 7; ,
+ uint64_t content_time_base_value :33; );
+ EBIT2(uint64_t reserved_2 : 7; ,
+ uint64_t metadata_time_base_value :33; );
+} __ucsi_packed;
+
+/**
+ * content_id field of a content_labelling_descriptor.
+ */
+struct mpeg_content_labelling_descriptor_content_id {
+ EBIT2(uint8_t reserved : 1; ,
+ uint8_t contentId : 7; );
+} __ucsi_packed;
+
+/**
+ * time_base_assoc field of a content_labelling_descriptor.
+ */
+struct mpeg_content_labelling_descriptor_time_base_association {
+ uint8_t time_base_association_data_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+
+
+/**
+ * Process an mpeg_content_labelling_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return Pointer to an mpeg_content_labelling_descriptor, or NULL on error.
+ */
+static inline struct mpeg_content_labelling_descriptor*
+ mpeg_content_labelling_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 2;
+ uint8_t *buf = (uint8_t*) d;
+ uint32_t len = d->len + 2;
+ struct mpeg_content_labelling_descriptor_flags *flags;
+ int id;
+
+ if (len < sizeof(struct mpeg_content_labelling_descriptor))
+ return NULL;
+
+ bswap16(buf + pos);
+ id = *((uint16_t*) (buf+pos));
+ pos += 2;
+
+ if (id == 0xffff) {
+ if (len < (pos+4))
+ return NULL;
+ bswap32(buf+pos);
+ pos += 4;
+ }
+
+ if (len < (pos + sizeof(struct mpeg_content_labelling_descriptor_flags)))
+ return NULL;
+ flags = (struct mpeg_content_labelling_descriptor_flags*) (buf+pos);
+ pos += sizeof(struct mpeg_content_labelling_descriptor_flags);
+
+ if (flags->content_reference_id_record_flag == 1) {
+ if (len < (pos+1))
+ return NULL;
+ if (len < (pos+1+buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ }
+
+ if ((flags->content_time_base_indicator == 1) ||
+ (flags->content_time_base_indicator == 2)) {
+ if (len < (pos + sizeof(struct mpeg_content_labelling_descriptor_time_base)))
+ return NULL;
+ bswap40(buf+pos);
+ bswap40(buf+pos+5);
+ pos += sizeof(struct mpeg_content_labelling_descriptor_time_base);
+ }
+
+ if (flags->content_time_base_indicator == 2) {
+ if (len < (pos + sizeof(struct mpeg_content_labelling_descriptor_content_id)))
+ return NULL;
+ pos += sizeof(struct mpeg_content_labelling_descriptor_content_id);
+ }
+
+ if (flags->content_time_base_indicator > 2) {
+ if (len < (pos+1))
+ return NULL;
+ if (len < (pos+1+buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ }
+
+ if (len < pos)
+ return NULL;
+
+ return (struct mpeg_content_labelling_descriptor*) d;
+}
+
+/**
+ * Accessor for pointer to id field of an mpeg_content_labelling_descriptor.
+ *
+ * @param d The mpeg_content_labelling_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline struct mpeg_content_labelling_descriptor_application_format_identifier*
+ mpeg_content_labelling_descriptor_id(struct mpeg_content_labelling_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d;
+
+ if (d->metadata_application_format != 0xffff)
+ return NULL;
+ return (struct mpeg_content_labelling_descriptor_application_format_identifier*)
+ (buf + sizeof(struct mpeg_content_labelling_descriptor));
+}
+
+/**
+ * Accessor for pointer to flags field of an mpeg_content_labelling_descriptor.
+ *
+ * @param d The mpeg_content_labelling_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline struct mpeg_content_labelling_descriptor_flags*
+ mpeg_content_labelling_descriptor_flags(struct mpeg_content_labelling_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_content_labelling_descriptor);
+
+ if (d->metadata_application_format != 0xffff)
+ buf += 4;
+
+ return (struct mpeg_content_labelling_descriptor_flags *) buf;
+}
+
+/**
+ * Accessor for reference_id field of an mpeg_content_labelling_descriptor.
+ *
+ * @param flags Pointer to the mpeg_content_labelling_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_content_labelling_descriptor_reference_id*
+ mpeg_content_labelling_descriptor_reference_id(struct mpeg_content_labelling_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags);
+
+ if (flags->content_reference_id_record_flag != 1)
+ return NULL;
+
+ return (struct mpeg_content_labelling_descriptor_reference_id *) buf;
+}
+
+/**
+ * Accessor for data field of an mpeg_content_reference_id.
+ *
+ * @param d The mpeg_content_reference_id structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_content_reference_id_data(struct mpeg_content_labelling_descriptor_reference_id *d)
+{
+ return (uint8_t*) d + sizeof(struct mpeg_content_labelling_descriptor_reference_id);
+}
+
+/**
+ * Accessor for time_base field of an mpeg_content_labelling_descriptor.
+ *
+ * @param flags Pointer to the mpeg_content_labelling_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_content_labelling_descriptor_time_base*
+ mpeg_content_labelling_descriptor_time_base(struct mpeg_content_labelling_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags);
+
+ if ((flags->content_time_base_indicator!=1) && (flags->content_time_base_indicator!=2))
+ return NULL;
+
+ if (flags->content_reference_id_record_flag == 1)
+ buf += 1 + buf[1];
+
+ return (struct mpeg_content_labelling_descriptor_time_base *) buf;
+}
+
+/**
+ * Accessor for content_id field of an mpeg_content_labelling_descriptor.
+ *
+ * @param flags Pointer to the mpeg_content_labelling_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_content_labelling_descriptor_content_id*
+ mpeg_content_labelling_descriptor_content_id(struct mpeg_content_labelling_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags);
+
+ if (flags->content_time_base_indicator!=2)
+ return NULL;
+
+ if (flags->content_reference_id_record_flag == 1)
+ buf += 1 + buf[1];
+ if ((flags->content_time_base_indicator==1) || (flags->content_time_base_indicator==2))
+ buf += sizeof(struct mpeg_content_labelling_descriptor_time_base);
+
+ return (struct mpeg_content_labelling_descriptor_content_id *) buf;
+}
+
+/**
+ * Accessor for time_base_association field of an mpeg_content_labelling_descriptor.
+ *
+ * @param flags Pointer to the mpeg_content_labelling_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_content_labelling_descriptor_time_base_association*
+ mpeg_content_labelling_descriptor_time_base_assoc(struct mpeg_content_labelling_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags);
+
+ if (flags->content_time_base_indicator<3)
+ return NULL;
+
+ if (flags->content_reference_id_record_flag == 1)
+ buf += 1 + buf[1];
+ if ((flags->content_time_base_indicator==1) || (flags->content_time_base_indicator==2))
+ buf += sizeof(struct mpeg_content_labelling_descriptor_time_base);
+ if (flags->content_time_base_indicator==2)
+ buf += sizeof(struct mpeg_content_labelling_descriptor_content_id);
+
+ return (struct mpeg_content_labelling_descriptor_time_base_association *) buf;
+}
+
+/**
+ * Accessor for data field of an mpeg_time_base_association.
+ *
+ * @param d The mpeg_time_base_association structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_time_base_association_data(struct mpeg_content_labelling_descriptor_time_base_association *d)
+{
+ return (uint8_t*) d + sizeof(struct mpeg_content_labelling_descriptor_time_base_association);
+}
+
+
+/**
+ * Accessor for private_data field of an mpeg_content_labelling_descriptor.
+ *
+ * @param d The mpeg_content_labelling_descriptor structure.
+ * @param flags Pointer to the mpeg_content_labelling_descriptor_flags.
+ * @param length Where the number of bytes in the field should be stored.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_content_labelling_descriptor_data(struct mpeg_content_labelling_descriptor *d,
+ struct mpeg_content_labelling_descriptor_flags *flags,
+ int *length)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_content_labelling_descriptor_flags);
+ uint8_t *end = (uint8_t*) d + d->d.len + 2;
+
+ if (flags->content_reference_id_record_flag == 1)
+ buf += 1 + buf[1];
+ if ((flags->content_time_base_indicator==1) || (flags->content_time_base_indicator==2))
+ buf += sizeof(struct mpeg_content_labelling_descriptor_time_base);
+ if (flags->content_time_base_indicator==2)
+ buf += sizeof(struct mpeg_content_labelling_descriptor_content_id);
+ if (flags->content_time_base_indicator<3)
+ buf += 1 + buf[1];
+
+ *length = end - buf;
+
+ return buf;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/copyright_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/copyright_descriptor.h
new file mode 100644
index 0000000..5991fe9
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/copyright_descriptor.h
@@ -0,0 +1,89 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_COPYRIGHT_DESCRIPTOR
+#define _UCSI_MPEG_COPYRIGHT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_copyright_descriptor structure.
+ */
+struct mpeg_copyright_descriptor {
+ struct descriptor d;
+
+ uint32_t copyright_identifier;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_copyright_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return mpeg_copyright_descriptor pointer, or NULL on error.
+ */
+static inline struct mpeg_copyright_descriptor*
+ mpeg_copyright_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct mpeg_copyright_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+
+ return (struct mpeg_copyright_descriptor*) d;
+}
+
+/**
+ * Retrieve pointer to data field of an mpeg_copyright_descriptor.
+ *
+ * @param d mpeg_copyright_descriptor pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ mpeg_copyright_descriptor_data(struct mpeg_copyright_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct mpeg_copyright_descriptor);
+}
+
+
+/**
+ * Determine length of the data field of an mpeg_copyright_descriptor.
+ *
+ * @param d mpeg_copyright_descriptor pointer.
+ * @return Length of field in bytes.
+ */
+static inline int
+ mpeg_copyright_descriptor_data_length(struct mpeg_copyright_descriptor *d)
+{
+ return d->d.len - 4;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/data_stream_alignment_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/data_stream_alignment_descriptor.h
new file mode 100644
index 0000000..887495f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/data_stream_alignment_descriptor.h
@@ -0,0 +1,73 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_DATA_STREAM_ALIGNMENT_DESCRIPTOR
+#define _UCSI_MPEG_DATA_STREAM_ALIGNMENT_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for alignment_type.
+ */
+enum {
+ MPEG_DATA_STREAM_ALIGNMENT_VIDEO_SLICE_OR_AU = 0x01,
+ MPEG_DATA_STREAM_ALIGNMENT_VIDEO_AU = 0x02,
+ MPEG_DATA_STREAM_ALIGNMENT_VIDEO_GOP_OR_SEQ = 0x03,
+ MPEG_DATA_STREAM_ALIGNMENT_VIDEO_SEQ = 0x04,
+
+ MPEG_DATA_STREAM_ALIGNMENT_AUDIO_SYNC_WORD = 0x01,
+};
+
+/**
+ * mpeg_data_stream_alignment_descriptor structure.
+ */
+struct mpeg_data_stream_alignment_descriptor {
+ struct descriptor d;
+
+ uint8_t alignment_type;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_data_stream_alignment_descriptor.
+ *
+ * @param d Pointer to generic descriptor structure.
+ * @return Pointer to mpeg_data_stream_alignment_descriptor, or NULL on error.
+ */
+static inline struct mpeg_data_stream_alignment_descriptor*
+ mpeg_data_stream_alignment_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_data_stream_alignment_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg_data_stream_alignment_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/descriptor.h
new file mode 100644
index 0000000..c32775f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/descriptor.h
@@ -0,0 +1,102 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_DESCRIPTOR_H
+#define _UCSI_MPEG_DESCRIPTOR_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/mpeg/mpeg4_audio_descriptor.h>
+#include <libucsi/mpeg/mpeg4_video_descriptor.h>
+#include <libucsi/mpeg/audio_stream_descriptor.h>
+#include <libucsi/mpeg/ca_descriptor.h>
+#include <libucsi/mpeg/content_labelling_descriptor.h>
+#include <libucsi/mpeg/copyright_descriptor.h>
+#include <libucsi/mpeg/data_stream_alignment_descriptor.h>
+#include <libucsi/mpeg/external_es_id_descriptor.h>
+#include <libucsi/mpeg/fmc_descriptor.h>
+#include <libucsi/mpeg/fmxbuffer_size_descriptor.h>
+#include <libucsi/mpeg/hierarchy_descriptor.h>
+#include <libucsi/mpeg/ibp_descriptor.h>
+#include <libucsi/mpeg/iod_descriptor.h>
+#include <libucsi/mpeg/iso_639_language_descriptor.h>
+#include <libucsi/mpeg/maximum_bitrate_descriptor.h>
+#include <libucsi/mpeg/metadata_descriptor.h>
+#include <libucsi/mpeg/metadata_pointer_descriptor.h>
+#include <libucsi/mpeg/metadata_std_descriptor.h>
+#include <libucsi/mpeg/multiplex_buffer_descriptor.h>
+#include <libucsi/mpeg/multiplex_buffer_utilization_descriptor.h>
+#include <libucsi/mpeg/muxcode_descriptor.h>
+#include <libucsi/mpeg/private_data_indicator_descriptor.h>
+#include <libucsi/mpeg/registration_descriptor.h>
+#include <libucsi/mpeg/sl_descriptor.h>
+#include <libucsi/mpeg/smoothing_buffer_descriptor.h>
+#include <libucsi/mpeg/std_descriptor.h>
+#include <libucsi/mpeg/system_clock_descriptor.h>
+#include <libucsi/mpeg/target_background_grid_descriptor.h>
+#include <libucsi/mpeg/video_stream_descriptor.h>
+#include <libucsi/mpeg/video_window_descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Enumeration of MPEG descriptor tags.
+ */
+enum mpeg_descriptor_tag {
+ dtag_mpeg_video_stream = 0x02,
+ dtag_mpeg_audio_stream = 0x03,
+ dtag_mpeg_hierarchy = 0x04,
+ dtag_mpeg_registration = 0x05,
+ dtag_mpeg_data_stream_alignment = 0x06,
+ dtag_mpeg_target_background_grid = 0x07,
+ dtag_mpeg_video_window = 0x08,
+ dtag_mpeg_ca = 0x09,
+ dtag_mpeg_iso_639_language = 0x0a,
+ dtag_mpeg_system_clock = 0x0b,
+ dtag_mpeg_multiplex_buffer_utilization = 0x0c,
+ dtag_mpeg_copyright = 0x0d,
+ dtag_mpeg_maximum_bitrate = 0x0e,
+ dtag_mpeg_private_data_indicator = 0x0f,
+ dtag_mpeg_smoothing_buffer = 0x10,
+ dtag_mpeg_std = 0x11,
+ dtag_mpeg_ibp = 0x12,
+ dtag_mpeg_4_video = 0x1b,
+ dtag_mpeg_4_audio = 0x1c,
+ dtag_mpeg_iod = 0x1d,
+ dtag_mpeg_sl = 0x1e,
+ dtag_mpeg_fmc = 0x1f,
+ dtag_mpeg_external_es_id = 0x20,
+ dtag_mpeg_muxcode = 0x21,
+ dtag_mpeg_fmxbuffer_size = 0x22,
+ dtag_mpeg_multiplex_buffer = 0x23,
+ dtag_mpeg_content_labelling = 0x24,
+ dtag_mpeg_metadata_pointer = 0x25,
+ dtag_mpeg_metadata = 0x26,
+ dtag_mpeg_metadata_std = 0x27,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/external_es_id_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/external_es_id_descriptor.h
new file mode 100644
index 0000000..3aa3237
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/external_es_id_descriptor.h
@@ -0,0 +1,63 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_EXTERNAL_ES_ID_DESCRIPTOR
+#define _UCSI_MPEG_EXTERNAL_ES_ID_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_external_es_id_descriptor structure.
+ */
+struct mpeg_external_es_id_descriptor {
+ struct descriptor d;
+
+ uint16_t external_es_id;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_external_es_id_descriptor structure.
+ *
+ * @param d Generic descriptor structure.
+ * @return mpeg_external_es_id_descriptor pointer, or NULL on error.
+ */
+static inline struct mpeg_external_es_id_descriptor*
+ mpeg_external_es_id_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_external_es_id_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+
+ return (struct mpeg_external_es_id_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmc_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmc_descriptor.h
new file mode 100644
index 0000000..5a5bed2
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmc_descriptor.h
@@ -0,0 +1,122 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_FMC_DESCRIPTOR
+#define _UCSI_MPEG_FMC_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_fmc_descriptor structure.
+ */
+struct mpeg_fmc_descriptor {
+ struct descriptor d;
+
+ /* struct mpeg_flex_mux muxes[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the muxes field of an mpeg_fmc_descriptor structure.
+ */
+struct mpeg_flex_mux {
+ uint16_t es_id;
+ uint8_t flex_mux_channel;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_fmc_descriptor structure.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to an mpeg_fmc_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_fmc_descriptor*
+ mpeg_fmc_descriptor_codec(struct descriptor* d)
+{
+ uint8_t* buf = (uint8_t*) d + 2;
+ int pos = 0;
+ int len = d->len;
+
+ if (len % sizeof(struct mpeg_flex_mux))
+ return NULL;
+
+ while(pos < len) {
+ bswap16(buf+pos);
+ pos += sizeof(struct mpeg_flex_mux);
+ }
+
+ return (struct mpeg_fmc_descriptor*) d;
+}
+
+/**
+ * Convenience iterator for the muxes field of an mpeg_fmc_descriptor structure.
+ *
+ * @param d Generic descriptor structure.
+ * @param pos Variable holding a pointer to the the current entry within the muxes field.
+ */
+#define mpeg_fmc_descriptor_muxes_for_each(d, pos) \
+ for ((pos) = mpeg_fmc_descriptor_muxes_first(d); \
+ (pos); \
+ (pos) = mpeg_fmc_descriptor_muxes_next(d, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct mpeg_flex_mux*
+ mpeg_fmc_descriptor_muxes_first(struct mpeg_fmc_descriptor *d)
+{
+ if (d->d.len < sizeof(struct mpeg_flex_mux))
+ return NULL;
+
+ return (struct mpeg_flex_mux *)
+ ((uint8_t*) d + sizeof(struct mpeg_fmc_descriptor));
+}
+
+static inline struct mpeg_flex_mux*
+ mpeg_fmc_descriptor_muxes_next(struct mpeg_fmc_descriptor *d,
+ struct mpeg_flex_mux *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct mpeg_flex_mux);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct mpeg_flex_mux *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmxbuffer_size_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmxbuffer_size_descriptor.h
new file mode 100644
index 0000000..74f643c
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/fmxbuffer_size_descriptor.h
@@ -0,0 +1,83 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_FMXBUFFER_SIZE_DESCRIPTOR
+#define _UCSI_MPEG_FMXBUFFER_SIZE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+
+/**
+ * mpeg_fmxbuffer_size_descriptor structure.
+ */
+struct mpeg_fmxbuffer_size_descriptor {
+ struct descriptor d;
+
+ /* uint8_t descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_fmxbuffer_size_descriptor structure.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ * @return Pointer to an mpeg_fmxbuffer_size_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_fmxbuffer_size_descriptor*
+ mpeg_fmxbuffer_size_descriptor_codec(struct descriptor* d)
+{
+ return (struct mpeg_fmxbuffer_size_descriptor*) d;
+}
+
+/**
+ * Retrieve pointer to descriptors field of mpeg_fmxbuffer_size_descriptor structure.
+ *
+ * @param d mpeg_fmxbuffer_size_descriptor structure pointer.
+ * @return Pointer to the descriptors.
+ */
+static inline uint8_t *
+ mpeg_fmxbuffer_size_descriptor_descriptors(struct mpeg_fmxbuffer_size_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct mpeg_fmxbuffer_size_descriptor);
+}
+
+/**
+ * Calculate the length of the descriptors field of an mpeg_fmxbuffer_size_descriptor structure.
+ *
+ * @param d mpeg_fmxbuffer_size_descriptor structure pointer.
+ * @return Length of descriptors in bytes.
+ */
+static inline int
+ mpeg_fmxbuffer_size_descriptor_descriptors_length(struct mpeg_fmxbuffer_size_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/hierarchy_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/hierarchy_descriptor.h
new file mode 100644
index 0000000..a38539d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/hierarchy_descriptor.h
@@ -0,0 +1,83 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_HIERARCHY_DESCRIPTOR
+#define _UCSI_MPEG_HIERARCHY_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Hierarchy type values.
+ */
+enum {
+ MPEG_HIERARCHY_TYPE_ISO13818_2_SPATIAL_SCALABILITY = 0x01,
+ MPEG_HIERARCHY_TYPE_ISO13818_2_SNR_SCALABILITY = 0x02,
+ MPEG_HIERARCHY_TYPE_ISO13818_2_TEMPORAL_SCALABILITY = 0x03,
+ MPEG_HIERARCHY_TYPE_ISO13818_2_DATA_PARTITIONING = 0x04,
+ MPEG_HIERARCHY_TYPE_ISO13818_3_EXTENSION_BITSTREAM = 0x05,
+ MPEG_HIERARCHY_TYPE_ISO13818_1_PRIVATE_BITSTREAM = 0x06,
+ MPEG_HIERARCHY_TYPE_ISO13818_2_MULTI_VIEW_PROFILE = 0x07,
+ MPEG_HIERARCHY_TYPE_BASE_LAYER = 0x0f,
+};
+
+
+/**
+ * mpeg_hierarchy_descriptor structure.
+ */
+struct mpeg_hierarchy_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t reserved_1 : 4; ,
+ uint8_t hierarchy_type : 4; );
+ EBIT2(uint8_t reserved_2 : 2; ,
+ uint8_t hierarchy_layer_index : 6; );
+ EBIT2(uint8_t reserved_3 : 2; ,
+ uint8_t hierarchy_embedded_layer_index : 6; );
+ EBIT2(uint8_t reserved_4 : 2; ,
+ uint8_t hierarchy_channel : 6; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_hierarchy_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to mpeg_hierarchy_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_hierarchy_descriptor*
+ mpeg_hierarchy_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_hierarchy_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg_hierarchy_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/ibp_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ibp_descriptor.h
new file mode 100644
index 0000000..e82780a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/ibp_descriptor.h
@@ -0,0 +1,65 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_IBP_DESCRIPTOR
+#define _UCSI_MPEG_IBP_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_ibp_descriptor structure.
+ */
+struct mpeg_ibp_descriptor {
+ struct descriptor d;
+
+ EBIT3(uint16_t closed_gop_flag : 1; ,
+ uint16_t identical_gop_flag : 1; ,
+ uint16_t max_gop_length : 14; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_ibp_descriptor structure.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to the mpeg_ibp_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_ibp_descriptor*
+ mpeg_ibp_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_ibp_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+
+ return (struct mpeg_ibp_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/iod_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iod_descriptor.h
new file mode 100644
index 0000000..61de153
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iod_descriptor.h
@@ -0,0 +1,87 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_IOD_DESCRIPTOR
+#define _UCSI_MPEG_IOD_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_iod_descriptor structure.
+ */
+struct mpeg_iod_descriptor {
+ struct descriptor d;
+
+ uint8_t scope_of_iod_label;
+ uint8_t iod_label;
+ /* uint8_t iod[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_iod_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to an mpeg_iod_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_iod_descriptor*
+ mpeg_iod_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct mpeg_iod_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg_iod_descriptor*) d;
+}
+
+/**
+ * Retrieve pointer to iod field of an mpeg_iod_descriptor structure.
+ *
+ * @param d Pointer to mpeg_iod_descriptor structure.
+ * @return Pointer to the iod field.
+ */
+static inline uint8_t *
+ mpeg_iod_descriptor_iod(struct mpeg_iod_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct mpeg_iod_descriptor);
+}
+
+/**
+ * Calculate the length of the iod field of an mpeg_iod_descriptor structure.
+ *
+ * @param d Pointer to mpeg_iod_descriptor structure.
+ * @return The number of bytes.
+ */
+static inline int
+ mpeg_iod_descriptor_iod_length(struct mpeg_iod_descriptor *d)
+{
+ return d->d.len - 2;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/iso_639_language_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iso_639_language_descriptor.h
new file mode 100644
index 0000000..5b5aac0
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/iso_639_language_descriptor.h
@@ -0,0 +1,124 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_ISO_639_LANGUAGE_DESCRIPTOR
+#define _UCSI_MPEG_ISO_639_LANGUAGE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+#include <libucsi/types.h>
+
+/**
+ * Possible values for audio_type.
+ */
+enum {
+ MPEG_AUDIO_TYPE_CLEAN_EFFECTS = 0x01,
+ MPEG_AUDIO_TYPE_HEARING_IMPAIRED = 0x02,
+ MPEG_AUDIO_TYPE_VISUAL_IMPAIRED_COMMENTARY = 0x03,
+};
+
+/**
+ * mpeg_iso_639_language_descriptor structure.
+ */
+struct mpeg_iso_639_language_descriptor {
+ struct descriptor d;
+
+ /* struct mpeg_iso_639_language_code languages[] */
+} __ucsi_packed;
+
+/**
+ * An entry in the mpeg_iso_639_language_descriptor languages field.
+ */
+struct mpeg_iso_639_language_code {
+ iso639lang_t language_code;
+ uint8_t audio_type;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_iso_639_language_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to an mpeg_iso_639_language_descriptor structure, or NULL
+ * on error.
+ */
+static inline struct mpeg_iso_639_language_descriptor*
+ mpeg_iso_639_language_descriptor_codec(struct descriptor* d)
+{
+ if (d->len % sizeof(struct mpeg_iso_639_language_code))
+ return NULL;
+
+ return (struct mpeg_iso_639_language_descriptor*) d;
+}
+
+/**
+ * Convenience iterator for the languages field of an mpeg_iso_639_language_descriptor
+ *
+ * @param d Pointer to the mpeg_iso_639_language_descriptor structure.
+ * @param pos Variable holding a pointer to the current entry.
+ */
+#define mpeg_iso_639_language_descriptor_languages_for_each(_d, _pos) \
+ for ((_pos) = mpeg_iso_639_language_descriptor_languages_first(_d); \
+ (_pos); \
+ (_pos) = mpeg_iso_639_language_descriptor_languages_next(_d, _pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct mpeg_iso_639_language_code*
+ mpeg_iso_639_language_descriptor_languages_first(struct mpeg_iso_639_language_descriptor *d)
+{
+ if (d->d.len < sizeof(struct mpeg_iso_639_language_code))
+ return NULL;
+
+ return (struct mpeg_iso_639_language_code *)
+ ((uint8_t*) d + sizeof(struct mpeg_iso_639_language_descriptor));
+}
+
+static inline struct mpeg_iso_639_language_code*
+ mpeg_iso_639_language_descriptor_languages_next(struct mpeg_iso_639_language_descriptor *d,
+ struct mpeg_iso_639_language_code *pos)
+{
+ uint8_t *end = (uint8_t*) d + 2 + d->d.len;
+ uint8_t *next = (uint8_t *) pos + sizeof(struct mpeg_iso_639_language_code);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct mpeg_iso_639_language_code *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/maximum_bitrate_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/maximum_bitrate_descriptor.h
new file mode 100644
index 0000000..e0bcddb
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/maximum_bitrate_descriptor.h
@@ -0,0 +1,64 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_MAXIMUM_BITRATE_DESCRIPTOR
+#define _UCSI_MPEG_MAXIMUM_BITRATE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_maximum_bitrate_descriptor structure.
+ */
+struct mpeg_maximum_bitrate_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint32_t reserved : 2; ,
+ uint32_t maximum_bitrate : 22; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_maximum_bitrate_descriptor.
+ *
+ * @param d Pointer to generic descriptor structure.
+ * @return Pointer to mpeg_maximum_bitrate_descriptor, or NULL on error.
+ */
+static inline struct mpeg_maximum_bitrate_descriptor*
+ mpeg_maximum_bitrate_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_maximum_bitrate_descriptor) - 2))
+ return NULL;
+
+ bswap24((uint8_t*) d + 2);
+
+ return (struct mpeg_maximum_bitrate_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_descriptor.h
new file mode 100644
index 0000000..5b91e05
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_descriptor.h
@@ -0,0 +1,472 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_METADATA_DESCRIPTOR
+#define _UCSI_MPEG_METADATA_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Values for the decoder_config_flags field.
+ */
+enum {
+ MPEG_DECODER_CONFIG_NONE = 0x00,
+ MPEG_DECODER_CONFIG_IN_DECODER_CONFIG = 0x01,
+ MPEG_DECODER_CONFIG_SAME_METADATA_SERVICE = 0x02,
+ MPEG_DECODER_CONFIG_DSMCC = 0x03,
+ MPEG_DECODER_CONFIG_SAME_PROGRAM = 0x04,
+};
+
+/**
+ * mpeg_metadata_descriptor structure.
+ */
+struct mpeg_metadata_descriptor {
+ struct descriptor d;
+
+ uint16_t metadata_application_format;
+ /* struct mpeg_metadata_descriptor_application_format_identifier appid */
+ /* uint8_t metadata_format */
+ /* struct mpeg_metadata_descriptor_format_identifier formid */
+ /* struct mpeg_metadata_descriptor_flags flags */
+ /* struct mpeg_metadata_descriptor_service_identifier service_identifier */
+ /* struct mpeg_metadata_descriptor_decoder_config decoder_config */
+ /* struct mpeg_metadata_descriptor_decoder_config_id_record decoder_config_id_record */
+ /* struct mpeg_metadata_descriptor_decoder_config_service_id decoder_config_service_id */
+ /* struct mpeg_metadata_descriptor_decoder_config_reserved decoder_config_reserved */
+ /* uint8_t private_data[] */
+} __ucsi_packed;
+
+/**
+ * appid field of a metadata_descriptor.
+ */
+struct mpeg_metadata_descriptor_application_format_identifier {
+ uint32_t id;
+} __ucsi_packed;
+
+/**
+ * formid field of a metadata_descriptor.
+ */
+struct mpeg_metadata_descriptor_format_identifier {
+ uint32_t id;
+} __ucsi_packed;
+
+/**
+ * Flags field of a metadata_descriptor
+ */
+struct mpeg_metadata_descriptor_flags {
+ uint8_t metadata_service_id;
+ EBIT3(uint8_t decoder_config_flags : 3; ,
+ uint8_t dsm_cc_flag : 1; ,
+ uint8_t reserved : 4; );
+} __ucsi_packed;
+
+/**
+ * service_identifier field of a metadata_descriptor.
+ */
+struct mpeg_metadata_descriptor_service_identifier {
+ uint8_t service_identification_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * decoder_config field of a metadata_descriptor.
+ */
+struct mpeg_metadata_descriptor_decoder_config {
+ uint8_t decoder_config_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * decoder_config_id_record field of a metadata_descriptor.
+ */
+struct mpeg_metadata_descriptor_decoder_config_id_record {
+ uint8_t decoder_config_id_record_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * decoder_config_service_id field of a metadata_descriptor.
+ */
+struct mpeg_metadata_descriptor_decoder_config_service_id {
+ uint8_t decoder_config_metadata_service_id;
+} __ucsi_packed;
+
+/**
+ * decoder_config_reserved field of a metadata_descriptor.
+ */
+struct mpeg_metadata_descriptor_decoder_config_reserved {
+ uint8_t reserved_data_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+
+
+
+/**
+ * Process an mpeg_metadata_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return Pointer to an mpeg_metadata_descriptor, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor*
+ mpeg_metadata_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 2;
+ uint8_t *buf = (uint8_t*) d;
+ uint32_t len = d->len + 2;
+ struct mpeg_metadata_descriptor_flags *flags;
+ int id;
+
+ if (len < sizeof(struct mpeg_metadata_descriptor))
+ return NULL;
+
+ bswap16(buf + pos);
+ id = *((uint16_t*) (buf+pos));
+ pos += 2;
+
+ if (id == 0xffff) {
+ if (len < (pos+4))
+ return NULL;
+ bswap32(buf+pos);
+ pos += 4;
+ }
+
+ if (len < (pos+1))
+ return NULL;
+
+ id = buf[pos];
+ pos++;
+ if (id == 0xff) {
+ if (len < (pos+4))
+ return NULL;
+ bswap32(buf+pos);
+ pos += 4;
+ }
+
+ if (len < (pos + sizeof(struct mpeg_metadata_descriptor_flags)))
+ return NULL;
+ flags = (struct mpeg_metadata_descriptor_flags*) (buf+pos);
+ pos += sizeof(struct mpeg_metadata_descriptor_flags);
+
+ if (flags->dsm_cc_flag == 1) {
+ if (len < (pos+1))
+ return NULL;
+ if (len < (pos+1+buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ }
+
+ if (flags->decoder_config_flags == 1) {
+ if (len < (pos+1))
+ return NULL;
+ if (len < (pos+1+buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ }
+
+ if (flags->decoder_config_flags == 3) {
+ if (len < (pos+1))
+ return NULL;
+ if (len < (pos+1+buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ }
+
+ if (flags->decoder_config_flags == 4) {
+ if (len < (pos+1))
+ return NULL;
+ pos++;
+ }
+
+ if ((flags->decoder_config_flags == 5) ||
+ (flags->decoder_config_flags == 6)) {
+ if (len < (pos+1))
+ return NULL;
+ if (len < (pos+1+buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ }
+
+ if (len < pos)
+ return NULL;
+
+ return (struct mpeg_metadata_descriptor*) d;
+}
+
+/**
+ * Accessor for pointer to appid field of an mpeg_metadata_descriptor.
+ *
+ * @param d The mpeg_metadata_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_application_format_identifier*
+ mpeg_metadata_descriptor_appid(struct mpeg_metadata_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor);
+
+ if (d->metadata_application_format != 0xffff)
+ return NULL;
+ return (struct mpeg_metadata_descriptor_application_format_identifier*) buf;
+}
+
+/**
+ * Accessor for metadata_format field of an mpeg_metadata_descriptor.
+ *
+ * @param d The mpeg_metadata_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline uint8_t
+ mpeg_metadata_descriptor_metadata_format(struct mpeg_metadata_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor);
+
+ if (d->metadata_application_format == 0xffff)
+ buf+=4;
+ return *buf;
+}
+
+/**
+ * Accessor for pointer to formid field of an mpeg_metadata_descriptor.
+ *
+ * @param d The mpeg_metadata_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_format_identifier*
+ mpeg_metadata_descriptor_formid(struct mpeg_metadata_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor);
+
+ if (d->metadata_application_format == 0xffff)
+ buf+=4;
+ if (*buf != 0xff)
+ return NULL;
+
+ return (struct mpeg_metadata_descriptor_format_identifier*) (buf+1);
+}
+
+/**
+ * Accessor for flags field of an mpeg_metadata_descriptor.
+ *
+ * @param d The mpeg_metadata_descriptor structure.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_flags*
+ mpeg_metadata_descriptor_flags(struct mpeg_metadata_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor);
+
+ if (d->metadata_application_format == 0xffff)
+ buf+=4;
+ if (*buf == 0xff)
+ buf+=4;
+
+ return (struct mpeg_metadata_descriptor_flags*) buf;
+}
+
+
+/**
+ * Accessor for service_identifier field of an mpeg_metadata_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_service_identifier*
+ mpeg_metadata_descriptor_sevice_identifier(struct mpeg_metadata_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags);
+
+ if (flags->dsm_cc_flag!=1)
+ return NULL;
+
+ return (struct mpeg_metadata_descriptor_service_identifier *) buf;
+}
+
+/**
+ * Accessor for data field of an mpeg_metadata_descriptor_service_identifier.
+ *
+ * @param d The mpeg_metadata_descriptor_service_identifier structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_metadata_descriptor_service_identifier_data(struct mpeg_metadata_descriptor_service_identifier *d)
+{
+ return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_service_identifier);
+}
+
+/**
+ * Accessor for decoder_config field of an mpeg_metadata_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_decoder_config*
+ mpeg_metadata_descriptor_decoder_config(struct mpeg_metadata_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags);
+
+ if (flags->decoder_config_flags != 1)
+ return NULL;
+
+ if (flags->dsm_cc_flag==1)
+ buf += 1 + buf[1];
+
+ return (struct mpeg_metadata_descriptor_decoder_config*) buf;
+}
+
+/**
+ * Accessor for data field of an mpeg_metadata_descriptor_service_identifier.
+ *
+ * @param d The mpeg_metadata_descriptor_service_identifier structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_metadata_descriptor_decoder_config_data(struct mpeg_metadata_descriptor_decoder_config *d)
+{
+ return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_decoder_config);
+}
+
+/**
+ * Accessor for decoder_config_id_record field of an mpeg_metadata_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_decoder_config_id_record*
+ mpeg_metadata_descriptor_decoder_config_id_record(struct mpeg_metadata_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags);
+
+ if (flags->decoder_config_flags != 3)
+ return NULL;
+
+ if (flags->dsm_cc_flag==1)
+ buf += 1 + buf[1];
+
+ return (struct mpeg_metadata_descriptor_decoder_config_id_record *) buf;
+}
+
+/**
+ * Accessor for data field of an mpeg_metadata_descriptor_decoder_config_id_record.
+ *
+ * @param d The mpeg_metadata_descriptor_decoder_config_id_record structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_metadata_descriptor_decoder_config_id_record_data(struct mpeg_metadata_descriptor_decoder_config_id_record *d)
+{
+ return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_decoder_config_id_record);
+}
+
+/**
+ * Accessor for decoder_config_service_id field of an mpeg_metadata_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_decoder_config_service_id*
+ mpeg_metadata_descriptor_decoder_config_service_id(struct mpeg_metadata_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags);
+
+ if (flags->decoder_config_flags != 4)
+ return NULL;
+
+ if (flags->dsm_cc_flag==1)
+ buf += 1 + buf[1];
+
+ return (struct mpeg_metadata_descriptor_decoder_config_service_id *) buf;
+}
+
+/**
+ * Accessor for decoder_config_reserved field of an mpeg_metadata_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_descriptor_decoder_config_reserved*
+ mpeg_metadata_descriptor_decoder_config_reserved(struct mpeg_metadata_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags);
+
+ if ((flags->decoder_config_flags != 5) && (flags->decoder_config_flags != 6))
+ return NULL;
+
+ if (flags->dsm_cc_flag==1)
+ buf += 1 + buf[1];
+
+ return (struct mpeg_metadata_descriptor_decoder_config_reserved *) buf;
+}
+
+/**
+ * Accessor for data field of an mpeg_metadata_descriptor_decoder_config_reserved.
+ *
+ * @param d The mpeg_metadata_descriptor_decoder_config_reserved structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_metadata_descriptor_decoder_config_reserved_data(struct mpeg_metadata_descriptor_decoder_config_reserved *d)
+{
+ return (uint8_t*) d + sizeof(struct mpeg_metadata_descriptor_decoder_config_reserved);
+}
+
+/**
+ * Accessor for private_data field of an mpeg_metadata_descriptor.
+ *
+ * @param d The mpeg_metadata_descriptor structure.
+ * @param flags Pointer to the mpeg_metadata_descriptor_flags.
+ * @param length Where the number of bytes in the field should be stored.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_metadata_descriptor_private_data(struct mpeg_metadata_descriptor *d,
+ struct mpeg_metadata_descriptor_flags *flags,
+ int *length)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_descriptor_flags);
+ uint8_t *end = (uint8_t*) d + d->d.len + 2;
+
+
+ if (flags->dsm_cc_flag==1)
+ buf += 1 + buf[1];
+ if (flags->decoder_config_flags==1)
+ buf += 1 + buf[1];
+ if (flags->decoder_config_flags==3)
+ buf += 1 + buf[1];
+ if (flags->decoder_config_flags==4)
+ buf++;
+ if ((flags->decoder_config_flags==5)||(flags->decoder_config_flags==6))
+ buf += 1 + buf[1];
+
+ *length = end - buf;
+ return buf;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_pointer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_pointer_descriptor.h
new file mode 100644
index 0000000..e4d7503
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_pointer_descriptor.h
@@ -0,0 +1,360 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_METADATA_POINTER_DESCRIPTOR
+#define _UCSI_MPEG_METADATA_POINTER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * Possible values for the mpeg_carriage_flags field.
+ */
+enum {
+ MPEG_CARRIAGE_SAME_TS = 0x00,
+ MPEG_CARRIAGE_DIFFERENT_TS = 0x01,
+ MPEG_CARRIAGE_PS = 0x02,
+ MPEG_CARRIAGE_OTHER = 0x03,
+};
+
+/**
+ * mpeg_metadata_pointer_descriptor structure.
+ */
+struct mpeg_metadata_pointer_descriptor {
+ struct descriptor d;
+
+ uint16_t metadata_application_format;
+ /* struct mpeg_metadata_pointer_descriptor_application_format_identifier appid */
+ /* uint8_t metadata_format */
+ /* struct mpeg_metadata_pointer_descriptor_format_identifier formid */
+ /* struct mpeg_metadata_pointer_descriptor_flags flags */
+ /* struct mpeg_metadata_pointer_descriptor_locator locator */
+ /* struct mpeg_metadata_pointer_descriptor_program_number program_number */
+ /* struct mpeg_metadata_pointer_descriptor_carriage carriage */
+ /* uint8_t private_data[] */
+} __ucsi_packed;
+
+/**
+ * appid field of a metadata_pointer_descriptor.
+ */
+struct mpeg_metadata_pointer_descriptor_application_format_identifier {
+ uint32_t id;
+} __ucsi_packed;
+
+/**
+ * formid field of a metadata_pointer_descriptor.
+ */
+struct mpeg_metadata_pointer_descriptor_format_identifier {
+ uint32_t id;
+} __ucsi_packed;
+
+/**
+ * Flags field of a metadata_pointer_descriptor
+ */
+struct mpeg_metadata_pointer_descriptor_flags {
+ uint8_t metadata_service_id;
+ EBIT3(uint8_t metadata_locator_record_flag : 1; ,
+ uint8_t mpeg_carriage_flags : 2; ,
+ uint8_t reserved : 5; );
+} __ucsi_packed;
+
+/**
+ * Reference_id field of a metadata_pointer_descriptor.
+ */
+struct mpeg_metadata_pointer_descriptor_locator {
+ uint8_t metadata_locator_record_length;
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * program_number field of a metadata_pointer_descriptor.
+ */
+struct mpeg_metadata_pointer_descriptor_program_number {
+ uint16_t number;
+} __ucsi_packed;
+
+/**
+ * carriage field of a metadata_pointer_descriptor.
+ */
+struct mpeg_metadata_pointer_descriptor_carriage {
+ uint16_t transport_stream_location;
+ uint16_t transport_stream_id;
+} __ucsi_packed;
+
+
+
+
+/**
+ * Process an mpeg_metadata_pointer_descriptor.
+ *
+ * @param d Generic descriptor.
+ * @return Pointer to an mpeg_metadata_pointer_descriptor, or NULL on error.
+ */
+static inline struct mpeg_metadata_pointer_descriptor*
+ mpeg_metadata_pointer_descriptor_codec(struct descriptor* d)
+{
+ uint32_t pos = 2;
+ uint8_t *buf = (uint8_t*) d;
+ uint32_t len = d->len + 2;
+ struct mpeg_metadata_pointer_descriptor_flags *flags;
+ int id;
+
+ if (len < sizeof(struct mpeg_metadata_pointer_descriptor))
+ return NULL;
+
+ bswap16(buf + pos);
+ id = *((uint16_t*) (buf+pos));
+ pos += 2;
+
+ if (id == 0xffff) {
+ if (len < (pos+4))
+ return NULL;
+ bswap32(buf+pos);
+ pos += 4;
+ }
+
+ if (len < (pos+1))
+ return NULL;
+
+ id = buf[pos];
+ pos++;
+ if (id == 0xff) {
+ if (len < (pos+4))
+ return NULL;
+ bswap32(buf+pos);
+ pos += 4;
+ }
+
+ if (len < (pos + sizeof(struct mpeg_metadata_pointer_descriptor_flags)))
+ return NULL;
+ flags = (struct mpeg_metadata_pointer_descriptor_flags*) (buf+pos);
+ pos += sizeof(struct mpeg_metadata_pointer_descriptor_flags);
+
+ if (flags->metadata_locator_record_flag == 1) {
+ if (len < (pos+1))
+ return NULL;
+ if (len < (pos+1+buf[pos]))
+ return NULL;
+ pos += 1 + buf[pos];
+ }
+
+ if (flags->mpeg_carriage_flags < 3) {
+ if (len < (pos + 2))
+ return NULL;
+ bswap16(buf+pos);
+ pos += 2;
+ }
+
+ if (flags->mpeg_carriage_flags == 1) {
+ if (len < (pos + 4))
+ return NULL;
+ bswap16(buf+pos);
+ bswap16(buf+pos+2);
+ pos += 4;
+ }
+
+ if (len < pos)
+ return NULL;
+
+ return (struct mpeg_metadata_pointer_descriptor*) d;
+}
+
+/**
+ * Accessor for pointer to appid field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param d The mpeg_metadata_pointer_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline struct mpeg_metadata_pointer_descriptor_application_format_identifier*
+ mpeg_metadata_pointer_descriptor_appid(struct mpeg_metadata_pointer_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor);
+
+ if (d->metadata_application_format != 0xffff)
+ return NULL;
+ return (struct mpeg_metadata_pointer_descriptor_application_format_identifier*) buf;
+}
+
+/**
+ * Accessor for metadata_format field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param d The mpeg_metadata_pointer_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline uint8_t
+ mpeg_metadata_pointer_descriptor_metadata_format(struct mpeg_metadata_pointer_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor);
+
+ if (d->metadata_application_format == 0xffff)
+ buf+=4;
+ return *buf;
+}
+
+/**
+ * Accessor for pointer to formid field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param d The mpeg_metadata_pointer_descriptor structure.
+ * @return The pointer, or NULL on error.
+ */
+static inline struct mpeg_metadata_pointer_descriptor_format_identifier*
+ mpeg_metadata_pointer_descriptor_formid(struct mpeg_metadata_pointer_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor);
+
+ if (d->metadata_application_format == 0xffff)
+ buf+=4;
+ if (*buf != 0xff)
+ return NULL;
+
+ return (struct mpeg_metadata_pointer_descriptor_format_identifier*) (buf+1);
+}
+
+/**
+ * Accessor for flags field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param d The mpeg_metadata_pointer_descriptor structure.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_pointer_descriptor_flags*
+ mpeg_metadata_pointer_descriptor_flags(struct mpeg_metadata_pointer_descriptor *d)
+{
+ uint8_t *buf = (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor);
+
+ if (d->metadata_application_format == 0xffff)
+ buf+=4;
+ if (*buf == 0xff)
+ buf+=4;
+
+ return (struct mpeg_metadata_pointer_descriptor_flags*) buf;
+}
+
+
+/**
+ * Accessor for locator field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_pointer_descriptor_locator*
+ mpeg_metadata_pointer_descriptor_locator(struct mpeg_metadata_pointer_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags);
+
+ if (flags->metadata_locator_record_flag!=1)
+ return NULL;
+
+ return (struct mpeg_metadata_pointer_descriptor_locator *) buf;
+}
+
+/**
+ * Accessor for data field of an mpeg_metadata_pointer_descriptor_locator.
+ *
+ * @param d The mpeg_metadata_pointer_descriptor_locator structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_metadata_pointer_descriptor_locator_data(struct mpeg_metadata_pointer_descriptor_locator *d)
+{
+ return (uint8_t*) d + sizeof(struct mpeg_metadata_pointer_descriptor_locator);
+}
+
+
+/**
+ * Accessor for program_number field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_pointer_descriptor_program_number*
+ mpeg_metadata_pointer_descriptor_program_number(struct mpeg_metadata_pointer_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags);
+
+ if (flags->mpeg_carriage_flags < 3)
+ return NULL;
+
+ if (flags->metadata_locator_record_flag==1)
+ buf += 1 + buf[1];
+
+ return (struct mpeg_metadata_pointer_descriptor_program_number*) buf;
+}
+
+/**
+ * Accessor for carriage field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags.
+ * @return Pointer to the field, or NULL on error.
+ */
+static inline struct mpeg_metadata_pointer_descriptor_carriage*
+ mpeg_metadata_pointer_descriptor_carriage(struct mpeg_metadata_pointer_descriptor_flags *flags)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags);
+
+ if (flags->mpeg_carriage_flags != 1)
+ return NULL;
+
+ if (flags->metadata_locator_record_flag==1)
+ buf += 1 + buf[1];
+ if (flags->mpeg_carriage_flags < 3)
+ buf += sizeof(struct mpeg_metadata_pointer_descriptor_program_number);
+
+ return (struct mpeg_metadata_pointer_descriptor_carriage *) buf;
+}
+
+/**
+ * Accessor for private_data field of an mpeg_metadata_pointer_descriptor.
+ *
+ * @param d The mpeg_metadata_pointer_descriptor structure.
+ * @param flags Pointer to the mpeg_metadata_pointer_descriptor_flags.
+ * @param length Where the number of bytes in the field should be stored.
+ * @return Pointer to the field.
+ */
+static inline uint8_t*
+ mpeg_metadata_pointer_descriptor_private_data(struct mpeg_metadata_pointer_descriptor *d,
+ struct mpeg_metadata_pointer_descriptor_flags *flags,
+ int *length)
+{
+ uint8_t *buf = (uint8_t*) flags + sizeof(struct mpeg_metadata_pointer_descriptor_flags);
+ uint8_t *end = (uint8_t*) d + d->d.len + 2;
+
+
+ if (flags->metadata_locator_record_flag==1)
+ buf += 1 + buf[1];
+ if (flags->mpeg_carriage_flags < 3)
+ buf += sizeof(struct mpeg_metadata_pointer_descriptor_program_number);
+ if (flags->mpeg_carriage_flags != 1)
+ buf += sizeof(struct mpeg_metadata_pointer_descriptor_carriage);
+
+ *length = end - buf;
+ return buf;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c
new file mode 100644
index 0000000..9af1d96
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.c
@@ -0,0 +1,28 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/mpeg/metadata_section.h>
+
+struct mpeg_metadata_section * mpeg_metadata_section_codec(struct section_ext * ext)
+{
+ return (struct mpeg_metadata_section *)ext;
+}
+
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.h
new file mode 100644
index 0000000..62c4e03
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_section.h
@@ -0,0 +1,122 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_METADATA_SECTION_H
+#define _UCSI_MPEG_METADATA_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * mpeg_metadata_section structure.
+ */
+struct mpeg_metadata_section {
+ struct section_ext head;
+
+ /* uint8_t data[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_metadata_section structure.
+ *
+ * @param section Pointer to the section_ext structure.
+ * @return Pointer to the mpeg_metadata_section structure, or NULL on error.
+ */
+extern struct mpeg_metadata_section *mpeg_metadata_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the random_access_indicator field of a metadata section.
+ *
+ * @param metadata metadata section pointer.
+ * @return The random_access_indicator.
+ */
+static inline uint8_t mpeg_metadata_section_random_access_indicator(struct mpeg_metadata_section *metadata)
+{
+ return metadata->head.reserved >> 1;
+}
+
+/**
+ * Accessor for the decoder_config_flag field of a metadata section.
+ *
+ * @param metadata metadata section pointer.
+ * @return The decoder_config_flag.
+ */
+static inline uint8_t mpeg_metadata_section_decoder_config_flag(struct mpeg_metadata_section *metadata)
+{
+ return metadata->head.reserved & 1;
+}
+
+/**
+ * Accessor for the fragment_indicator field of a metadata section.
+ *
+ * @param metadata metadata section pointer.
+ * @return The fragment_indicator.
+ */
+static inline uint8_t mpeg_metadata_section_fragment_indicator(struct mpeg_metadata_section *metadata)
+{
+ return metadata->head.reserved1;
+}
+
+/**
+ * Accessor for the service_id field of a metadata section.
+ *
+ * @param metadata metadata section pointer.
+ * @return The service_id.
+ */
+static inline uint16_t mpeg_metadata_section_service_id(struct mpeg_metadata_section *metadata)
+{
+ return metadata->head.table_id_ext >> 8;
+}
+
+/**
+ * Retrieve pointer to data field of an mpeg_metadata_section.
+ *
+ * @param s mpeg_metadata_section pointer.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ mpeg_metadata_section_data(struct mpeg_metadata_section *s)
+{
+ return (uint8_t *) s + sizeof(struct mpeg_metadata_section);
+}
+
+
+/**
+ * Determine length of the data field of an mpeg_copyright_descriptor.
+ *
+ * @param s mpeg_metadata_section_data pointer.
+ * @return Length of field in bytes.
+ */
+static inline int
+ mpeg_metadata_section_data_length(struct mpeg_metadata_section *s)
+{
+ return section_ext_length(&s->head) - sizeof(struct mpeg_metadata_section);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_std_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_std_descriptor.h
new file mode 100644
index 0000000..fc83e6e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/metadata_std_descriptor.h
@@ -0,0 +1,72 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_METADATA_STD_DESCRIPTOR
+#define _UCSI_MPEG_METADATA_STD_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_metadata_std_descriptor structure.
+ */
+struct mpeg_metadata_std_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint32_t reserved_1 : 2; ,
+ uint32_t metadata_input_leak_rate :22; );
+ EBIT2(uint32_t reserved_2 : 2; ,
+ uint32_t metadata_buffer_size :22; );
+ EBIT2(uint32_t reserved_3 : 2; ,
+ uint32_t metadata_output_leak_rate :22; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_metadata_std_descriptor.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_metadata_std_descriptor, or NULL on error.
+ */
+static inline struct mpeg_metadata_std_descriptor*
+ mpeg_metadata_std_descriptor_codec(struct descriptor* d)
+{
+ uint8_t *buf = (uint8_t*) d;
+
+ if (d->len != (sizeof(struct mpeg_metadata_std_descriptor) - 2))
+ return NULL;
+
+ bswap24(buf + 2);
+ bswap24(buf + 5);
+ bswap24(buf + 8);
+
+ return (struct mpeg_metadata_std_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_audio_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_audio_descriptor.h
new file mode 100644
index 0000000..f876759
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_audio_descriptor.h
@@ -0,0 +1,61 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG4_AUDIO_DESCRIPTOR
+#define _UCSI_MPEG4_AUDIO_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg4_audio_descriptor structure.
+ */
+struct mpeg4_audio_descriptor {
+ struct descriptor d;
+
+ uint8_t mpeg4_audio_profile_and_level;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg4_audio_descriptor.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to an mpeg4_audio_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg4_audio_descriptor*
+ mpeg4_audio_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg4_audio_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg4_audio_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_video_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_video_descriptor.h
new file mode 100644
index 0000000..b956b91
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/mpeg4_video_descriptor.h
@@ -0,0 +1,61 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG4_VIDEO_DESCRIPTOR
+#define _UCSI_MPEG4_VIDEO_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg4_video_descriptor structure.
+ */
+struct mpeg4_video_descriptor {
+ struct descriptor d;
+
+ uint8_t mpeg4_visual_profile_and_level;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg4_video_descriptor structure.
+ *
+ * @param d Pointer to generic descriptor structure.
+ * @return Pointer to mpeg4_video_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg4_video_descriptor*
+ mpeg4_video_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg4_video_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg4_video_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_descriptor.h
new file mode 100644
index 0000000..d55ce3d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_descriptor.h
@@ -0,0 +1,65 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_MULTIPLEX_BUFFER_DESCRIPTOR
+#define _UCSI_MPEG_MULTIPLEX_BUFFER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_multiplex_buffer_descriptor descriptor.
+ */
+struct mpeg_multiplex_buffer_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint64_t mb_buffer_size : 24; ,
+ uint64_t tb_leak_rate : 24; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_multiplex_buffer_descriptor.
+ *
+ * @param d Pointer to generic descriptor structure.
+ * @return Pointer to an mpeg_multiplex_buffer_descriptor structure, or NULL on
+ * error.
+ */
+static inline struct mpeg_multiplex_buffer_descriptor*
+ mpeg_multiplex_buffer_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_multiplex_buffer_descriptor) - 2))
+ return NULL;
+
+ bswap48((uint8_t*) d + 2);
+
+ return (struct mpeg_multiplex_buffer_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_utilization_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_utilization_descriptor.h
new file mode 100644
index 0000000..16550ed
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/multiplex_buffer_utilization_descriptor.h
@@ -0,0 +1,67 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_MULTIPLEX_BUFFER_UTILIZATION_DESCRIPTOR
+#define _UCSI_MPEG_MULTIPLEX_BUFFER_UTILIZATION_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_multiplex_buffer_utilization_descriptor structure.
+ */
+struct mpeg_multiplex_buffer_utilization_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint16_t bound_valid_flag : 1; ,
+ uint16_t ltw_offset_lower_bound : 15; );
+ EBIT2(uint16_t reserved : 1; ,
+ uint16_t ltw_offset_upper_bound : 15; );
+} __ucsi_packed;
+
+/**
+ * Process a mpeg_multiplex_buffer_utilization_descriptor.
+ *
+ * @param d Generic descriptor pointer.
+ * @return mpeg_multiplex_buffer_utilization_descriptor pointer, or NULL on error.
+ */
+static inline struct mpeg_multiplex_buffer_utilization_descriptor*
+ mpeg_multiplex_buffer_utilization_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_multiplex_buffer_utilization_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+ bswap16((uint8_t*) d + 4);
+
+ return (struct mpeg_multiplex_buffer_utilization_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/muxcode_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/muxcode_descriptor.h
new file mode 100644
index 0000000..6bed334
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/muxcode_descriptor.h
@@ -0,0 +1,82 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_MUXCODE_DESCRIPTOR
+#define _UCSI_MPEG_MUXCODE_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_muxcode_descriptor structure
+ */
+struct mpeg_muxcode_descriptor {
+ struct descriptor d;
+
+ /* uint8_t entries[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_muxcode_descriptor.
+ *
+ * @param d Pointer to a generic descriptor structure.
+ * @return Pointer to an mpeg_muxcode_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_muxcode_descriptor*
+ mpeg_muxcode_descriptor_codec(struct descriptor* d)
+{
+ return (struct mpeg_muxcode_descriptor*) d;
+}
+
+/**
+ * Retrieve pointer to entries field of an mpeg_muxcode_descriptor structure.
+ *
+ * @param d Generic descriptor structure.
+ * @return Pointer to the entries field.
+ */
+static inline uint8_t *
+ mpeg_muxcode_descriptor_entries(struct mpeg_muxcode_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct mpeg_muxcode_descriptor);
+}
+
+/**
+ * Determine length of entries field of an mpeg_muxcode_descriptor structure.
+ *
+ * @param d Generic descriptor structure.
+ * @return Number of bytes in the entries field.
+ */
+static inline int
+ mpeg_muxcode_descriptor_entries_length(struct mpeg_muxcode_descriptor *d)
+{
+ return d->d.len;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c
new file mode 100644
index 0000000..c56ccb1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.c
@@ -0,0 +1,80 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/mpeg/odsmt_section.h>
+
+struct mpeg_odsmt_section *mpeg_odsmt_section_codec(struct section_ext * ext)
+{
+ struct mpeg_odsmt_section * odsmt = (struct mpeg_odsmt_section *)ext;
+ uint8_t * buf = (uint8_t *)ext;
+ int pos = sizeof(struct section_ext);
+ int len = section_ext_length(ext);
+ int i;
+
+ if (len < sizeof(struct mpeg_odsmt_section))
+ return NULL;
+
+ pos++;
+
+ if (odsmt->stream_count == 0) {
+ struct mpeg_odsmt_stream * stream =
+ (struct mpeg_odsmt_stream *) (buf + pos);
+
+ if ((pos + sizeof(struct mpeg_odsmt_stream_single)) > len)
+ return NULL;
+
+ bswap16(buf+pos);
+ pos+=3;
+
+ if ((pos + stream->u.single.es_info_length) >= len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, stream->u.single.es_info_length))
+ return NULL;
+
+ pos += stream->u.single.es_info_length;
+ } else {
+ for (i=0; i< odsmt->stream_count; i++) {
+ struct mpeg_odsmt_stream * stream =
+ (struct mpeg_odsmt_stream *)(buf + pos);
+
+ if ((pos + sizeof(struct mpeg_odsmt_stream_multi)) > len)
+ return NULL;
+
+ bswap16(buf+pos);
+ pos += sizeof(struct mpeg_odsmt_stream_multi);
+
+ if ((pos + stream->u.multi.es_info_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos,
+ stream->u.multi.es_info_length))
+ return NULL;
+
+ pos += stream->u.multi.es_info_length;
+ }
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return (struct mpeg_odsmt_section *) ext;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h
new file mode 100644
index 0000000..2e5302d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/odsmt_section.h
@@ -0,0 +1,224 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_ODSMT_SECTION_H
+#define _UCSI_MPEG_ODSMT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * mpeg_odsmt_section structure.
+ */
+struct mpeg_odsmt_section {
+ struct section_ext head;
+
+ uint8_t stream_count;
+ /* stream_count==0 => struct mpeg_odsmt_stream_single streams
+ stream_count>0 => struct mpeg_odsmt_stream_multi streams[] */
+ /* uint8_t object_descriptors[] */
+} __ucsi_packed;
+
+struct mpeg_odsmt_stream_single
+{
+ uint16_t esid;
+ uint8_t es_info_length;
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+struct mpeg_odsmt_stream_multi
+{
+ uint16_t esid;
+ uint8_t fmc;
+ uint8_t es_info_length;
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Structure describing the stream information held in an mpeg_odsmt_section.
+ */
+struct mpeg_odsmt_stream {
+ union {
+ struct mpeg_odsmt_stream_single single __ucsi_packed;
+ struct mpeg_odsmt_stream_multi multi __ucsi_packed;
+ } u __ucsi_packed;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_odsmt_section.
+ *
+ * @param section Pointer to the generic section_ext structure.
+ * @return Pointer to a mpeg_odsmt_section structure, or NULL on error.
+ */
+extern struct mpeg_odsmt_section *mpeg_odsmt_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the PID field of an ODSMT.
+ *
+ * @param odsmt odsmt pointer.
+ * @return The pid.
+ */
+static inline uint16_t mpeg_odsmt_section_pid(struct mpeg_odsmt_section *odsmt)
+{
+ return odsmt->head.table_id_ext & 0x1fff;
+}
+
+/**
+ * Convenience iterator for the streams field of an mpeg_odsmt_section.
+ *
+ * @param osdmt Pointer to the mpeg_odsmt_section structure.
+ * @param pos Variable holding pointer to the current mpeg_odsmt_stream structure.
+ * @param index Variable holding the stream index.
+ */
+#define mpeg_odsmt_section_streams_for_each(osdmt, pos, index) \
+ for (index=0, (pos) = mpeg_odsmt_section_streams_first(odsmt); \
+ (pos); \
+ (pos) = mpeg_odsmt_section_streams_next(odsmt, pos, ++index))
+
+/**
+ * Convenience iterator for the descriptors field of an mpeg_odsmt_stream.
+ *
+ * @param osdmt Pointer to the mpeg_odsmt_section structure.
+ * @param stream Pointer to the mpeg_odsmt_stream structure.
+ * @param pos Variable holding pointer to the current descriptor structure.
+ */
+#define mpeg_odsmt_stream_descriptors_for_each(osdmt, stream, pos) \
+ for ((pos) = mpeg_odsmt_stream_descriptors_first(odsmt, stream); \
+ (pos); \
+ (pos) = mpeg_odsmt_stream_descriptors_next(odsmt, stream, pos))
+
+/**
+ * Retrieve a pointer to the object_descriptors field of an mpeg_odsmt_section.
+ *
+ * @param osdmt Pointer to the mpeg_odsmt_section structure.
+ * @param len On return, will contain the number of bytes in the object descriptors field.
+ * @return Pointer to the object_descriptors field, or NULL on error.
+ */
+static inline uint8_t*
+ mpeg_odsmt_section_object_descriptors(struct mpeg_odsmt_section * odsmt,
+ uint32_t* len);
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct mpeg_odsmt_stream *
+ mpeg_odsmt_section_streams_first(struct mpeg_odsmt_section *odsmt)
+{
+ int pos = sizeof(struct mpeg_odsmt_section);
+
+ if (pos >= section_ext_length(&odsmt->head))
+ return NULL;
+
+ return (struct mpeg_odsmt_stream *) ((uint8_t *) odsmt + pos);
+}
+
+static inline struct mpeg_odsmt_stream *
+ mpeg_odsmt_section_streams_next(struct mpeg_odsmt_section *odsmt,
+ struct mpeg_odsmt_stream *pos,
+ int index)
+{
+ uint8_t *end = (uint8_t*) odsmt + section_ext_length(&odsmt->head);
+ uint8_t *next;
+
+ if (index > odsmt->stream_count)
+ return NULL;
+
+ next = (uint8_t *) pos + sizeof(struct mpeg_odsmt_stream_multi) +
+ pos->u.multi.es_info_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct mpeg_odsmt_stream *) next;
+}
+
+static inline struct descriptor *
+ mpeg_odsmt_stream_descriptors_first(struct mpeg_odsmt_section *odsmt,
+ struct mpeg_odsmt_stream *stream)
+{
+ if (odsmt->stream_count == 0) {
+ if (stream->u.single.es_info_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t*) stream + sizeof(struct mpeg_odsmt_stream_single));
+ } else {
+ if (stream->u.multi.es_info_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t*) stream + sizeof(struct mpeg_odsmt_stream_multi));
+ }
+}
+
+static inline struct descriptor *
+ mpeg_odsmt_stream_descriptors_next(struct mpeg_odsmt_section *odsmt,
+ struct mpeg_odsmt_stream *stream,
+ struct descriptor* pos)
+{
+ if (odsmt->stream_count == 0) {
+ return next_descriptor((uint8_t *) stream + sizeof(struct mpeg_odsmt_stream_single),
+ stream->u.single.es_info_length,
+ pos);
+ } else {
+ return next_descriptor((uint8_t *) stream + sizeof(struct mpeg_odsmt_stream_multi),
+ stream->u.multi.es_info_length,
+ pos);
+ }
+}
+
+static inline uint8_t*
+ mpeg_odsmt_section_object_descriptors(struct mpeg_odsmt_section * odsmt,
+ uint32_t* len)
+{
+ struct mpeg_odsmt_stream* pos;
+ int size = sizeof(struct mpeg_odsmt_section);
+ int index;
+
+ mpeg_odsmt_section_streams_for_each(odsmt, pos, index) {
+ if (odsmt->stream_count == 0)
+ size += sizeof(struct mpeg_odsmt_stream_single) +
+ pos->u.single.es_info_length;
+ else
+ size += sizeof(struct mpeg_odsmt_stream_multi) +
+ pos->u.multi.es_info_length;
+ }
+
+ *len = section_ext_length(&odsmt->head) - size;
+ return (uint8_t*) odsmt + size;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c
new file mode 100644
index 0000000..80b28d5
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.c
@@ -0,0 +1,46 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/mpeg/pat_section.h>
+
+struct mpeg_pat_section *mpeg_pat_section_codec(struct section_ext * ext)
+{
+ uint8_t *buf = (uint8_t *)ext;
+ int pos = sizeof(struct section_ext);
+ int len = section_ext_length(ext);
+
+ if (len < sizeof(struct mpeg_pat_section))
+ return NULL;
+
+ while (pos < len) {
+ if ((pos + 4) > len)
+ return NULL;
+
+ bswap16(buf + pos);
+ bswap16(buf + pos + 2);
+ pos += 4;
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return (struct mpeg_pat_section *)ext;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h
new file mode 100644
index 0000000..20b3f7a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pat_section.h
@@ -0,0 +1,118 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_PAT_SECTION_H
+#define _UCSI_MPEG_PAT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * mpeg_pat_section structure.
+ */
+struct mpeg_pat_section {
+ struct section_ext head; /* table_id_ext == transport_stream_id */
+
+ /* struct mpeg_pat_program programs[] */
+} __ucsi_packed;
+
+/**
+ * A program within an mpeg_pat_section.
+ */
+struct mpeg_pat_program {
+ uint16_t program_number;
+ EBIT2(uint16_t reserved : 3; ,
+ uint16_t pid :13; )
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_pat_section.
+ *
+ * @param section Pointer to the generic section_ext structure.
+ * @return Pointer to the mpeg_pat_section structure, or NULL on error.
+ */
+extern struct mpeg_pat_section *mpeg_pat_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for the transport_stream_id field of a PAT.
+ *
+ * @param pat PAT pointer.
+ * @return The transport_stream_id.
+ */
+static inline uint16_t mpeg_pat_section_transport_stream_id(struct mpeg_pat_section *pat)
+{
+ return pat->head.table_id_ext;
+}
+
+/**
+ * Conveience iterator for the programs field of an mpeg_pat_section.
+ *
+ * @param pat Pointer to the mpeg_pat_section structure.
+ * @param pos Variable holding a pointer to the current mpeg_pat_program structure.
+ */
+#define mpeg_pat_section_programs_for_each(pat, pos) \
+ for ((pos) = mpeg_pat_section_programs_first(pat); \
+ (pos); \
+ (pos) = mpeg_pat_section_programs_next(pat, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct mpeg_pat_program *
+ mpeg_pat_section_programs_first(struct mpeg_pat_section * pat)
+{
+ int pos = sizeof(struct mpeg_pat_section);
+
+ if (pos >= section_ext_length(&pat->head))
+ return NULL;
+
+ return (struct mpeg_pat_program*)((uint8_t *) pat + pos);
+}
+
+static inline
+ struct mpeg_pat_program *mpeg_pat_section_programs_next(struct mpeg_pat_section * pat,
+ struct mpeg_pat_program * pos)
+{
+ uint8_t *end = (uint8_t*) pat + section_ext_length(&pat->head);
+ uint8_t *next= (uint8_t *) pos + sizeof(struct mpeg_pat_program);
+
+ if (next >= end)
+ return NULL;
+
+ return (struct mpeg_pat_program *) next;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c
new file mode 100644
index 0000000..6ff4fac
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.c
@@ -0,0 +1,71 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/mpeg/pmt_section.h>
+
+struct mpeg_pmt_section * mpeg_pmt_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *) ext;
+ struct mpeg_pmt_section * pmt = (struct mpeg_pmt_section *) ext;
+ unsigned int pos = sizeof(struct section_ext);
+ unsigned int len = section_ext_length(ext);
+
+ if (len < sizeof(struct mpeg_pmt_section))
+ return NULL;
+
+ bswap16(buf + pos);
+ pos += 2;
+ bswap16(buf + pos);
+ pos += 2;
+
+ if ((pos + pmt->program_info_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, pmt->program_info_length))
+ return NULL;
+
+ pos += pmt->program_info_length;
+
+ while (pos < len) {
+ struct mpeg_pmt_stream * stream =
+ (struct mpeg_pmt_stream *) (buf + pos);
+
+ if ((pos + sizeof(struct mpeg_pmt_stream)) > len)
+ return NULL;
+
+ bswap16(buf + pos + 1);
+ bswap16(buf + pos + 3);
+ pos += sizeof(struct mpeg_pmt_stream);
+
+ if ((pos + stream->es_info_length) > len)
+ return NULL;
+
+ if (verify_descriptors(buf + pos, stream->es_info_length))
+ return NULL;
+
+ pos += stream->es_info_length;
+ }
+
+ if (pos != len)
+ return NULL;
+
+ return (struct mpeg_pmt_section *) ext;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h
new file mode 100644
index 0000000..73bba1d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/pmt_section.h
@@ -0,0 +1,188 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_PMT_SECTION_H
+#define _UCSI_MPEG_PMT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * mpeg_pmt_section structure.
+ */
+struct mpeg_pmt_section {
+ struct section_ext head;
+
+ EBIT2(uint16_t reserved_1 : 3; ,
+ uint16_t pcr_pid :13; )
+ EBIT2(uint16_t reserved_2 : 4; ,
+ uint16_t program_info_length :12; )
+ /* struct descriptor descriptors[] */
+ /* struct mpeg_pmt_stream streams[] */
+} __ucsi_packed;
+
+/**
+ * A stream within an mpeg_pmt_section.
+ */
+struct mpeg_pmt_stream {
+ uint8_t stream_type;
+ EBIT2(uint16_t reserved_1 : 3; ,
+ uint16_t pid :13; )
+ EBIT2(uint16_t reserved_2 : 4; ,
+ uint16_t es_info_length :12; )
+
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_pmt_section section.
+ *
+ * @param section Pointer to the generic section header.
+ * @return Pointer to the mpeg_pmt_section structure, or NULL on error.
+ */
+extern struct mpeg_pmt_section *mpeg_pmt_section_codec(struct section_ext *section);
+
+/**
+ * Accessor for program_number field of a PMT.
+ *
+ * @param pmt PMT pointer.
+ * @return The program_number.
+ */
+static inline uint16_t mpeg_pmt_section_program_number(struct mpeg_pmt_section *pmt)
+{
+ return pmt->head.table_id_ext;
+}
+
+/**
+ * Convenience iterator for the descriptors field of the mpeg_pmt_section structure.
+ *
+ * @param pmt Pointer to the mpeg_pmt_section structure.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define mpeg_pmt_section_descriptors_for_each(pmt, pos) \
+ for ((pos) = mpeg_pmt_section_descriptors_first(pmt); \
+ (pos); \
+ (pos) = mpeg_pmt_section_descriptors_next(pmt, pos))
+
+/**
+ * Convenience iterator for the streams field of the mpeg_pmt_section structure.
+ *
+ * @param pmt Pointer to the mpeg_pmt_section structure.
+ * @param pos Variable holding a pointer to the current mpeg_pmt_stream.
+ */
+#define mpeg_pmt_section_streams_for_each(pmt, pos) \
+ for ((pos) = mpeg_pmt_section_streams_first(pmt); \
+ (pos); \
+ (pos) = mpeg_pmt_section_streams_next(pmt, pos))
+
+/**
+ * Convenience iterator for the descriptors field of an mpeg_pmt_stream structure.
+ *
+ * @param stream Pointer to the mpeg_pmt_stream structure.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define mpeg_pmt_stream_descriptors_for_each(stream, pos) \
+ for ((pos) = mpeg_pmt_stream_descriptors_first(stream); \
+ (pos); \
+ (pos) = mpeg_pmt_stream_descriptors_next(stream, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ mpeg_pmt_section_descriptors_first(struct mpeg_pmt_section * pmt)
+{
+ if (pmt->program_info_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t *) pmt + sizeof(struct mpeg_pmt_section));
+}
+
+static inline struct descriptor *
+ mpeg_pmt_section_descriptors_next(struct mpeg_pmt_section *pmt,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t *) pmt + sizeof(struct mpeg_pmt_section),
+ pmt->program_info_length,
+ pos);
+}
+
+static inline struct mpeg_pmt_stream *
+ mpeg_pmt_section_streams_first(struct mpeg_pmt_section * pmt)
+{
+ int pos = sizeof(struct mpeg_pmt_section) + pmt->program_info_length;
+
+ if (pos >= section_ext_length(&pmt->head))
+ return NULL;
+
+ return (struct mpeg_pmt_stream *)((uint8_t *)pmt + pos);
+}
+
+static inline struct mpeg_pmt_stream *
+ mpeg_pmt_section_streams_next(struct mpeg_pmt_section * pmt,
+ struct mpeg_pmt_stream * pos)
+{
+ uint8_t *end = (uint8_t*) pmt + section_ext_length(&pmt->head);
+ uint8_t *next = (uint8_t *) pos + sizeof(struct mpeg_pmt_stream) +
+ pos->es_info_length;
+
+ if (next >= end)
+ return NULL;
+
+ return (struct mpeg_pmt_stream *) next;
+}
+
+static inline struct descriptor *
+ mpeg_pmt_stream_descriptors_first(struct mpeg_pmt_stream *stream)
+{
+ if (stream->es_info_length == 0)
+ return NULL;
+
+ return (struct descriptor *)
+ ((uint8_t*) stream + sizeof(struct mpeg_pmt_stream));
+}
+
+static inline struct descriptor *
+ mpeg_pmt_stream_descriptors_next(struct mpeg_pmt_stream *stream,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t *) stream + sizeof(struct mpeg_pmt_stream),
+ stream->es_info_length,
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/private_data_indicator_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/private_data_indicator_descriptor.h
new file mode 100644
index 0000000..80e8ef3
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/private_data_indicator_descriptor.h
@@ -0,0 +1,63 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_PRIVATE_DATA_INDICATOR_DESCRIPTOR
+#define _UCSI_MPEG_PRIVATE_DATA_INDICATOR_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_private_data_indicator_descriptor structure
+ */
+struct mpeg_private_data_indicator_descriptor {
+ struct descriptor d;
+
+ uint32_t private_data_indicator;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_private_data_indicator_descriptor structure.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_private_data_indicator_descriptor, or NULL on error.
+ */
+static inline struct mpeg_private_data_indicator_descriptor*
+ mpeg_private_data_indicator_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_private_data_indicator_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+
+ return (struct mpeg_private_data_indicator_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/registration_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/registration_descriptor.h
new file mode 100644
index 0000000..df5c186
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/registration_descriptor.h
@@ -0,0 +1,91 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_REGISTRATION_DESCRIPTOR
+#define _UCSI_MPEG_REGISTRATION_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_registration_descriptor structure.
+ */
+struct mpeg_registration_descriptor {
+ struct descriptor d;
+
+ uint32_t format_identifier;
+ /* uint8_t additional_id_info[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_registration_descriptor.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_registration_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_registration_descriptor*
+ mpeg_registration_descriptor_codec(struct descriptor* d)
+{
+ if (d->len < (sizeof(struct mpeg_registration_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+
+ return (struct mpeg_registration_descriptor*) d;
+}
+
+/**
+ * Retrieve a pointer to the additional_id_info field of the
+ * mpeg_registration_descriptor structure.
+ *
+ * @param d Pointer to the mpeg_registration_descriptor structure.
+ * @return Pointer to the field.
+ */
+static inline uint8_t *
+ mpeg_registration_descriptor_additional_id_info(struct mpeg_registration_descriptor *d)
+{
+ return (uint8_t *) d + sizeof(struct mpeg_registration_descriptor);
+}
+
+/**
+ * Determine number of bytes in the additional_id_info field of the
+ * mpeg_registration_descriptor structure.
+ *
+ * @param d Pointer to the mpeg_registration_descriptor structure.
+ * @return Number of bytes.
+ */
+
+static inline int
+ mpeg_registration_descriptor_additional_id_info_length(struct mpeg_registration_descriptor *d)
+{
+ return d->d.len - 4;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h
new file mode 100644
index 0000000..6215e95
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/section.h
@@ -0,0 +1,58 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_SECTION_H
+#define _UCSI_MPEG_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/mpeg/cat_section.h>
+#include <libucsi/mpeg/odsmt_section.h>
+#include <libucsi/mpeg/pat_section.h>
+#include <libucsi/mpeg/pmt_section.h>
+#include <libucsi/mpeg/tsdt_section.h>
+#include <libucsi/mpeg/metadata_section.h>
+
+#define TRANSPORT_PAT_PID 0x00
+#define TRANSPORT_CAT_PID 0x01
+#define TRANSPORT_TSDT_PID 0x02
+
+/**
+ * Enumeration of MPEG section tags.
+ */
+enum mpeg_section_tag {
+ stag_mpeg_program_association = 0x00,
+ stag_mpeg_conditional_access = 0x01,
+ stag_mpeg_program_map = 0x02,
+ stag_mpeg_transport_stream_description = 0x03,
+ stag_mpeg_iso14496_scene_description = 0x04,
+ stag_mpeg_iso14496_object_description = 0x05,
+ stag_mpeg_metadata = 0x06
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/sl_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/sl_descriptor.h
new file mode 100644
index 0000000..ab086e3
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/sl_descriptor.h
@@ -0,0 +1,63 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_SL_DESCRIPTOR
+#define _UCSI_MPEG_SL_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_sl_descriptor structure.
+ */
+struct mpeg_sl_descriptor {
+ struct descriptor d;
+
+ uint16_t es_id;
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_sl_descriptor.
+ *
+ * @param d The generic descriptor structure.
+ * @return Pointer to an mpeg_sl_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_sl_descriptor*
+ mpeg_sl_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_sl_descriptor) - 2))
+ return NULL;
+
+ bswap16((uint8_t*) d + 2);
+
+ return (struct mpeg_sl_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/smoothing_buffer_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/smoothing_buffer_descriptor.h
new file mode 100644
index 0000000..5e6ad33
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/smoothing_buffer_descriptor.h
@@ -0,0 +1,66 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_SMOOTHING_BUFFER_DESCRIPTOR
+#define _UCSI_MPEG_SMOOTHING_BUFFER_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_smoothing_buffer_descriptor structure.
+ */
+struct mpeg_smoothing_buffer_descriptor {
+ struct descriptor d;
+
+ EBIT4(uint64_t reserved_1 : 2; ,
+ uint64_t sb_leak_rate :22; ,
+ uint64_t reserved_2 : 2; ,
+ uint64_t sb_size :22; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_smoothing_buffer_descriptor.
+ *
+ * @param d The generic descriptor structure.
+ * @return Pointer to mpeg_smoothing_buffer_descriptor, or NULL on error.
+ */
+static inline struct mpeg_smoothing_buffer_descriptor*
+ mpeg_smoothing_buffer_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_smoothing_buffer_descriptor) - 2))
+ return NULL;
+
+ bswap48((uint8_t*) d + 2);
+
+ return (struct mpeg_smoothing_buffer_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/std_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/std_descriptor.h
new file mode 100644
index 0000000..2625a41
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/std_descriptor.h
@@ -0,0 +1,62 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_STD_DESCRIPTOR
+#define _UCSI_MPEG_STD_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_std_descriptor structure.
+ */
+struct mpeg_std_descriptor {
+ struct descriptor d;
+
+ EBIT2(uint8_t reserved : 7; ,
+ uint8_t leak_valid_flag : 1; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_std_descriptor.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_std_descriptor, or NULL on error.
+ */
+static inline struct mpeg_std_descriptor*
+ mpeg_std_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_std_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg_std_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/system_clock_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/system_clock_descriptor.h
new file mode 100644
index 0000000..681641f
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/system_clock_descriptor.h
@@ -0,0 +1,65 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_SYSTEM_CLOCK_DESCRIPTOR
+#define _UCSI_MPEG_SYSTEM_CLOCK_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_system_clock_descriptor structure.
+ */
+struct mpeg_system_clock_descriptor {
+ struct descriptor d;
+
+ EBIT3(uint8_t external_clock_reference_indicator : 1; ,
+ uint8_t reserved_1 : 1; ,
+ uint8_t clock_accuracy_integer : 6; );
+ EBIT2(uint8_t clock_accuracy_exponent : 3; ,
+ uint8_t reserved_2 : 5; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_system_clock_descriptor.
+ *
+ * @param d The generic descriptor structure.
+ * @return Pointer to a mpeg_system_clock_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_system_clock_descriptor*
+ mpeg_system_clock_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_system_clock_descriptor) - 2))
+ return NULL;
+
+ return (struct mpeg_system_clock_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/target_background_grid_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/target_background_grid_descriptor.h
new file mode 100644
index 0000000..7394e82
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/target_background_grid_descriptor.h
@@ -0,0 +1,66 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_TARGET_BACKGROUND_GRID_DESCRIPTOR
+#define _UCSI_MPEG_TARGET_BACKGROUND_GRID_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * mpeg_target_background_grid_descriptor structure.
+ */
+struct mpeg_target_background_grid_descriptor {
+ struct descriptor d;
+
+ EBIT3(uint32_t horizontal_size : 14; ,
+ uint32_t vertical_size : 14; ,
+ uint32_t aspect_ratio_information : 4; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_target_background_grid_descriptor structure.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_target_background_grid_descriptor structure, or
+ * NULL on error.
+ */
+static inline struct mpeg_target_background_grid_descriptor*
+ mpeg_target_background_grid_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_target_background_grid_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+
+ return (struct mpeg_target_background_grid_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c
new file mode 100644
index 0000000..fbbbe3c
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.c
@@ -0,0 +1,35 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libucsi/mpeg/tsdt_section.h>
+
+struct mpeg_tsdt_section * mpeg_tsdt_section_codec(struct section_ext * ext)
+{
+ uint8_t * buf = (uint8_t *)ext;
+ int pos = sizeof(struct section_ext);
+
+ if (verify_descriptors(buf + pos,
+ section_ext_length(ext) - sizeof(struct mpeg_tsdt_section)))
+ return NULL;
+
+ return (struct mpeg_tsdt_section *)ext;
+}
+
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h
new file mode 100644
index 0000000..9039278
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/tsdt_section.h
@@ -0,0 +1,94 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_TSDT_SECTION_H
+#define _UCSI_MPEG_TSDT_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/section.h>
+
+/**
+ * mpeg_tsdt_section structure.
+ */
+struct mpeg_tsdt_section {
+ struct section_ext head;
+
+ /* struct descriptor descriptors[] */
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_tsdt_section structure.
+ *
+ * @param section Pointer to the section_ext structure.
+ * @return Pointer to the mpeg_tsdt_section structure, or NULL on error.
+ */
+extern struct mpeg_tsdt_section *mpeg_tsdt_section_codec(struct section_ext *section);
+
+/**
+ * Convenience iterator for descriptors field.
+ *
+ * @param tsdt Pointer to the mpeg_tsdt_section structure.
+ * @param pos Variable holding a pointer to the current descriptor.
+ */
+#define mpeg_tsdt_section_descriptors_for_each(tsdt, pos) \
+ for ((pos) = mpeg_tsdt_section_descriptors_first(tsdt); \
+ (pos); \
+ (pos) = mpeg_tsdt_section_descriptors_next(tsdt, pos))
+
+
+
+
+
+
+
+
+
+
+/******************************** PRIVATE CODE ********************************/
+static inline struct descriptor *
+ mpeg_tsdt_section_descriptors_first(struct mpeg_tsdt_section * tsdt)
+{
+ int pos = sizeof(struct mpeg_tsdt_section);
+
+ if (pos >= section_ext_length(&tsdt->head))
+ return NULL;
+
+ return (struct descriptor*)((uint8_t *) tsdt + pos);
+}
+
+static inline struct descriptor *
+ mpeg_tsdt_section_descriptors_next(struct mpeg_tsdt_section *tsdt,
+ struct descriptor* pos)
+{
+ return next_descriptor((uint8_t *) tsdt + sizeof(struct mpeg_tsdt_section),
+ section_ext_length(&tsdt->head) - sizeof(struct mpeg_tsdt_section),
+ pos);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/types.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/types.h
new file mode 100644
index 0000000..300cb23
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/types.h
@@ -0,0 +1,127 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_TYPES_H
+#define _UCSI_MPEG_TYPES_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Known stream types.
+ */
+enum {
+ MPEG_STREAM_TYPE_ISO11172_VIDEO = 0x01,
+ MPEG_STREAM_TYPE_ISO13818_2_VIDEO = 0x02,
+ MPEG_STREAM_TYPE_ISO11172_AUDIO = 0x03,
+ MPEG_STREAM_TYPE_ISO13818_3_AUDIO = 0x04,
+ MPEG_STREAM_TYPE_ISO13818_1_PRIVATE_SECTIONS = 0x05,
+ MPEG_STREAM_TYPE_ISO13818_1_PRIVATE_PES = 0x06,
+ MPEG_STREAM_TYPE_ISO13522_MHEG = 0x07,
+ MPEG_STREAM_TYPE_ISO13818_DSMCC = 0x08,
+ MPEG_STREAM_TYPE_ITUH222_1 = 0x09,
+ MPEG_STREAM_TYPE_ISO13818_6_A = 0x0a,
+ MPEG_STREAM_TYPE_ISO13818_6_B = 0x0b,
+ MPEG_STREAM_TYPE_ISO13818_6_C = 0x0c,
+ MPEG_STREAM_TYPE_ISO13818_6_D = 0x0d,
+ MPEG_STREAM_TYPE_ISO13818_1_AUX = 0x0e,
+ MPEG_STREAM_TYPE_ISO13818_7_AUDIO_ADTS = 0x0f,
+ MPEG_STREAM_TYPE_ISO14496_2_VISUAL = 0x10,
+ MPEG_STREAM_TYPE_ISO14496_3_AUDIO_LATM = 0x11,
+ MPEG_STREAM_TYPE_ISO14496_1_PES = 0x12,
+ MPEG_STREAM_TYPE_ISO14496_1_SECTIONS = 0x13,
+ MPEG_STREAM_TYPE_ISO14496_6_SYNCDOWNLOAD = 0x14,
+ MPEG_STREAM_TYPE_METADATA_PES = 0x15,
+ MPEG_STREAM_TYPE_METADATA_SECTIONS = 0x16,
+ MPEG_STREAM_TYPE_METADATA_DSMCC_DATA = 0x17,
+ MPEG_STREAM_TYPE_METADATA_DSMCC_OBJECT = 0x18,
+ MPEG_STREAM_TYPE_METADATA_SYNCDOWNLOAD = 0x19,
+};
+
+/**
+ * Metadata formats
+ */
+enum {
+ MPEG_METADATA_FORMAT_ISO15938_1_TEM = 0x01,
+ MPEG_METADATA_FORMAT_ISO15938_1_BIM = 0x02,
+ MPEG_METADATA_FORMAT_METADATA_APPLICATION_FORMAT = 0x3F,
+ MPEG_METADATA_FORMAT_METADATA_APPLICATION_FORMAT_ID = 0xFF,
+};
+
+/**
+ * MPEG 4 audio profile and levels.
+ */
+enum {
+ MPEG4_AUDIO_PROFILE_MAIN_LEVEL_1 = 0x10,
+ MPEG4_AUDIO_PROFILE_MAIN_LEVEL_2 = 0x11,
+ MPEG4_AUDIO_PROFILE_MAIN_LEVEL_3 = 0x12,
+ MPEG4_AUDIO_PROFILE_MAIN_LEVEL_4 = 0x13,
+
+ MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_1 = 0x18,
+ MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_2 = 0x19,
+ MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_3 = 0x1a,
+ MPEG4_AUDIO_PROFILE_SCALABLE_LEVEL_4 = 0x1b,
+
+ MPEG4_AUDIO_PROFILE_SPEECH_LEVEL_1 = 0x20,
+ MPEG4_AUDIO_PROFILE_SPEECH_LEVEL_2 = 0x21,
+
+ MPEG4_AUDIO_PROFILE_SYNTHESIS_LEVEL_1 = 0x28,
+ MPEG4_AUDIO_PROFILE_SYNTHESIS_LEVEL_2 = 0x29,
+ MPEG4_AUDIO_PROFILE_SYNTHESIS_LEVEL_3 = 0x2a,
+
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_1 = 0x30,
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_2 = 0x31,
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_3 = 0x32,
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_4 = 0x33,
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_5 = 0x34,
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_6 = 0x35,
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_7 = 0x36,
+ MPEG4_AUDIO_PROFILE_HQ_LEVEL_8 = 0x37,
+
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_1 = 0x38,
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_2 = 0x39,
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_3 = 0x3a,
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_4 = 0x3b,
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_5 = 0x3c,
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_6 = 0x3d,
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_7 = 0x3e,
+ MPEG4_AUDIO_PROFILE_LOW_DELAY_LEVEL_8 = 0x3f,
+
+ MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_1 = 0x40,
+ MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_2 = 0x41,
+ MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_3 = 0x42,
+ MPEG4_AUDIO_PROFILE_NATURAL_LEVEL_4 = 0x43,
+
+ MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_1 = 0x48,
+ MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_2 = 0x49,
+ MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_3 = 0x4a,
+ MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_4 = 0x4b,
+ MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_5 = 0x4c,
+ MPEG4_AUDIO_PROFILE_MOBILE_LEVEL_6 = 0x4d,
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_stream_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_stream_descriptor.h
new file mode 100644
index 0000000..14e9196
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_stream_descriptor.h
@@ -0,0 +1,101 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_VIDEO_STREAM_DESCRIPTOR
+#define _UCSI_MPEG_VIDEO_STREAM_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+#include <libucsi/endianops.h>
+
+/**
+ * The mpeg_video_stream_descriptor structure
+ */
+struct mpeg_video_stream_descriptor {
+ struct descriptor d;
+
+ EBIT5(uint8_t multiple_frame_rate_flag : 1; ,
+ uint8_t frame_rate_code : 4; ,
+ uint8_t mpeg_1_only_flag : 1; ,
+ uint8_t constrained_parameter_flag : 1; ,
+ uint8_t still_picture_flag : 1; );
+ /* if (mpeg_1_only_flag == 0) struct mpeg_video_stream_extra extra */
+} __ucsi_packed;
+
+/**
+ * The mpeg_video_stream_extra - only present in non-MPEG1-only streams.
+ */
+struct mpeg_video_stream_extra {
+ uint8_t profile_and_level_indication;
+ EBIT3(uint8_t chroma_format : 2; ,
+ uint8_t frame_rate_extension : 1; ,
+ uint8_t reserved : 5; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_video_stream_descriptor structure.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_video_stream_descriptor, or NULL on error.
+ */
+static inline struct mpeg_video_stream_descriptor*
+ mpeg_video_stream_descriptor_codec(struct descriptor* d)
+{
+ struct mpeg_video_stream_descriptor* vsd =
+ (struct mpeg_video_stream_descriptor*) d;
+
+ if (d->len < (sizeof(struct mpeg_video_stream_descriptor) - 2))
+ return NULL;
+
+ if (!vsd->mpeg_1_only_flag) {
+ if (d->len != (sizeof(struct mpeg_video_stream_descriptor) +
+ sizeof(struct mpeg_video_stream_extra) - 2))
+ return NULL;
+ }
+
+ return (struct mpeg_video_stream_descriptor*) d;
+}
+
+/**
+ * Get a pointer to the mpeg_video_stream_extra structure.
+ *
+ * @param d Pointer to the mpeg_video_stream_descriptor structure.
+ * @return Pointer to the mpeg_video_stream_extra structure, or NULL on error.
+ */
+static inline struct mpeg_video_stream_extra*
+ mpeg_video_stream_descriptor_extra(struct mpeg_video_stream_descriptor* d)
+{
+ if (d->mpeg_1_only_flag != 0)
+ return NULL;
+
+ return (struct mpeg_video_stream_extra*)
+ ((uint8_t*) d + sizeof(struct mpeg_video_stream_descriptor));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_window_descriptor.h b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_window_descriptor.h
new file mode 100644
index 0000000..a9a63c7
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/mpeg/video_window_descriptor.h
@@ -0,0 +1,64 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_MPEG_VIDEO_WINDOW_DESCRIPTOR
+#define _UCSI_MPEG_VIDEO_WINDOW_DESCRIPTOR 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/descriptor.h>
+
+/**
+ * mpeg_video_window_descriptor structure.
+ */
+struct mpeg_video_window_descriptor {
+ struct descriptor d;
+
+ EBIT3(uint32_t horizontal_offset : 14; ,
+ uint32_t vertical_offset : 14; ,
+ uint32_t window_priority : 4; );
+} __ucsi_packed;
+
+/**
+ * Process an mpeg_video_window_descriptor.
+ *
+ * @param d Pointer to the generic descriptor structure.
+ * @return Pointer to the mpeg_video_window_descriptor structure, or NULL on error.
+ */
+static inline struct mpeg_video_window_descriptor*
+ mpeg_video_window_descriptor_codec(struct descriptor* d)
+{
+ if (d->len != (sizeof(struct mpeg_video_window_descriptor) - 2))
+ return NULL;
+
+ bswap32((uint8_t*) d + 2);
+
+ return (struct mpeg_video_window_descriptor*) d;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/section.h b/kaffeine/src/input/dvb/lib/libucsi/section.h
new file mode 100644
index 0000000..e2f7551
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/section.h
@@ -0,0 +1,253 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_SECTION_H
+#define _UCSI_SECTION_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <libucsi/endianops.h>
+#include <libucsi/descriptor.h>
+#include <libucsi/crc32.h>
+#include <stdint.h>
+#include <string.h>
+
+#define CRC_SIZE 4
+
+
+/**
+ * Generic section header.
+ */
+struct section {
+ uint8_t table_id;
+ EBIT4(uint16_t syntax_indicator : 1; ,
+ uint16_t private_indicator : 1; , /* 2.4.4.10 */
+ uint16_t reserved : 2; ,
+ uint16_t length :12; )
+} __ucsi_packed;
+
+/**
+ * Generic extended section header structure.
+ */
+struct section_ext {
+ uint8_t table_id;
+ EBIT4(uint16_t syntax_indicator : 1; ,
+ uint16_t private_indicator : 1; , /* 2.4.4.10 */
+ uint16_t reserved : 2; ,
+ uint16_t length :12; )
+
+ uint16_t table_id_ext;
+ EBIT3(uint8_t reserved1 : 2; ,
+ uint8_t version_number : 5; ,
+ uint8_t current_next_indicator : 1; )
+ uint8_t section_number;
+ uint8_t last_section_number;
+} __ucsi_packed;
+
+/**
+ * Structure for keeping track of sections of a PSI table.
+ */
+struct psi_table_state {
+ uint8_t version_number;
+ uint16_t next_section_number;
+ uint8_t complete:1;
+ uint8_t new_table:1;
+} __ucsi_packed;
+
+
+/**
+ * Process a section structure in-place.
+ *
+ * @param buf Pointer to the data.
+ * @param len Length of data.
+ * @return Pointer to the section structure, or NULL if invalid.
+ */
+static inline struct section * section_codec(uint8_t * buf, int len)
+{
+ struct section * ret = (struct section *)buf;
+
+ if (len < 3)
+ return NULL;
+
+ bswap16(buf+1);
+
+ if (len != ret->length + 3)
+ return NULL;
+
+ return ret;
+}
+
+/**
+ * Some sections have a CRC even though they are not section_exts.
+ * This function is to allow checking of them.
+ *
+ * @param section Pointer to the processed section structure.
+ * @return Nonzero on error, or 0 if the CRC was correct.
+ */
+static inline int section_check_crc(struct section *section)
+{
+ uint8_t * buf = (uint8_t *) section;
+ int len = sizeof(struct section) + section->length;
+ uint32_t crc;
+
+ /* the crc check has to be performed on the unswapped data */
+ bswap16(buf+1);
+ crc = crc32(CRC32_INIT, buf, len);
+ bswap16(buf+1);
+
+ /* the crc check includes the crc value,
+ * the result should therefore be zero.
+ */
+ if (crc)
+ return -1;
+ return 0;
+}
+
+
+/**
+ * Decode an extended section structure.
+ *
+ * @param section Pointer to the processed section structure.
+ * @param check_crc If 1, the CRC of the section will also be checked.
+ * @return Pointer to the parsed section_ext structure, or NULL if invalid.
+ */
+static inline struct section_ext * section_ext_decode(struct section * section,
+ int check_crc)
+{
+ if (section->syntax_indicator == 0)
+ return NULL;
+
+ if (check_crc) {
+ if (section_check_crc(section))
+ return NULL;
+ }
+
+ bswap16((uint8_t *)section + sizeof(struct section));
+
+ return (struct section_ext *)section;
+}
+
+/**
+ * Encode an extended section structure for transmission.
+ *
+ * @param section Pointer to the section_ext structure.
+ * @param update_crc If 1, the CRC of the section will also be updated.
+ * @return Pointer to the encoded section_ext structure, or NULL if invalid.
+ */
+static inline struct section_ext * section_ext_encode(struct section_ext* section,
+ int update_crc)
+{
+ if (section->syntax_indicator == 0)
+ return NULL;
+
+ bswap16((uint8_t *)section + sizeof(struct section));
+
+ if (update_crc) {
+ uint8_t * buf = (uint8_t *) section;
+ int len = sizeof(struct section) + section->length;
+ uint32_t crc;
+
+ /* zap the current CRC value */
+ memset(buf+len-4, 0, 4);
+
+ /* the crc has to be performed on the swapped data */
+ bswap16(buf+1);
+ crc = crc32(CRC32_INIT, buf, len);
+ bswap16(buf+1);
+
+ /* update the CRC */
+ *((uint32_t*) (buf+len-4)) = crc;
+ bswap32(buf+len-4);
+ }
+
+ return (struct section_ext *)section;
+}
+
+/**
+ * Determine the total length of a section, including the header.
+ *
+ * @param section The parsed section structure.
+ * @return The length.
+ */
+static inline int section_length(struct section *section)
+{
+ return section->length + sizeof(struct section);
+}
+
+/**
+ * Determine the total length of an extended section, including the header,
+ * but omitting the CRC.
+ *
+ * @param section The parsed section_ext structure.
+ * @return The length.
+ */
+static inline int section_ext_length(struct section_ext * section)
+{
+ return section->length + sizeof(struct section) - CRC_SIZE;
+}
+
+/**
+ * Reset a psi_table_state structure.
+ *
+ * @param tstate The structure to reset.
+ */
+static inline void psi_table_state_reset(struct psi_table_state *tstate)
+{
+ tstate->version_number = 0xff;
+}
+
+/**
+ * Check if a supplied section_ext is something we want to process.
+ *
+ * @param section The parsed section_ext structure.
+ * @param tstate The state structure for this PSI table.
+ * @return 0=> not useful. nonzero => useful.
+ */
+static inline int section_ext_useful(struct section_ext *section, struct psi_table_state *tstate)
+{
+ if ((section->version_number == tstate->version_number) && tstate->complete)
+ return 0;
+ if ((section->version_number != tstate->version_number) && (section->section_number == 0)) {
+ tstate->next_section_number = 0;
+ tstate->complete = 0;
+ tstate->version_number = section->version_number;
+ tstate->new_table = 1;
+ } else if (section->section_number == tstate->next_section_number) {
+ tstate->new_table = 0;
+ } else {
+ return 0;
+ }
+
+ tstate->next_section_number++;
+ if (section->last_section_number < tstate->next_section_number) {
+ tstate->complete = 1;
+ }
+
+ return 1;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/section_buf.c b/kaffeine/src/input/dvb/lib/libucsi/section_buf.c
new file mode 100644
index 0000000..35d465e
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/section_buf.c
@@ -0,0 +1,173 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <errno.h>
+#include <string.h>
+#include "section_buf.h"
+
+#define SECTION_HDR_SIZE 3
+#define SECTION_PAD 0xff
+
+int section_buf_init(struct section_buf *section, int max)
+{
+ if (max < SECTION_HDR_SIZE)
+ return -EINVAL;
+
+ memset(section, 0, sizeof(struct section_buf));
+ section->max = max; /* max size of data */
+ section->len = SECTION_HDR_SIZE;
+ section->wait_pdu = 1;
+
+ return 0;
+}
+
+int section_buf_add(struct section_buf *section, uint8_t* frag, int len, int *section_status)
+{
+ int copy;
+ int used = 0;
+ uint8_t *data;
+ uint8_t *pos = (uint8_t*) section + sizeof(struct section_buf) + section->count;
+
+ /* have we finished? */
+ if (section->header && (section->len == section->count)) {
+ *section_status = 1;
+ return 0;
+ }
+
+ /* skip over section padding bytes */
+ *section_status = 0;
+ if (section->count == 0) {
+ while(len && (*frag == SECTION_PAD)) {
+ frag++;
+ len--;
+ used++;
+ }
+
+ if (len == 0)
+ return used;
+ }
+
+ /* grab the header to get the section length */
+ if (!section->header) {
+ /* copy the header frag */
+ copy = SECTION_HDR_SIZE - section->count;
+ if (copy > len)
+ copy = len;
+ memcpy(pos, frag, copy);
+ section->count += copy;
+ pos += copy;
+ frag += copy;
+ used += copy;
+ len -= copy;
+
+ /* we need 3 bytes for the section header */
+ if (section->count != SECTION_HDR_SIZE)
+ return used;
+
+ /* work out the length & check it isn't too big */
+ data = (uint8_t*) section + sizeof(struct section_buf);
+ section->len = SECTION_HDR_SIZE + (((data[1] & 0x0f) << 8) | data[2]);
+ if (section->len > section->max) {
+ *section_status = -ERANGE;
+ return len + used;
+ }
+
+ /* update fields */
+ section->header = 1;
+ }
+
+ /* accumulate frag */
+ copy = section->len - section->count;
+ if (copy > len)
+ copy = len;
+ memcpy(pos, frag, copy);
+ section->count += copy;
+ used += copy;
+
+ /* have we finished? */
+ if (section->header && (section->len == section->count))
+ *section_status = 1;
+
+ /* return number of bytes used */
+ return used;
+}
+
+int section_buf_add_transport_payload(struct section_buf *section,
+ uint8_t* payload, int len,
+ int pdu_start, int *section_status)
+{
+ int used = 0;
+ int tmp;
+
+ /* have we finished? */
+ if (section->header && (section->len == section->count)) {
+ *section_status = 1;
+ return 0;
+ }
+
+ /* don't bother if we're waiting for a PDU */
+ *section_status = 0;
+ if (section->wait_pdu && (!pdu_start))
+ return len;
+
+ /* if we're at a PDU start, we need extra handling for the extra first
+ * byte giving the offset to the start of the next section. */
+ if (pdu_start) {
+ /* we have received a pdu */
+ section->wait_pdu = 0;
+
+ /* work out the offset to the _next_ payload */
+ int offset = payload[0];
+ if ((offset+1) > len) {
+ section->wait_pdu = 1;
+ *section_status = -EINVAL;
+ return len;
+ }
+
+ /* accumulate the end if we need to */
+ if (section->count != 0) {
+ /* add the final fragment. */
+ tmp = section_buf_add(section, payload + 1, offset, section_status);
+
+ /* the stream said this was the final fragment
+ * (PDU START bit) - check that it really was! */
+ if ((tmp != offset) || section_buf_remaining(section) || (*section_status != 1)) {
+ *section_status = -ERANGE;
+ section->wait_pdu = 1;
+ return 1 + tmp;
+ }
+
+ /* it is complete - return the number of bytes we used */
+ return 1 + tmp;
+ }
+
+ /* otherwise, we skip the end of the previous section, and
+ * start accumulating the new data. */
+ used = 1 + offset;
+ }
+
+ /* ok, just accumulate the data as normal */
+ tmp = section_buf_add(section, payload+used, len - used, section_status);
+ if (*section_status < 0) {
+ section->wait_pdu = 1;
+ }
+
+ return used + tmp;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/section_buf.h b/kaffeine/src/input/dvb/lib/libucsi/section_buf.h
new file mode 100644
index 0000000..e15cc1d
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/section_buf.h
@@ -0,0 +1,125 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_SECTION_BUF_H
+#define _UCSI_SECTION_BUF_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+
+#define DVB_MAX_SECTION_BYTES 4096
+
+/**
+ * Buffer used to keep track of section fragments. You should allocate an
+ * area of memory of size (sizeof(section_buf) + <maxsectionsize>), and pass that area
+ * to section_buf_init() to set it up.
+ */
+struct section_buf {
+ uint32_t max; /* maximum size of section - setup by section_buf_init() */
+ uint32_t count; /* number of bytes currently accumulated */
+ uint32_t len; /* total number of bytes expected in the complete section */
+ uint8_t header:1; /* flag indicating the section header has been commpletely received */
+ uint8_t wait_pdu:1;/* flag indicating to wait till the next PDU start */
+ /* uint8_t data[] */
+};
+
+/**
+ * Initialise a section_buf structure.
+ *
+ * @param section The section_buf to initialise.
+ * @param max Maximum number of bytes in section (must be > 3)
+ * @return 0 on success, nonzero on error.
+ */
+extern int section_buf_init(struct section_buf *section, int max);
+
+/**
+ * Initialise a section_buf structure.
+ *
+ * @param section The section_buf to initialise.
+ * @param max Maximum number of bytes in section (must be > 3)
+ * @return 0 on success, nonzero on error.
+ */
+static inline void section_buf_reset(struct section_buf *section)
+{
+ int tmp = section->wait_pdu;
+ section_buf_init(section, section->max);
+ section->wait_pdu = tmp;
+}
+
+/**
+ * Add a data fragment to a section_buf.
+ *
+ * @param section section_buf to add to.
+ * @param frag Pointer to data fragment.
+ * @param len Number of bytes of data.
+ * @param section_status 0: nothing special. 1: section complete. -ERANGE indicates that the
+ * section is larger than section->max.
+ * @return Number of bytes which were consumed.
+ */
+extern int section_buf_add(struct section_buf *section, uint8_t* frag, int len, int *section_status);
+
+/**
+ * Add a transport packet PSI payload to a section_buf. This takes into account
+ * the extra byte present in PDU_START flagged packets.
+ *
+ * @param section section_buf to add to.
+ * @param payload Pointer to packet payload data.
+ * @param len Number of bytes of data.
+ * @param pdu_start True if the payload_unit_start_indicator flag was set in the
+ * TS packet.
+ * @param section_status 0: nothing special. 1: section complete. -ERANGE indicates that the
+ * section is larger than section->max. -EINVAL indicates the pointer_field was completely
+ * invalid (too large).
+ */
+extern int section_buf_add_transport_payload(struct section_buf *section,
+ uint8_t* payload, int len,
+ int pdu_start, int *section_status);
+
+/**
+ * Get the number of bytes left to be received in a section_buf.
+ *
+ * @param section The section_buf concerned.
+ * @return The number of bytes.
+ */
+static inline int section_buf_remaining(struct section_buf *section)
+{
+ return section->len - section->count;
+}
+
+/**
+ * Return a pointer to the start of the data in the section_buf.
+ *
+ * @param section The section_buf concerned.
+ * @return The data.
+ */
+static inline uint8_t* section_buf_data(struct section_buf *section)
+{
+ return (uint8_t*) section + sizeof(struct section_buf);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/testrecord.txt b/kaffeine/src/input/dvb/lib/libucsi/testrecord.txt
new file mode 100644
index 0000000..259ffe1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/testrecord.txt
@@ -0,0 +1,101 @@
+libucsi test record. Anything without PASS is either not tested, or is
+currently broken.
+
+Testing means (a) ensure there are no segfaults etc. (b) dump the raw hex,
+decode it by hand, and check it matches the output.
+
+Sections:
+PASS mpeg/cat_section.h
+ mpeg/odsmt_section.h
+PASS mpeg/pat_section.h
+PASS mpeg/pmt_section.h
+ mpeg/tsdt_section.h
+ mpeg/metadata_section.h
+PASS dvb/bat_section.h
+ dvb/dit_section.h
+PASS dvb/eit_section.h
+ dvb/int_section.h
+PASS dvb/nit_section.h
+ dvb/rst_section.h
+PASS dvb/sdt_section.h
+ dvb/sit_section.h
+PASS dvb/st_section.h
+PASS dvb/tdt_section.h
+PASS dvb/tot_section.h
+
+Descriptors:
+PASS mpeg/audio_stream_descriptor.h
+PASS mpeg/ca_descriptor.h
+PASS mpeg/copyright_descriptor.h
+PASS mpeg/data_stream_alignment_descriptor.h
+PASS mpeg/external_es_id_descriptor.h
+ mpeg/fmc_descriptor.h
+PASS mpeg/fmxbuffer_size_descriptor.h
+ mpeg/hierarchy_descriptor.h
+ mpeg/ibp_descriptor.h
+ mpeg/iod_descriptor.h
+PASS mpeg/iso_639_language_descriptor.h
+PASS mpeg/maximum_bitrate_descriptor.h
+ mpeg/mpeg4_audio_descriptor.h
+ mpeg/mpeg4_video_descriptor.h
+ mpeg/multiplex_buffer_descriptor.h
+PASS mpeg/multiplex_buffer_utilization_descriptor.h
+ mpeg/muxcode_descriptor.h
+PASS mpeg/private_data_indicator_descriptor.h
+PASS mpeg/registration_descriptor.h
+ mpeg/sl_descriptor.h
+PASS mpeg/smoothing_buffer_descriptor.h
+PASS mpeg/std_descriptor.h
+PASS mpeg/system_clock_descriptor.h
+ mpeg/target_background_grid_descriptor.h
+PASS mpeg/video_stream_descriptor.h
+ mpeg/video_window_descriptor.h
+
+ dvb/ac3_descriptor.h
+ dvb/ancillary_data_descriptor.h
+ dvb/announcement_support_descriptor.h
+ dvb/bouquet_name_descriptor.h
+ dvb/ca_identifier_descriptor.h
+ dvb/ca_system_descriptor.h
+ dvb/cable_delivery_descriptor.h
+ dvb/cell_frequency_link_descriptor.h
+ dvb/cell_list_descriptor.h
+ dvb/component_descriptor.h
+ dvb/content_descriptor.h
+ dvb/country_availability_descriptor.h
+ dvb/data_broadcast_descriptor.h
+ dvb/data_broadcast_id_descriptor.h
+ dvb/descriptor.h
+ dvb/dsng_descriptor.h
+ dvb/extended_event_descriptor.h
+ dvb/frequency_list_descriptor.h
+ dvb/linkage_descriptor.h
+ dvb/local_time_offset_descriptor.h
+ dvb/mosaic_descriptor.h
+ dvb/multilingual_bouquet_name_descriptor.h
+ dvb/multilingual_component_descriptor.h
+ dvb/multilingual_network_name_descriptor.h
+ dvb/multilingual_service_name_descriptor.h
+ dvb/network_name_descriptor.h
+ dvb/nvod_reference_descriptor.h
+ dvb/parental_rating_descriptor.h
+ dvb/partial_transport_stream_descriptor.h
+ dvb/pdc_descriptor.h
+ dvb/private_data_specifier_descriptor.h
+ dvb/satellite_delivery_descriptor.h
+ dvb/service_descriptor.h
+ dvb/service_list_descriptor.h
+ dvb/service_move_descriptor.h
+ dvb/short_event_descriptor.h
+ dvb/short_smoothing_buffer_descriptor.h
+ dvb/stream_identifier_descriptor.h
+ dvb/stuffing_descriptor.h
+ dvb/subtitling_descriptor.h
+ dvb/telephone_descriptor.h
+ dvb/teletext_descriptor.h
+ dvb/terrestrial_delivery_descriptor.h
+ dvb/time_shifted_event_descriptor.h
+ dvb/time_shifted_service_descriptor.h
+ dvb/transport_stream_descriptor.h
+ dvb/vbi_data_descriptor.h
+ dvb/vbi_teletext_descriptor.h
diff --git a/kaffeine/src/input/dvb/lib/libucsi/transport_packet.c b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.c
new file mode 100644
index 0000000..ca6c2e1
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.c
@@ -0,0 +1,256 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "transport_packet.h"
+
+#define CONTINUITY_VALID 0x80
+#define CONTINUITY_DUPESEEN 0x40
+
+int transport_packet_values_extract(struct transport_packet *pkt,
+ struct transport_values *out,
+ enum transport_value extract)
+{
+ uint8_t *end = (uint8_t*) pkt + TRANSPORT_PACKET_LENGTH;
+ uint8_t *adapend;
+ uint8_t *pos = (uint8_t*) pkt + sizeof(struct transport_packet);
+ enum transport_value extracted = 0;
+ enum transport_adaptation_flags adapflags = 0;
+ enum transport_adaptation_extension_flags adapextflags = 0;
+ int adaplength = 0;
+ int adapextlength = 0;
+
+ /* does the packet contain an adaptation field ? */
+ if ((pkt->adaptation_field_control & 2) == 0)
+ goto extract_payload;
+
+ /* get the adaptation field length and skip the byte */
+ adaplength = *pos++;
+
+ /* do we actually have any adaptation data? */
+ if (adaplength == 0)
+ goto extract_payload;
+
+ /* sanity check */
+ adapend = pos + adaplength;
+ if (adapend > end)
+ return -1;
+
+ /* extract the adaptation flags (we must have at least 1 byte to be here) */
+ adapflags = *pos++;
+
+ /* do we actually want anything else? */
+ if ((extract & 0xffff) == 0)
+ goto extract_payload;
+
+ /* PCR? */
+ if (adapflags & transport_adaptation_flag_pcr) {
+ if ((pos+6) > adapend)
+ return -1;
+
+ if (extract & transport_value_pcr) {
+ uint64_t base = ((uint64_t) pos[0] << 25) |
+ ((uint64_t) pos[1] << 17) |
+ ((uint64_t) pos[2] << 9) |
+ ((uint64_t) pos[3] << 1) |
+ ((uint64_t) pos[4] >> 7);
+ uint64_t ext = (((uint64_t) pos[4] & 1) << 8) |
+ (uint64_t) pos[5];
+ out->pcr= base * 300ULL + ext;
+ extracted |= transport_value_pcr;
+ }
+ pos += 6;
+ }
+
+ /* OPCR? */
+ if (adapflags & transport_adaptation_flag_opcr) {
+ if ((pos+6) > adapend)
+ return -1;
+
+ if (extract & transport_value_opcr) {
+ uint64_t base = ((uint64_t) pos[0] << 25) |
+ ((uint64_t) pos[1] << 17) |
+ ((uint64_t) pos[2] << 9) |
+ ((uint64_t) pos[3] << 1) |
+ ((uint64_t) pos[4] >> 7);
+ uint64_t ext = (((uint64_t) pos[4] & 1) << 8) |
+ (uint64_t) pos[5];
+ out->opcr= base * 300ULL + ext;
+ extracted |= transport_value_opcr;
+ }
+ pos += 6;
+ }
+
+ /* splice countdown? */
+ if (adapflags & transport_adaptation_flag_splicing_point) {
+ if ((pos+1) > adapend)
+ return -1;
+
+ if (extract & transport_value_splice_countdown) {
+ out->splice_countdown = *pos;
+ extracted |= transport_value_splice_countdown;
+ }
+ pos++;
+ }
+
+ /* private data? */
+ if (adapflags & transport_adaptation_flag_private_data) {
+ if ((pos+1) > adapend)
+ return -1;
+ if ((pos+1+*pos) > adapend)
+ return -1;
+
+ if (extract & transport_value_private_data) {
+ out->private_data_length = *pos;
+ out->private_data = pos + 1;
+ extracted |= transport_value_private_data;
+ }
+ pos += 1 + *pos;
+ }
+
+ /* is there an adaptation extension? */
+ if (!(adapflags & transport_adaptation_flag_extension))
+ goto extract_payload;
+
+ /* get/check the length */
+ if (pos >= adapend)
+ return -1;
+ adapextlength = *pos++;
+ if ((pos + adapextlength) > adapend)
+ return -1;
+
+ /* do we want/have anything in the adaptation extension? */
+ if (((extract & 0xff00) == 0) || (adapextlength == 0))
+ goto extract_payload;
+
+ /* extract the adaptation extension flags (we must have at least 1 byte
+ * to be here) */
+ adapextflags = *pos++;
+
+ /* LTW? */
+ if (adapextflags & transport_adaptation_extension_flag_ltw) {
+ if ((pos+2) > adapend)
+ return -1;
+
+ if (extract & transport_value_ltw) {
+ if (*pos & 0x80) {
+ out->ltw_offset = ((pos[0] & 0x7f) << 8) |
+ (pos[1]);
+ extracted |= transport_value_ltw;
+ }
+ }
+ pos += 2;
+ }
+
+ /* piecewise_rate? */
+ if (adapextflags & transport_adaptation_extension_flag_piecewise_rate) {
+ if ((pos+3) > adapend)
+ return -1;
+
+ if (extract & transport_value_piecewise_rate) {
+ out->piecewise_rate = ((pos[0] & 0x3f) << 16) |
+ (pos[1] << 8) |
+ pos[2];
+ extracted |= transport_value_piecewise_rate;
+ }
+ pos += 3;
+ }
+
+ /* seamless_splice? */
+ if (adapextflags & transport_adaptation_extension_flag_seamless_splice) {
+ if ((pos+5) > adapend)
+ return -1;
+
+ if (extract & transport_value_piecewise_rate) {
+ out->splice_type = pos[0] >> 4;
+ out->dts_next_au = ((pos[0] & 0x0e) << 29) |
+ (pos[1] << 22) |
+ ((pos[2] & 0xfe) << 14) |
+ (pos[3] << 7) |
+ ((pos[4] & 0xfe) >> 1);
+ extracted |= transport_value_seamless_splice;
+ }
+ pos += 5;
+ }
+
+
+
+extract_payload:
+ /* does the packet contain a payload? */
+ if (pkt->adaptation_field_control & 1) {
+ int off = sizeof(struct transport_packet);
+ if (pkt->adaptation_field_control & 2)
+ off++;
+ off += adaplength;
+
+ out->payload = (uint8_t*) pkt + off;
+ out->payload_length = TRANSPORT_PACKET_LENGTH - off;
+ } else {
+ out->payload = NULL;
+ out->payload_length = 0;
+ }
+
+ out->flags = adapflags;
+ return extracted;
+}
+
+int transport_packet_continuity_check(struct transport_packet *pkt,
+ int discontinuity_indicator, unsigned char *cstate)
+{
+ unsigned char pktcontinuity = pkt->continuity_counter;
+ unsigned char prevcontinuity = *cstate & 0x0f;
+ unsigned char nextcontinuity;
+
+ /* NULL packets have undefined continuity */
+ if (transport_packet_pid(pkt) == TRANSPORT_NULL_PID)
+ return 0;
+
+ /* is the state valid? */
+ if (!(*cstate & CONTINUITY_VALID)) {
+ *cstate = pktcontinuity | CONTINUITY_VALID;
+ return 0;
+ }
+
+ /* check for discontinuity_indicator */
+ if (discontinuity_indicator) {
+ *cstate = pktcontinuity | CONTINUITY_VALID;
+ return 0;
+ }
+
+ /* only packets with a payload should increment the counter */
+ if (pkt->adaptation_field_control & 1)
+ nextcontinuity = (prevcontinuity + 1) & 0xf;
+ else
+ nextcontinuity = prevcontinuity;
+
+ /* check for a normal continuity progression */
+ if (nextcontinuity == pktcontinuity) {
+ *cstate = pktcontinuity | CONTINUITY_VALID;
+ return 0;
+ }
+
+ /* one dupe is allowed */
+ if ((prevcontinuity == pktcontinuity) && (!(*cstate & CONTINUITY_DUPESEEN))) {
+ *cstate = pktcontinuity | (CONTINUITY_VALID|CONTINUITY_DUPESEEN);
+ return 0;
+ }
+
+ /* continuity error */
+ return -1;
+}
diff --git a/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h
new file mode 100644
index 0000000..7dfbd78
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/transport_packet.h
@@ -0,0 +1,195 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_TRANSPORT_PACKET_H
+#define _UCSI_TRANSPORT_PACKET_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdint.h>
+#include "descriptor.h"
+
+#define TRANSPORT_PACKET_LENGTH 188
+#define TRANSPORT_PACKET_SYNC 0x47
+#define TRANSPORT_MAX_PIDS 0x2000
+#define TRANSPORT_NULL_PID 0x1fff
+
+
+/**
+ * Enumeration of adaptation field control values.
+ */
+enum transport_adaptation_field_control {
+ transport_adaptation_field_control_reserved = 0x00,
+ transport_adaptation_field_control_payload_only = 0x01,
+ transport_adaptation_field_control_adaptation_only = 0x02,
+ transport_adaptation_field_control_adaptation_payload = 0x03,
+};
+
+/**
+ * Enumeration of scrambling control values.
+ */
+enum transport_scrambling_control {
+ transport_scrambling_control_unscrambled = 0x00,
+ transport_scrambling_control_user_1 = 0x01,
+ transport_scrambling_control_user_2 = 0x02,
+ transport_scrambling_control_user_3 = 0x03,
+};
+
+/**
+ * Enumeration of adaptation flags.
+ */
+enum transport_adaptation_flags {
+ transport_adaptation_flag_discontinuity = 0x80,
+ transport_adaptation_flag_random_access = 0x40,
+ transport_adaptation_flag_es_priority = 0x20,
+ transport_adaptation_flag_pcr = 0x10,
+ transport_adaptation_flag_opcr = 0x08,
+ transport_adaptation_flag_splicing_point = 0x04,
+ transport_adaptation_flag_private_data = 0x02,
+ transport_adaptation_flag_extension = 0x01,
+};
+
+/**
+ * Enumeration of adaptation extension flags.
+ */
+enum transport_adaptation_extension_flags {
+ transport_adaptation_extension_flag_ltw = 0x80,
+ transport_adaptation_extension_flag_piecewise_rate = 0x40,
+ transport_adaptation_extension_flag_seamless_splice = 0x20,
+};
+
+/**
+ * Enumeration of flags controlling which values to extract using the
+ * transport_packet_values_extract() function.
+ */
+enum transport_value {
+ /* normal adaptation */
+ transport_value_pcr = 0x0001,
+ transport_value_opcr = 0x0002,
+ transport_value_splice_countdown = 0x0004,
+ transport_value_private_data = 0x0008,
+
+ /* extension adaptation */
+ transport_value_ltw = 0x0100,
+ transport_value_piecewise_rate = 0x0200,
+ transport_value_seamless_splice = 0x0400,
+};
+
+/**
+ * Structure describing a transport packet header.
+ */
+struct transport_packet {
+ uint8_t sync_byte;
+ EBIT4(uint8_t transport_error_indicator : 1; ,
+ uint8_t payload_unit_start_indicator : 1; ,
+ uint8_t transport_priority : 1; ,
+ uint8_t pid_hi : 5; );
+ uint8_t pid_lo;
+ EBIT3(uint8_t transport_scrambling_control : 2; ,
+ uint8_t adaptation_field_control : 2; ,
+ uint8_t continuity_counter : 4; );
+ /* values */
+} __ucsi_packed;
+
+/**
+ * Structure to extract values into using the transport_packet_values_extract()
+ * function.
+ */
+struct transport_values {
+ enum transport_adaptation_flags flags; /* always extracted */
+ uint8_t *payload; /* always extracted */
+ uint16_t payload_length; /* always extracted */
+
+ uint64_t pcr;
+ uint64_t opcr;
+ uint8_t splice_countdown;
+ uint8_t private_data_length;
+ uint8_t *private_data;
+ uint16_t ltw_offset;
+ uint32_t piecewise_rate;
+ uint8_t splice_type;
+ uint64_t dts_next_au;
+};
+
+/**
+ * Extract the PID from a transport packet.
+ *
+ * @param pkt The packet.
+ * @return The PID.
+ */
+static inline int transport_packet_pid(struct transport_packet *pkt)
+{
+ return (pkt->pid_hi << 8) | (pkt->pid_lo);
+}
+
+/**
+ * Process a buffer into a transport packet.
+ *
+ * @param buf Raw buffer.
+ * @return transport_packet pointer, or NULL on error.
+ */
+static inline struct transport_packet *transport_packet_init(unsigned char *buf)
+{
+ struct transport_packet *pkt = (struct transport_packet*) buf;
+
+ if (pkt->sync_byte != TRANSPORT_PACKET_SYNC)
+ return NULL;
+
+ if (transport_packet_pid(pkt) >= TRANSPORT_MAX_PIDS)
+ return NULL;
+
+ return pkt;
+}
+
+/**
+ * Check the continuity counter for a packet in a PID stream.
+ *
+ * @param pkt transport_packet to check.
+ * @param discontinuity_indicator Set to 1 if the packet's discontinuity_indicator flag is set.
+ * @param cstate Pointer to a single 8 bit character, used to store state for validating
+ * continuity. To initialise the state, simply set it to 0 before the first call.
+ * @return 0 if the continuity was correct, or nonzero on error. cstate will not be updated on error,
+ * it is up to the caller to clear it to accept the next packet.
+ */
+extern int transport_packet_continuity_check(struct transport_packet *pkt,
+ int discontinuity_indicator, unsigned char *cstate);
+
+/**
+ * Extract selected fields from a transport packet.
+ *
+ * @param pkt The packet.
+ * @param out Destination structure for values.
+ * @param extract Orred bitmask of enum transport_value - tells it what fields
+ * to extract if they are available.
+ * @return < 0 => error. Otherwise, an orred bitmask of enum transport_value
+ * telling you what fields were successfully extracted.
+ */
+extern int transport_packet_values_extract(struct transport_packet *pkt,
+ struct transport_values *out,
+ enum transport_value extract);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/lib/libucsi/types.h b/kaffeine/src/input/dvb/lib/libucsi/types.h
new file mode 100644
index 0000000..b01d79a
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libucsi/types.h
@@ -0,0 +1,36 @@
+/*
+ * section and descriptor parser
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _UCSI_TYPES_H
+#define _UCSI_TYPES_H 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef uint8_t iso639lang_t[3];
+typedef uint8_t iso639country_t[3];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kaffeine/src/input/dvb/plugins/Makefile.am b/kaffeine/src/input/dvb/plugins/Makefile.am
new file mode 100644
index 0000000..63f5318
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = epg stream \ No newline at end of file
diff --git a/kaffeine/src/input/dvb/plugins/epg/Makefile.am b/kaffeine/src/input/dvb/plugins/epg/Makefile.am
new file mode 100644
index 0000000..28ef5bf
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/epg/Makefile.am
@@ -0,0 +1,16 @@
+lib_LTLIBRARIES = libkaffeineepgplugin.la
+
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb \
+ -I$(top_srcdir)/kaffeine/src \
+ $(all_includes)
+
+kaffeineincludedir = $(includedir)/kaffeine
+kaffeineinclude_HEADERS = kaffeinedvbevents.h kaffeinedvbsection.h
+
+libkaffeineepgplugin_la_SOURCES = kaffeinedvbevents.cpp kaffeinedvbsection.cpp
+libkaffeineepgplugin_la_LIBADD = $(LIB_KPARTS)
+libkaffeineepgplugin_la_LDFLAGS = $(all_libraries) -version-info 0:1:0 -no-undefined
+
+kde_servicetypes_DATA = kaffeineepgplugin.desktop
diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.cpp b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.cpp
new file mode 100644
index 0000000..afa5e55
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.cpp
@@ -0,0 +1,496 @@
+/*
+ * kaffeinedvbevents.cpp
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <qdatetime.h>
+#include <qfile.h>
+
+#include <klocale.h>
+#include <kstandarddirs.h>
+
+#include "kaffeinedvbevents.h"
+
+
+
+ShortEvent::ShortEvent()
+{
+ name=text="";
+}
+
+ShortEvent::~ShortEvent()
+{
+}
+
+EventDesc::EventDesc()
+{
+ loop = 0;
+ nid=sid=tsid=eid=0;
+ tid=sn=lsn=running=0;
+ title=subtitle="";
+ source="";
+ shortEvents.setAutoDelete( true );
+ extEvents.setAutoDelete( true );
+}
+
+EventDesc::~EventDesc()
+{
+ shortEvents.clear();
+ extEvents.clear();
+}
+
+
+
+EventSid::EventSid( int s )
+{
+ sid = s;
+ events.setAutoDelete( true );
+}
+
+EventSid::~EventSid()
+{
+ QMutexLocker locker( &mutex );
+ events.clear();
+}
+
+void EventSid::remove( EventDesc *d )
+{
+ QMutexLocker locker( &mutex );
+ events.remove( d );
+}
+
+EventDesc *EventSid::getEventDesc( int n )
+{
+ QMutexLocker locker( &mutex );
+ return events.at(n);
+}
+
+
+
+EventTsid::EventTsid( int n, int t )
+{
+ tsid = t;
+ nid = n;
+ sidList.setAutoDelete( true );
+}
+
+EventTsid::~EventTsid()
+{
+ QMutexLocker locker( &mutex );
+ sidList.clear();
+}
+
+EventSid *EventTsid::getNEventSid( int n )
+{
+ QMutexLocker locker( &mutex );
+ return sidList.at( n );
+}
+
+EventSid *EventTsid::getEventSid( int sid )
+{
+ int i;
+
+ QMutexLocker locker( &mutex );
+ for ( i=0; i<(int)sidList.count(); i++ ) {
+ if ( sidList.at(i)->getSid()==sid )
+ return sidList.at(i);
+ }
+ EventSid *es = new EventSid( sid );
+ sidList.append( es );
+ return es;
+}
+
+EventDesc *EventTsid::getEventDesc( int sid, int n )
+{
+ int i;
+ EventSid *es=0;
+
+ mutex.lock();
+ for ( i=0; i<(int)sidList.count(); i++ ) {
+ if ( sidList.at(i)->getSid()==sid ) {
+ es = sidList.at(i);
+ break;
+ }
+ }
+ mutex.unlock();
+ if ( !es )
+ return 0;
+ return es->getEventDesc( n );
+}
+
+
+
+EventSource::EventSource( QString src )
+{
+ source = src;
+ tsidList.setAutoDelete( true );
+}
+
+EventSource::~EventSource()
+{
+ QMutexLocker locker( &mutex );
+ tsidList.clear();
+}
+
+EventTsid *EventSource::getNEventTsid( int n )
+{
+ QMutexLocker locker( &mutex );
+ return tsidList.at( n );
+}
+
+EventSid *EventSource::getEventSid( int nid, int tsid, int sid )
+{
+ int i;
+ EventTsid *et=0;
+
+ mutex.lock();
+ for ( i=0; i<(int)tsidList.count(); i++ ) {
+ if ( tsidList.at(i)->getTsid()==tsid && (nid==0 || tsidList.at(i)->getNid()==nid) ) {
+ et = tsidList.at(i);
+ break;
+ }
+ }
+ if ( !et ) {
+ if ( nid==0) {
+ mutex.unlock();
+ return 0;
+ }
+ et = new EventTsid( nid, tsid );
+ tsidList.append( et );
+ }
+ mutex.unlock();
+ return et->getEventSid( sid );
+}
+
+EventDesc *EventSource::getEventDesc( int nid, int tsid, int sid, int n )
+{
+ int i;
+ EventTsid *et=0;
+
+ mutex.lock();
+ for ( i=0; i<(int)tsidList.count(); i++ ) {
+ if ( tsidList.at(i)->getTsid()==tsid && (nid==0 || tsidList.at(i)->getNid()==nid) ) {
+ et = tsidList.at(i);
+ break;
+ }
+ }
+ mutex.unlock();
+ if ( !et )
+ return 0;
+ return et->getEventDesc( sid, n );
+}
+
+
+
+
+EventTable::EventTable()
+{
+ srcList.setAutoDelete( true );
+ connect ( &cleanTimer, SIGNAL(timeout()), this, SLOT(setClean()) );
+ cleanTimer.start( 10000 );
+ epgLoaded = false;
+}
+
+EventTable::~EventTable()
+{
+ QMutexLocker locker( &mutex );
+ srcList.clear();
+}
+
+void EventTable::saveEpg()
+{
+ EventSource *esrc;
+ EventTsid *et;
+ EventSid *es;
+ QPtrList<EventDesc> *esEvents;
+ EventDesc *desc;
+ int i, k, j, m, n;
+ QCString c;
+ int count=0;
+ unsigned char sync=0xff;
+ QTime t1=QTime::currentTime();
+
+ QFile f( locateLocal("appdata", "dvbepg.data" ) );
+ if ( f.open(IO_WriteOnly|IO_Truncate) ) {
+ QDataStream dt( &f );
+ for( i=0; i<getNSource(); i++ ) {
+ if ( !(esrc=getNEventSource( i )) )
+ continue;
+ for ( m=0; m<esrc->getNTsid(); m++ ) {
+ if ( !(et=esrc->getNEventTsid( m )) )
+ continue;
+ for ( n=0; n<et->getNSid(); n++ ) {
+ if ( !(es=et->getNEventSid( n )) )
+ continue;
+ esEvents = es->getEvents();
+ es->lock();
+ for ( j=0; j<(int)esEvents->count(); j++ ) {
+ if ( !(desc=esEvents->at( j )) )
+ continue;
+ dt << sync; // sync byte
+ c = desc->source.utf8();
+ dt << c.data();
+ dt << desc->tid;
+ dt << desc->sid;
+ dt << desc->tsid;
+ dt << desc->nid;
+ dt << desc->sn;
+ dt << desc->lsn;
+ dt << desc->eid;
+ dt << desc->running;
+ dt << desc->startDateTime.toTime_t();
+ dt << (uint)((desc->duration.hour()*3600)+(desc->duration.minute()*60)+desc->duration.second());
+ dt << desc->shortEvents.count();
+ for ( k=0; k<(int)desc->shortEvents.count(); k++ ) {
+ c = desc->shortEvents.at(k)->name.utf8();
+ dt << c.data();
+ c = desc->shortEvents.at(k)->text.utf8();
+ dt << c.data();
+ }
+ dt << (uint)desc->extEvents.count();
+ for ( k=0; k<(int)desc->extEvents.count(); k++ ) {
+ c = desc->extEvents.at(k)->utf8();
+ dt << c.data();
+ }
+ c = desc->title.utf8();
+ dt << c.data();
+ c = desc->subtitle.utf8();
+ dt << c.data();
+ ++count;
+ }
+ es->unlock();
+ }
+ }
+ }
+ f.close();
+ fprintf( stderr, "Saved epg data : %d events (%d msecs)\n", count, t1.msecsTo(QTime::currentTime()) );
+ }
+}
+
+void EventTable::loadEpg()
+{
+ EventDesc *desc;
+ ShortEvent *sev;
+ EventSid *slist;
+ uint count, tmp, i;
+#define EPGBUFSIZE 500
+ char buf[EPGBUFSIZE];
+ int num=0;
+ unsigned char sync;
+ QDateTime cur=QDateTime::currentDateTime();
+ QTime t1=QTime::currentTime();
+
+ if ( epgLoaded )
+ return;
+
+ epgLoaded = true;
+ QFile f( locateLocal("appdata", "dvbepg.data" ) );
+ if ( f.open(IO_ReadOnly) ) {
+ QDataStream dt( &f );
+ while (!dt.eof() ) {
+ dt >> sync;
+ if ( sync!=0xff ) {
+ f.close();
+ fprintf( stderr, "Sync error while loading epg data : %d events loaded\n", num );
+ return;
+ }
+ desc = new EventDesc();
+ dt >> tmp;
+ if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return;
+ dt.readRawBytes( buf, tmp );
+ desc->source = QString::fromUtf8( buf );
+ dt >> desc->tid;
+ dt >> desc->sid;
+ dt >> desc->tsid;
+ dt >> desc->nid;
+ dt >> desc->sn;
+ dt >> desc->lsn;
+ dt >> desc->eid;
+ dt >> desc->running;
+ dt >> tmp;
+ desc->startDateTime.setTime_t( tmp );
+ dt >> tmp;
+ desc->duration = QTime().addSecs( tmp );
+ dt >> count;
+ for ( i=0; i<count; i++ ) {
+ sev = new ShortEvent();
+ dt >> tmp;
+ if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return;
+ dt.readRawBytes( buf, tmp );
+ sev->name = QString::fromUtf8( buf );
+ dt >> tmp;
+ if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return;
+ dt.readRawBytes( buf, tmp );
+ sev->text = QString::fromUtf8( buf );
+ desc->shortEvents.append( sev );
+ }
+ dt >> count;
+ for ( i=0; i<count; i++ ) {
+ dt >> tmp;
+ if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return;
+ dt.readRawBytes( buf, tmp );
+ desc->extEvents.append( new QString( QString::fromUtf8( buf ) ) );
+ }
+ dt >> tmp;
+ if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return;
+ dt.readRawBytes( buf, tmp );
+ desc->title = QString::fromUtf8( buf );
+ dt >> tmp;
+ if ( !validString( f, desc, tmp, EPGBUFSIZE, num ) ) return;
+ dt.readRawBytes( buf, tmp );
+ desc->subtitle = QString::fromUtf8( buf );
+ if ( desc->startDateTime.addSecs( (desc->duration.hour()*3600)+(desc->duration.minute()*60)+desc->duration.second() )<cur )
+ delete desc;
+ else {
+ slist = getEventSource( desc->source )->getEventSid( desc->nid, desc->tsid, desc->sid );
+ if ( !slist )
+ continue;
+ slist->lock();
+ slist->getEvents()->append( desc );
+ slist->unlock();
+ ++num;
+ }
+ }
+ f.close();
+ fprintf( stderr, "Loaded epg data : %d events (%d msecs)\n", num, t1.msecsTo(QTime::currentTime()) );
+ }
+}
+
+bool EventTable::validString( QFile &f, EventDesc *d, int len, int buflen, int nev )
+{
+ if ( len<1 || len>buflen ) {
+ f.close();
+ fprintf( stderr, "Error while loading epg data : %d events loaded\n", nev );
+ delete d;
+ return false;
+ }
+ return true;
+}
+
+void EventTable::setClean()
+{
+ start();
+}
+
+void EventTable::doClean( bool b )
+{
+ if ( b ) {
+ if ( cleanTimer.isActive() )
+ return;
+ cleanTimer.start( 10000 );
+ }
+ else {
+ cleanTimer.stop();
+ wait();
+ }
+}
+
+void EventTable::run()
+{
+ int k, m, n, sec;
+ EventSource *esrc;
+ EventTsid *et;
+ EventSid *es;
+ EventDesc *desc;
+ QDateTime dt, cur;
+
+ setpriority(PRIO_PROCESS, 0, 19);
+
+ cur = QDateTime::currentDateTime();
+ for( k=0; k<getNSource(); k++ ) {
+ if ( !(esrc=getNEventSource( k )) )
+ continue;
+ for ( m=0; m<esrc->getNTsid(); m++ ) {
+ if ( !(et=esrc->getNEventTsid( m )) )
+ continue;
+ for ( n=0; n<et->getNSid(); n++ ) {
+ if ( !(es=et->getNEventSid( n )) )
+ continue;
+ if ( !(desc=es->getEventDesc( 0 )) )
+ continue;
+ dt = desc->startDateTime;
+ sec = desc->duration.hour()*3600+desc->duration.minute()*60+desc->duration.second();
+ if ( dt.addSecs( sec )<cur )
+ es->remove( desc );
+ }
+ }
+ }
+}
+
+EventSource *EventTable::getNEventSource( int n )
+{
+ QMutexLocker locker( &mutex );
+ return srcList.at( n );
+}
+
+EventSource *EventTable::getEventSource( QString src )
+{
+ int i;
+
+ QMutexLocker locker( &mutex );
+ for ( i=0; i<(int)srcList.count(); i++ ) {
+ if ( srcList.at(i)->getSource()==src )
+ return srcList.at(i);
+ }
+ EventSource *es = new EventSource( src );
+ srcList.append( es );
+ return es;
+}
+
+EventDesc *EventTable::getEventDesc( QString src, int nid, int tsid, int sid, int n )
+{
+ int i;
+ EventSource *es=0;
+
+ mutex.lock();
+ for ( i=0; i<(int)srcList.count(); i++ ) {
+ if ( srcList.at(i)->getSource()==src ) {
+ es = srcList.at(i);
+ break;
+ }
+ }
+ mutex.unlock();
+ if ( !es )
+ return 0;
+ return es->getEventDesc( nid, tsid, sid, n );
+}
+
+
+
+KaffeineEpgPlugin::KaffeineEpgPlugin( QObject* parent, const char* name ) : KParts::Part( parent, name )
+{
+}
+
+KaffeineEpgPlugin::~KaffeineEpgPlugin()
+{
+}
+
+bool KaffeineEpgPlugin::safeLen( unsigned char* buf )
+{
+ if ( buf<(secbuf+readSize) )
+ return true;
+ fprintf( stderr, "EIT (%d:%d) : buffer overflow! Rejected\n", adapter, tuner );
+ return false;
+}
+
+#include "kaffeinedvbevents.moc"
diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.h b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.h
new file mode 100644
index 0000000..07dbd16
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbevents.h
@@ -0,0 +1,177 @@
+/*
+ * kaffeinedvbevents.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KAFFEINEDVBEVENTS_H
+#define KAFFEINEDVBEVENTS_H
+
+#include <qtimer.h>
+#include <qmutex.h>
+#include <qfile.h>
+#include <qobject.h>
+
+#include <kparts/part.h>
+
+#include "kaffeinedvbsection.h"
+
+
+
+class ShortEvent
+{
+
+public:
+
+ ShortEvent();
+ ~ShortEvent();
+
+ QString name;
+ QString text;
+};
+
+class EventDesc
+{
+
+public:
+
+ EventDesc();
+ ~EventDesc();
+
+ QString source;
+ unsigned char tid;
+ unsigned short sid;
+ unsigned short tsid;
+ unsigned short nid;
+ unsigned char sn;
+ unsigned char lsn;
+ unsigned short eid;
+ unsigned char running;
+ QDateTime startDateTime;
+ QTime duration;
+ QPtrList<ShortEvent> shortEvents;
+ QPtrList<QString> extEvents;
+ QString title;
+ QString subtitle;
+ unsigned int loop;
+};
+
+
+
+class EventSid
+{
+public:
+ EventSid( int s );
+ ~EventSid();
+ int getSid() { return sid; }
+ void lock() { mutex.lock(); }
+ void unlock() { mutex.unlock(); }
+ QPtrList<EventDesc> *getEvents() { return &events; }
+ EventDesc *getEventDesc( int n );
+ int getNDesc() { return events.count(); }
+ void remove( EventDesc *d );
+private:
+ QMutex mutex;
+ int sid;
+ QPtrList<EventDesc> events;
+};
+
+
+
+class EventTsid
+{
+public:
+ EventTsid( int n, int t );
+ ~EventTsid();
+ int getTsid() { return tsid; }
+ int getNid() { return nid; }
+ EventSid *getEventSid( int sid );
+ EventSid *getNEventSid( int n );
+ int getNSid() { return sidList.count(); }
+ EventDesc *getEventDesc( int sid, int n );
+private:
+ QMutex mutex;
+ int tsid, nid;
+ QPtrList<EventSid> sidList;
+};
+
+
+
+class EventSource
+{
+public:
+ EventSource( QString src );
+ ~EventSource();
+ EventSid *getEventSid( int nid, int tsid, int sid );
+ EventTsid *getNEventTsid( int n );
+ int getNTsid() { return tsidList.count(); }
+ EventDesc *getEventDesc( int nid, int tsid, int sid, int n );
+ QString getSource() { return source; }
+private:
+ QMutex mutex;
+ QString source;
+ QPtrList<EventTsid> tsidList;
+};
+
+
+
+class EventTable : public QObject, public QThread
+{
+ Q_OBJECT
+public:
+ EventTable();
+ ~EventTable();
+ EventSource *getEventSource( QString src );
+ EventDesc *getEventDesc( QString src, int nid, int tsid, int sid, int n );
+ EventSource *getNEventSource( int n );
+ int getNSource() { return srcList.count(); }
+ void doClean( bool b );
+ void saveEpg();
+ void loadEpg();
+protected:
+ virtual void run();
+private:
+ bool validString( QFile &f, EventDesc *d, int len, int buflen, int nev );
+ QMutex mutex;
+ QPtrList<EventSource> srcList;
+ QTimer cleanTimer;
+ bool epgLoaded;
+private slots:
+ void setClean();
+};
+
+
+
+class KDE_EXPORT KaffeineEpgPlugin : public KParts::Part, public KaffeineDVBsection
+{
+ Q_OBJECT
+public:
+ KaffeineEpgPlugin( QObject* parent, const char* name );
+ virtual ~KaffeineEpgPlugin();
+ virtual bool go( QString /*src*/, int /*freqKhz*/ ) { return false; }
+ virtual void stop() {}
+ void setTable( EventTable *table ) { events = table; }
+
+protected:
+ bool safeLen( unsigned char* buf );
+
+ unsigned char secbuf[4096];
+ int readSize;
+ EventTable *events;
+};
+
+#endif /* KAFFEINEDVBEVENTS_H */
diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp
new file mode 100644
index 0000000..d6170e8
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.cpp
@@ -0,0 +1,327 @@
+/*
+ * kaffeinedvbsection.cpp
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <iconv.h>
+
+#include <klocale.h>
+
+#include "kaffeinedvbsection.h"
+
+
+
+KaffeineDVBsection::KaffeineDVBsection()
+{
+}
+
+
+
+KaffeineDVBsection::KaffeineDVBsection( int anum, int tnum, const QString &charset )
+{
+ initSection( anum, tnum, charset );
+}
+
+
+
+void KaffeineDVBsection::initSection( int anum, int tnum, const QString &charset )
+{
+ defaultCharset = charset.ascii();
+ adapter = anum;
+ tuner = tnum;
+ isRunning = false;
+ fdDemux = -1;
+}
+
+
+
+KaffeineDVBsection::~KaffeineDVBsection()
+{
+ if ( fdDemux>-1 )
+ close( fdDemux );
+}
+
+
+
+bool KaffeineDVBsection::setFilter( int pid, int tid, int timeout, bool checkcrc )
+{
+ struct dmx_sct_filter_params sctfilter;
+ QString demuxer = QString("/dev/dvb/adapter%1/demux%2").arg( adapter ).arg( tuner );
+
+ if ((fdDemux = open( demuxer.ascii(), O_RDWR | O_NONBLOCK )) < 0) {
+ perror ("open failed");
+ return false;
+ }
+
+ pf[0].fd = fdDemux;
+ pf[0].events = POLLIN;
+
+ memset( &sctfilter, 0, sizeof( sctfilter ) );
+
+ sctfilter.pid = pid;
+ if ( tid<256 && tid>0 ) {
+ sctfilter.filter.filter[0] = tid;
+ sctfilter.filter.mask[0] = 0xff;
+ }
+ sctfilter.flags = DMX_IMMEDIATE_START;
+ if ( checkcrc )
+ sctfilter.flags|= DMX_CHECK_CRC;
+ sctfilter.timeout = timeout;
+
+ if ( ioctl( fdDemux, DMX_SET_FILTER, &sctfilter ) < 0 ) {
+ perror ( "ioctl DMX_SET_FILTER failed" );
+ return false;
+ }
+ return true;
+}
+
+
+
+void KaffeineDVBsection::stopFilter()
+{
+ ioctl( fdDemux, DMX_STOP );
+ close( fdDemux );
+ fdDemux = -1;
+}
+
+
+
+unsigned int KaffeineDVBsection::getBits( unsigned char *b, int offbits, int nbits )
+{
+ int i, nbytes;
+ unsigned int ret = 0;
+ unsigned char *buf;
+
+ buf = b+(offbits/8);
+ offbits %=8;
+ nbytes = (offbits+nbits)/8;
+ if ( ((offbits+nbits)%8)>0 )
+ nbytes++;
+ for ( i=0; i<nbytes; i++ )
+ ret += buf[i]<<((nbytes-i-1)*8);
+ i = (4-nbytes)*8+offbits;
+ ret = ((ret<<i)>>i)>>((nbytes*8)-nbits-offbits);
+
+ return ret;
+}
+
+
+
+bool KaffeineDVBsection::doIconv( QCString &s, QCString table, char *buffer, int buflen )
+{
+ size_t inSize, outSize=buflen;
+ char *inBuf, *outBuf;
+ iconv_t cd;
+
+ inSize = s.length();
+ if ( inSize<1 )
+ return false;
+ cd = iconv_open( "UTF8", table );
+ inBuf = s.data();
+ outBuf = buffer;
+ outBuf[0] = 0;
+ iconv( cd, &inBuf, &inSize, &outBuf, &outSize );
+ *outBuf = 0;
+ iconv_close( cd );
+ return true;
+}
+
+
+
+QString KaffeineDVBsection::getText( unsigned char *buf, int length )
+{
+ QCString s;
+ QString ret="";
+ int i=0;
+ char buffer[1000];
+ QCString table=defaultCharset;
+
+ if ( length==0 )
+ return "";
+
+ while ( i<length ) {
+ if ( buf[i]<0x20 && (i+2)<length ) {
+ if ( !s.isEmpty() ) {
+ if ( doIconv( s, table, buffer, sizeof(buffer) ) ) {
+ ret += QString::fromUtf8( buffer );
+ s = "";
+ }
+ }
+ switch ( buf[i] ) {
+ case 0x01: table = "ISO8859-5"; ++i; break;
+ case 0x02: table = "ISO8859-6"; ++i; break;
+ case 0x03: table = "ISO8859-7"; ++i; break;
+ case 0x04: table = "ISO8859-8"; ++i; break;
+ case 0x05: table = "ISO8859-9"; ++i; break;
+ case 0x06: table = "ISO8859-10"; ++i; break;
+ case 0x07: table = "ISO8859-11"; ++i; break;
+ case 0x09: table = "ISO8859-13"; ++i; break;
+ case 0x0A: table = "ISO8859-14"; ++i; break;
+ case 0x0B: table = "ISO8859-15"; ++i; break;
+ case 0x13: table = "GB2312"; ++i; break;
+ case 0x14: table = "BIG5"; ++i; break;
+ case 0x10: {
+ switch ( buf[i+2] ) {
+ case 0x01: table = "ISO8859-1"; break;
+ case 0x02: table = "ISO8859-2"; break;
+ case 0x03: table = "ISO8859-3"; break;
+ case 0x04: table = "ISO8859-4"; break;
+ case 0x05: table = "ISO8859-5"; break;
+ case 0x06: table = "ISO8859-6"; break;
+ case 0x07: table = "ISO8859-7"; break;
+ case 0x08: table = "ISO8859-8"; break;
+ case 0x09: table = "ISO8859-9"; break;
+ case 0x0A: table = "ISO8859-10"; break;
+ case 0x0B: table = "ISO8859-11"; break;
+ case 0x0D: table = "ISO8859-13"; break;
+ case 0x0E: table = "ISO8859-14"; break;
+ case 0x0F: table = "ISO8859-15"; break;
+ }
+ i+= 3;
+ break;
+ }
+ default: ++i;
+ }
+ }
+
+ if ( buf[i]>=0x80 && buf[i]<=0x9f ) {
+ ++i;
+ continue; // control codes
+ }
+ s += buf[i++];
+ }
+
+ if ( !s.isEmpty() ) {
+ if ( doIconv( s, table, buffer, sizeof(buffer) ) ) {
+ ret += QString::fromUtf8( buffer );
+ }
+ }
+ return ret;
+}
+
+
+
+QString KaffeineDVBsection::langDesc( unsigned char* buf )
+{
+ char c[4];
+ QString s;
+
+ memset( mempcpy( c, buf+2, 3 ), 0, 1 );
+ s = c;
+ return s;
+}
+
+
+
+QTime KaffeineDVBsection::getTime( unsigned char *buf )
+{
+ int h, m, s;
+
+ h = ((getBits(buf,0,4)*10)+getBits(buf,4,4))%24;
+ m = ((getBits(buf,8,4)*10)+getBits(buf,12,4))%60;
+ s = ((getBits(buf,16,4)*10)+getBits(buf,20,4))%60;
+ return QTime( h, m, s );
+}
+
+
+
+QDate KaffeineDVBsection::getDate( unsigned char *buf )
+{
+ int i, j, m, D, Y, M, k, mjd;
+
+ mjd = getBits(buf,0,16);
+ i = (int)((mjd-15078.2)/365.25);
+ j = (int)(i*365.25);
+ m = (int)((mjd-14956.1-j)/30.6001);
+ D = mjd-14956-j-(int)(m*30.6001);
+ if ( m==14 || m==15 )
+ k = 1;
+ else
+ k = 0;
+ Y = i+k+1900;
+ M = m-1-k*12;
+
+ return QDate( (Y>=1970)?Y:1970, (M>0 && M<13)?M:1, (D>0 && D<32)?D:1 );
+}
+
+
+
+QDateTime KaffeineDVBsection::getDateTime( unsigned char *buf )
+{
+ /*int hh, mm, ss;
+ int i, j, m, D, Y, M, k, mjd;
+ int sec;
+
+ mjd = getBits(buf,0,16);
+ i = (int)((mjd-15078.2)/365.25);
+ j = (int)(i*365.25);
+ m = (int)((mjd-14956.1-j)/30.6001);
+ D = mjd-14956-j-(int)(m*30.6001);
+ if ( m==14 || m==15 ) k = 1;
+ else k = 0;
+ Y = i+k+1900;
+ M = m-1-k*12;
+
+ hh = ((getBits(buf+2,0,4)*10)+getBits(buf+2,4,4))%24;
+ mm = ((getBits(buf+2,8,4)*10)+getBits(buf+2,12,4))%60;
+ ss = ((getBits(buf+2,16,4)*10)+getBits(buf+2,20,4))%60;
+
+ QDateTime dt( QDate( (Y>=1970)?Y:1970, (M>0 && M<13)?M:1, (D>0 && D<32)?D:1 ), QTime( hh, mm, ss ) );
+ QDateTime u( QDate( 1970, 1, 1 ), QTime( 0, 0, 0 ) );
+ sec = u.secsTo( dt );
+ u.setTime_t( sec ); // UTC to local
+ return u;*/
+
+ int i, j, m, k, mjd;
+ struct tm tt;
+ struct tm *t=&tt;
+
+ mjd = getBits(buf,0,16);
+ i = (int)((mjd-15078.2)/365.25);
+ j = (int)(i*365.25);
+ m = (int)((mjd-14956.1-j)/30.6001);
+ t->tm_mday = mjd-14956-j-(int)(m*30.6001);
+ if ( m==14 || m==15 )
+ k = 1;
+ else
+ k = 0;
+ t->tm_year = i+k;
+ t->tm_mon = m-1-k*12-1;
+ t->tm_sec = ((getBits(buf+2,16,4)*10)+getBits(buf+2,20,4))%60;
+ t->tm_min = ((getBits(buf+2,8,4)*10)+getBits(buf+2,12,4))%60;
+ t->tm_hour = ((getBits(buf+2,0,4)*10)+getBits(buf+2,4,4))%24;
+ t->tm_isdst = -1;
+ t->tm_gmtoff = 0;
+
+ time_t p=timegm(t);
+ if ( p>0 ) {
+ t = localtime(&p);
+ return QDateTime( QDate( t->tm_year+1900, t->tm_mon+1, t->tm_mday ), QTime( t->tm_hour, t->tm_min, t->tm_sec ) );
+ }
+ else
+ return QDateTime( QDate( 1970, 1, 1 ), QTime( 0, 0, 0 ) );
+}
diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.h b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.h
new file mode 100644
index 0000000..af451f2
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/epg/kaffeinedvbsection.h
@@ -0,0 +1,64 @@
+/*
+ * kaffeinedvbsection.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KAFFEINEDVBSECTION_H
+#define KAFFEINEDVBSECTION_H
+
+#include <sys/poll.h>
+#include <linux/dvb/dmx.h>
+
+#include <qthread.h>
+#include <qdatetime.h>
+
+
+
+class KaffeineDVBsection : public QThread
+{
+
+public:
+
+ KaffeineDVBsection();
+ KaffeineDVBsection( int anum, int tnum, const QString &charset="ISO8859-1" );
+ ~KaffeineDVBsection();
+ void initSection( int anum, int tnum, const QString &charset="ISO8859-1" );
+ static unsigned int getBits( unsigned char *b, int offbits, int nbits );
+
+protected:
+
+ virtual void run() {}
+ QString langDesc( unsigned char* buf );
+ bool setFilter( int pid, int tid, int timeout=5000, bool checkcrc=true );
+ void stopFilter();
+ QString getText( unsigned char *buf, int length );
+ bool doIconv( QCString &s, QCString table, char *buffer, int buflen );
+ QTime getTime( unsigned char *buf );
+ QDate getDate( unsigned char *buf );
+ QDateTime getDateTime( unsigned char *buf );
+
+ int fdDemux;
+ int indexChannels;
+ bool isRunning;
+ int adapter;
+ int tuner;
+ QCString defaultCharset;
+ struct pollfd pf[1];
+};
+
+#endif /* KAFFEINEDVBSECTION_H */
diff --git a/kaffeine/src/input/dvb/plugins/epg/kaffeineepgplugin.desktop b/kaffeine/src/input/dvb/plugins/epg/kaffeineepgplugin.desktop
new file mode 100644
index 0000000..2a71d4f
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/epg/kaffeineepgplugin.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=ServiceType
+X-KDE-ServiceType=KaffeineEpgPlugin
diff --git a/kaffeine/src/input/dvb/plugins/stream/Makefile.am b/kaffeine/src/input/dvb/plugins/stream/Makefile.am
new file mode 100644
index 0000000..3d3f9b9
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/stream/Makefile.am
@@ -0,0 +1,16 @@
+lib_LTLIBRARIES = libkaffeinedvbplugin.la
+
+METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb \
+ -I$(top_srcdir)/kaffeine/src \
+ $(all_includes)
+
+kaffeineincludedir = $(includedir)/kaffeine
+kaffeineinclude_HEADERS = kaffeinedvbplugin.h
+
+libkaffeinedvbplugin_la_SOURCES = kaffeinedvbplugin.cpp
+libkaffeinedvbplugin_la_LIBADD = $(LIB_KPARTS)
+libkaffeinedvbplugin_la_LDFLAGS = $(all_libraries) -version-info 0:1:0 -no-undefined
+
+kde_servicetypes_DATA = kaffeinedvbplugin.desktop
diff --git a/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.cpp b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.cpp
new file mode 100644
index 0000000..bd3e5b3
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.cpp
@@ -0,0 +1,30 @@
+/*
+ * kaffeinedvbplugin.cpp
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "kaffeinedvbplugin.h"
+#include "kaffeinedvbplugin.moc"
+
+KaffeineDvbPlugin::KaffeineDvbPlugin(QObject* parent, const char* name) : KParts::Part( parent, name )
+{
+}
+
+KaffeineDvbPlugin::~KaffeineDvbPlugin()
+{
+}
diff --git a/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.desktop b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.desktop
new file mode 100644
index 0000000..cc28b16
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.desktop
@@ -0,0 +1,4 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=ServiceType
+X-KDE-ServiceType=KaffeineDvbPlugin
diff --git a/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.h b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.h
new file mode 100644
index 0000000..f112397
--- /dev/null
+++ b/kaffeine/src/input/dvb/plugins/stream/kaffeinedvbplugin.h
@@ -0,0 +1,52 @@
+/*
+ * kaffeinedvbplugin.h
+ *
+ * Copyright (C) 2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KAFFEINEDVBPLUGIN_H
+#define KAFFEINEDVBPLUGIN_H
+
+#include <qpopupmenu.h>
+#include <qstring.h>
+
+#include <kparts/part.h>
+#include <kconfig.h>
+
+/*
+ * Base-Class for Kaffeine DVB plugins.
+ */
+
+class KDE_EXPORT KaffeineDvbPlugin : public KParts::Part
+{
+ Q_OBJECT
+public:
+ KaffeineDvbPlugin(QObject* parent, const char* name);
+ virtual ~KaffeineDvbPlugin();
+ virtual QString pluginName() { return QString(); }
+
+ // returns a "handle".
+ virtual void* init( int /*sid*/ , int /*anum*/, int /*tnum*/, int /*fta*/ ) { return NULL; }
+
+ virtual void process( void* /*handle*/, unsigned char* /*buf*/, int /*len*/ ) {};
+ virtual void close( void* /*handle*/ ) {};
+
+public slots:
+ virtual void configDialog() {};
+};
+
+#endif /* KAFFEINEDVBPLUGIN_H */
diff --git a/kaffeine/src/input/dvb/scandialog.cpp b/kaffeine/src/input/dvb/scandialog.cpp
new file mode 100644
index 0000000..2399c74
--- /dev/null
+++ b/kaffeine/src/input/dvb/scandialog.cpp
@@ -0,0 +1,1019 @@
+/*
+ * scandialog.cpp
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qlayout.h>
+#include <qdir.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qgroupbox.h>
+#include <qlistview.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qwhatsthis.h>
+#include <qapplication.h>
+#include <qaccel.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+#include "scandialog.h"
+#include "channeleditor.h"
+#include "dvbsi.h"
+
+
+
+DListViewItem::DListViewItem( QListView *parent, ChannelDesc *desc, QString label1, QString label2 )
+ : QListViewItem( parent, label1, label2 )
+{
+ chan = desc;
+}
+
+
+
+ScanDialog::ScanDialog( QPtrList<DvbStream> *d, QPtrList<ChannelDesc> *ch, QSize size, QString src, const QString &charset )
+{
+ QString s;
+ int i, j;
+ QStringList list, tmp;
+
+ KIconLoader *icon = new KIconLoader();
+ tvPix = icon->loadIcon( "kdvbtv", KIcon::Small );
+ tvcPix = icon->loadIcon( "kdvbtvc", KIcon::Small );
+ raPix = icon->loadIcon( "kdvbra", KIcon::Small );
+ racPix = icon->loadIcon( "kdvbrac", KIcon::Small );
+
+ chandesc = ch;
+ dvbsi = 0;
+ dvb = d;
+ sourcesPath = src;
+ defaultCharset = charset;
+
+ for ( i=0; i<(int)dvb->count(); i++ ) {
+ tmp = dvb->at(i)->getSources( true );
+ for ( j=0; j<(int)tmp.count(); j++ ) {
+ if ( tmp[j].startsWith( "AUTO" ) )
+ list.append( QString("AUTO(%1:%2)").arg(dvb->at(i)->getAdapter()).arg(dvb->at(i)->getTuner()) );
+ else
+ list.append( tmp[j] );
+ }
+ }
+ searchComb->insertStringList( list );
+
+ setCaption( i18n("Channels") );
+
+ transponders.setAutoDelete( true );
+
+ QGridLayout *statLayout = new QGridLayout( statusFrame, 1, 1, 11, 6 );
+
+ QLabel *lab = new QLabel( i18n("Signal:"), statusFrame );
+ statLayout->addWidget( lab, 0, 0 );
+ signal = new KGradProgress( statusFrame );
+ statLayout->addWidget( signal, 0, 1 );
+ lab = new QLabel( i18n("SNR:"), statusFrame );
+ statLayout->addWidget( lab, 1, 0 );
+ snr = new KGradProgress( statusFrame );
+ statLayout->addWidget( snr, 1, 1 );
+ lab = new QLabel( i18n("Tuned:"), statusFrame );
+ statLayout->addWidget( lab, 2, 0 );
+ lock = new KLed( statusFrame, "lockLed" );
+ lock->setState( KLed::Off );
+ lock->setDarkFactor( 500 );
+ statLayout->addWidget( lock, 2, 1 );
+ progress = new QProgressBar( 100, statusFrame );
+ progress->setIndicatorFollowsStyle( false );
+ progress->setProgress( 0 );
+ statLayout->addMultiCellWidget( progress, 3, 3, 0, 1 );
+ progressLab = new QLabel( statusFrame );
+ statLayout->addMultiCellWidget( progressLab, 4, 4, 0, 1 );
+
+ channelsList->clear();
+ foundList->clear();
+ foundList->setAllColumnsShowFocus( true );
+ foundList->setSelectionMode( QListView::Extended );
+ channelsList->setSorting( 0 );
+
+ ChannelDesc *chan;
+ QListViewItem *it;
+ for ( int i=0; i<(int)chandesc->count(); i++ ) {
+ chan = chandesc->at(i);
+ it = new QListViewItem( channelsList, chan->name );
+ if ( !chan->pix.isNull() )
+ it->setPixmap( 0, chan->pix );
+ else {
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ it->setPixmap( 0, tvcPix );
+ else
+ it->setPixmap( 0, tvPix );
+ }
+ else {
+ if ( chan->fta )
+ it->setPixmap( 0, racPix );
+ else
+ it->setPixmap( 0, raPix );
+ }
+ }
+ }
+
+ startBtn->setPaletteForegroundColor( QColor(255,0,0) );
+
+ connect( searchComb, SIGNAL(activated(int)), this, SLOT(setDvb(int)) );
+
+ ds = dvb->at(0);
+ ds->setScanning( true );
+ if ( searchComb->currentText().startsWith( "AUTO" ) )
+ offsetGroup->show();
+ else
+ offsetGroup->hide();
+ bool ok=false;
+ dvbsi = new DVBsi( &ok, ds->getAdapter(), ds->getTuner(), ds, defaultCharset );
+ connect( ds, SIGNAL(snrStatus(int)), snr, SLOT(setProgress(int)) );
+ connect( ds, SIGNAL(signalStatus(int)), signal, SLOT(setProgress(int)) );
+ connect( ds, SIGNAL(lockStatus(bool)), this, SLOT(setLock(bool)) );
+ connect( dvbsi, SIGNAL(end(bool)), this, SLOT(siEnded(bool)) );
+
+ connect( &checkTimer, SIGNAL( timeout() ), this, SLOT( checkNewChannel() ) );
+ connect( &progressTimer, SIGNAL( timeout() ), this, SLOT( setProgress() ) );
+ connect( startBtn, SIGNAL(toggled(bool)), this, SLOT(scan(bool)) );
+ connect( addfilteredBtn, SIGNAL(clicked()), this, SLOT(addFiltered()) );
+ connect( addselectedBtn, SIGNAL(clicked()), this, SLOT(addSelected()) );
+ connect( channelsList, SIGNAL(contextMenuRequested(QListViewItem*,const QPoint&,int)), this, SLOT(pop(QListViewItem*,const QPoint&,int)) );
+ connect( channelsList, SIGNAL(doubleClicked(QListViewItem*,const QPoint &,int)), this, SLOT( slotChannelChanged(QListViewItem*,const QPoint &,int) ) );
+ connect( newBtn, SIGNAL(clicked()), this, SLOT(newChannel()) );
+ connect( delBtn, SIGNAL(clicked()), this, SLOT(deleteAll()) );
+ connect( selectallBtn, SIGNAL(clicked()), this, SLOT(selectAll()) );
+
+ QAccel *ac = new QAccel( channelsList );
+ ac->insertItem( Key_Delete, 100 );
+ ac->connectItem( 100, this, SLOT(deleteChannel()) );
+
+ resize( size );
+ delete icon;
+}
+
+
+
+void ScanDialog::selectAll()
+{
+ foundList->selectAll( true );
+}
+
+
+
+void ScanDialog::slotChannelChanged( QListViewItem *_channel, const QPoint &, int )
+{
+ if ( !_channel )
+ return;
+ QPixmap pix;
+ QString s = _channel->text(0);
+ if ( edit( s, pix ) ) {
+ _channel->setText( 0, s );
+ _channel->setPixmap( 0, pix );
+ }
+}
+
+
+
+void ScanDialog::setDvb( int index )
+{
+ int i, pos=0;
+ QStringList list;
+ bool ok=false;
+
+ for ( i=0; i<(int)dvb->count(); i++ ) {
+ list = dvb->at(i)->getSources( true );
+ pos+= list.count();
+ if ( index<pos ) {
+ if ( checkTimer.isActive() )
+ checkTimer.stop();
+ if ( progressTimer.isActive() )
+ progressTimer.stop();
+ disconnect( ds, SIGNAL(snrStatus(int)), snr, SLOT(setProgress(int)) );
+ disconnect( ds, SIGNAL(signalStatus(int)), signal, SLOT(setProgress(int)) );
+ disconnect( ds, SIGNAL(lockStatus(bool)), this, SLOT(setLock(bool)) );
+ disconnect( dvbsi, SIGNAL(end(bool)), this, SLOT(siEnded(bool)) );
+ ds->setScanning( false );
+ dvbsi->stop();
+ delete dvbsi;
+ ds = dvb->at(i);
+ ds->setScanning( true );
+ dvbsi = new DVBsi( &ok, ds->getAdapter(), ds->getTuner(), ds, defaultCharset );
+ connect( ds, SIGNAL(snrStatus(int)), snr, SLOT(setProgress(int)) );
+ connect( ds, SIGNAL(signalStatus(int)), signal, SLOT(setProgress(int)) );
+ connect( ds, SIGNAL(lockStatus(bool)), this, SLOT(setLock(bool)) );
+ connect( dvbsi, SIGNAL(end(bool)), this, SLOT(siEnded(bool)) );
+ break;
+ }
+ }
+ if ( searchComb->currentText().startsWith( "AUTO" ) )
+ offsetGroup->show();
+ else
+ offsetGroup->hide();
+}
+
+
+
+void ScanDialog::pop( QListViewItem *it, const QPoint &pos, int col )
+{
+ QPoint p=pos;
+
+ if ( !it )
+ return;
+
+ int i=col;
+ QPixmap pix;
+ QString s = it->text(0);
+
+ QPopupMenu *pop = new QPopupMenu();
+ pop->insertItem( i18n("Edit..."), 1 );
+ pop->insertItem( i18n("Delete"), 2 );
+ i = 0;
+ i = pop->exec( QCursor::pos() );
+ switch ( i ) {
+ case 0 :
+ break;
+ case 1 :
+ if ( edit( s, pix ) ) {
+ it->setText( 0, s );
+ it->setPixmap( 0, pix );
+ }
+ break;
+ case 2 :
+ deleteChannel( it->text(0) );
+ break;
+ }
+ delete pop;
+}
+
+
+
+void ScanDialog::deleteChannel()
+{
+ QListViewItem *it = channelsList->currentItem();
+ if ( it )
+ deleteChannel( it->text(0) );
+}
+
+
+
+void ScanDialog::deleteChannel( QString name )
+{
+ int j, i;
+ QListViewItem *it;
+
+ for ( j=0; j<(int)chandesc->count(); j++ ) {
+ if ( chandesc->at(j)->name==name ) {
+ for ( i=0; i<(int)chandesc->count(); i++ ) {
+ if ( chandesc->at(i)->num==chandesc->count() ) {
+ chandesc->at(i)->num = chandesc->at(j)->num;
+ break;
+ }
+ }
+ dvbsi->channels.append( new ChannelDesc( *chandesc->at(j) ) );
+ addFound( dvbsi->channels.getLast(), false );
+ chandesc->remove(j);
+ it = channelsList->firstChild();
+ while ( it!=0 ) {
+ if ( name==it->text(0) ) {
+ channelsList->removeItem( it );
+ break;
+ }
+ it = it->nextSibling();
+ }
+ break;
+ }
+ }
+}
+
+
+
+void ScanDialog::newChannel()
+{
+ ChannelDesc chan;
+ QStringList list;
+ //int i;
+
+ //for ( i=0; i<(int)searchComb->count(); i++ ) list.append( searchComb->text(i) );
+ if ( ds->getType()==FE_QPSK )
+ list.append( searchComb->currentText() );
+ else
+ list = ds->getSources();
+
+ chandesc->append( new ChannelDesc( chan ) );
+ chan.tp.type = ds->getType();
+ chan.num = chandesc->count();
+
+ ChannelEditor dlg( list, false, &chan, chandesc, this );
+
+ int ret = dlg.exec();
+ chandesc->remove();
+ if ( ret==ChannelEditor::Accepted ) {
+ chandesc->append( new ChannelDesc( chan ) );
+ QListViewItem *it = new QListViewItem( channelsList, chan.name );
+ if ( chan.type==1 ) {
+ if ( chan.fta )
+ it->setPixmap( 0, tvcPix );
+ else
+ it->setPixmap( 0, tvPix );
+ }
+ else {
+ if ( chan.fta )
+ it->setPixmap( 0, racPix );
+ else
+ it->setPixmap( 0, raPix );
+ }
+ }
+}
+
+
+
+void ScanDialog::deleteAll()
+{
+ int i, ret;
+
+ ret = KMessageBox::questionYesNo( this, i18n("Do you really want to delete all channels?") );
+ if ( ret!=KMessageBox::Yes )
+ return;
+ for ( i=0; i<(int)chandesc->count(); i++ ) {
+ dvbsi->channels.append( new ChannelDesc( *chandesc->at(i) ) );
+ addFound( dvbsi->channels.getLast(), false );
+ }
+ channelsList->clear();
+ chandesc->clear();
+}
+
+
+
+bool ScanDialog::edit( QString &name, QPixmap &pix )
+{
+ int j;
+ ChannelDesc *chan=0;
+ QStringList list, tmp;
+ int i;
+
+ for ( i=0; i<(int)dvb->count(); i++ ) {
+ tmp = dvb->at(i)->getSources();
+ for ( j=0; j<(int)tmp.count(); j++ )
+ list.append( tmp[j] );
+ }
+
+ for ( j=0; j<(int)chandesc->count(); j++ ) {
+ chan = chandesc->at(j);
+ if ( chan->name==name ) {
+ j = -1;
+ break;
+ }
+ }
+ if ( j==-1 ) {
+ ChannelEditor dlg( list, false, chan, chandesc, this );
+ int ret = dlg.exec();
+ if ( ret==ChannelEditor::Accepted ) {
+ name = chan->name;
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ pix = tvcPix;
+ else
+ pix = tvPix;
+ }
+ else {
+ if ( chan->fta )
+ pix = racPix;
+ else
+ pix = raPix;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+void ScanDialog::parseTp( QString s, fe_type_t type, QString src )
+{
+ Transponder *trans;
+ QString t;
+ int pos;
+
+ s = s.stripWhiteSpace();
+ trans = new Transponder();
+ pos = s.find(" ");
+ if ( s.left(pos)=="T" ) {
+ trans->type=FE_OFDM;
+ trans->source = "Terrestrial";
+ }
+ else if ( s.left(pos)=="C" ) {
+ trans->type=FE_QAM;
+ trans->source = "Cable";
+ }
+ else {
+ trans->type=FE_QPSK;
+ trans->source = src;
+ }
+ if ( trans->type!=type ) {
+ delete trans;
+ return;
+ }
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ trans->freq = s.left(pos).toULong()/1000;
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ if ( trans->type==FE_QPSK ) {
+ trans->pol = s.left(pos).lower()[0].latin1();
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ }
+ if ( trans->type!=FE_OFDM ) {
+ trans->sr = s.left(pos).toULong()/1000;
+ }
+ else {
+ if ( s.left(pos)=="8MHz" )
+ trans->bandwidth = BANDWIDTH_8_MHZ;
+ else if ( s.left(pos)=="7MHz" )
+ trans->bandwidth = BANDWIDTH_7_MHZ;
+ else if ( s.left(pos)=="6MHz" )
+ trans->bandwidth = BANDWIDTH_6_MHZ;
+ else
+ trans->bandwidth = BANDWIDTH_AUTO;
+ }
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ if ( s.left(pos)=="1/2" )
+ trans->coderateH = FEC_1_2;
+ else if ( s.left(pos)=="2/3" )
+ trans->coderateH = FEC_2_3;
+ else if ( s.left(pos)=="3/4" )
+ trans->coderateH = FEC_3_4;
+ else if ( s.left(pos)=="4/5" )
+ trans->coderateH = FEC_4_5;
+ else if ( s.left(pos)=="5/6" )
+ trans->coderateH = FEC_5_6;
+ else if ( s.left(pos)=="6/7" )
+ trans->coderateH = FEC_6_7;
+ else if ( s.left(pos)=="7/8" )
+ trans->coderateH = FEC_7_8;
+ else if ( s.left(pos)=="8/9" )
+ trans->coderateH = FEC_8_9;
+ else if ( s.left(pos)=="NONE" )
+ trans->coderateH = FEC_NONE;
+ else
+ trans->coderateH = FEC_AUTO;
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ if ( trans->type==FE_OFDM ) {
+ if ( s.left(pos)=="1/2" )
+ trans->coderateL = FEC_1_2;
+ else if ( s.left(pos)=="2/3" )
+ trans->coderateL = FEC_2_3;
+ else if ( s.left(pos)=="3/4" )
+ trans->coderateL = FEC_3_4;
+ else if ( s.left(pos)=="4/5" )
+ trans->coderateL = FEC_4_5;
+ else if ( s.left(pos)=="5/6" )
+ trans->coderateL = FEC_5_6;
+ else if ( s.left(pos)=="6/7" )
+ trans->coderateL = FEC_6_7;
+ else if ( s.left(pos)=="7/8" )
+ trans->coderateL = FEC_7_8;
+ else if ( s.left(pos)=="8/9" )
+ trans->coderateL = FEC_8_9;
+ else if ( s.left(pos)=="NONE" )
+ trans->coderateL = FEC_NONE;
+ else
+ trans->coderateL = FEC_AUTO;
+
+ if ( trans->coderateH==FEC_NONE )
+ trans->coderateH = FEC_AUTO;
+ if ( trans->coderateL==FEC_NONE )
+ trans->coderateL = FEC_AUTO;
+
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ }
+ if ( trans->type!=FE_QPSK ) {
+ if ( s.left(pos)=="QPSK" )
+ trans->modulation = QPSK;
+ else if ( s.left(pos)=="QAM16" )
+ trans->modulation = QAM_16;
+ else if ( s.left(pos)=="QAM32" )
+ trans->modulation = QAM_32;
+ else if ( s.left(pos)=="QAM64" )
+ trans->modulation = QAM_64;
+ else if ( s.left(pos)=="QAM128" )
+ trans->modulation = QAM_128;
+ else if ( s.left(pos)=="QAM256" )
+ trans->modulation = QAM_256;
+ else
+ trans->modulation = QAM_AUTO;
+ }
+ if ( trans->type==FE_OFDM ) {
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ if ( s.left(pos)=="8k" )
+ trans->transmission = TRANSMISSION_MODE_8K;
+ else if ( s.left(pos)=="2k" )
+ trans->transmission = TRANSMISSION_MODE_2K;
+ else
+ trans->transmission = TRANSMISSION_MODE_AUTO;
+
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ if ( s.left(pos)=="1/32" )
+ trans->guard = GUARD_INTERVAL_1_32;
+ else if ( s.left(pos)=="1/16" )
+ trans->guard = GUARD_INTERVAL_1_16;
+ else if ( s.left(pos)=="1/8" )
+ trans->guard = GUARD_INTERVAL_1_8;
+ else if ( s.left(pos)=="1/4" )
+ trans->guard = GUARD_INTERVAL_1_4;
+ else
+ trans->guard = GUARD_INTERVAL_AUTO;
+
+ s = s.right( s.length()-pos-1 );
+ s = s.stripWhiteSpace();
+ pos = s.find(" ");
+ if ( s.left(pos)=="1" )
+ trans->hierarchy = HIERARCHY_1;
+ else if ( s.left(pos)=="2" )
+ trans->hierarchy = HIERARCHY_2;
+ else if ( s.left(pos)=="4" )
+ trans->hierarchy = HIERARCHY_4;
+ else if ( s.left(pos)=="NONE" )
+ trans->hierarchy = HIERARCHY_NONE;
+ else
+ trans->hierarchy = HIERARCHY_AUTO;
+ }
+ transponders.append( trans );
+}
+
+
+
+bool ScanDialog::getTransData()
+{
+ QString s=sourcesPath;
+
+ transponders.clear();
+
+ if ( searchComb->currentText().startsWith("AUTO") ) {
+ int i;
+ for ( i=402; i<900; i+=8 ) {
+ if ( offset167m->isChecked() ) {
+ s = QString("T %1 8MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( (i*1000000)-167000 );
+ parseTp( s, ds->getType(), "" );
+ }
+ if ( offset0->isChecked() ) {
+ s = QString("T %1 8MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( i*1000000 );
+ parseTp( s, ds->getType(), "" );
+ }
+ if ( offset167p->isChecked() ) {
+ s = QString("T %1 8MHz AUTO AUTO AUTO AUTO AUTO AUTO").arg( (i*1000000)+167000 );
+ parseTp( s, ds->getType(), "" );
+ }
+ }
+ return true;
+ }
+
+ switch ( ds->getType() ) {
+ case FE_QPSK : s += "dvb-s/"; break;
+ case FE_QAM : s += "dvb-c/"; break;
+ case FE_OFDM : s += "dvb-t/"; break;
+ case FE_ATSC : return false;
+ }
+ s += searchComb->currentText();
+ QFile f( s );
+ if ( f.open(IO_ReadOnly) ) {
+ QTextStream tt( &f );
+ while ( !tt.eof() ) {
+ s = tt.readLine();
+ if ( s.startsWith("#") )
+ continue;
+ if ( s.length()==0 )
+ continue;
+ parseTp( s, ds->getType(), searchComb->currentText() );
+ }
+ f.close();
+ return true;
+ }
+ else
+ return false;
+}
+
+
+
+void ScanDialog::checkDuplicateName( ChannelDesc *chan )
+{
+ QString org, name;
+ int i, j=1;
+ bool loop;
+
+ org = name = chan->name;
+
+ do {
+ loop = false;
+ for ( i=0; i<(int)chandesc->count(); i++ ) {
+ if ( name==chandesc->at(i)->name ) {
+ name = org+"-"+QString().setNum(j);
+ loop = true;
+ ++j;
+ break;
+ }
+ }
+ } while ( loop );
+ chan->name = name;
+}
+
+bool ScanDialog::checkChannUpdate( ChannelDesc *chan )
+{
+ int i, j;
+ AudioPid a;
+ SubPid s;
+ ChannelDesc *desc;
+
+ for ( i=0; i<(int)chandesc->count(); i++ ) {
+ desc = chandesc->at(i);
+ if ( chan->tp.source==desc->tp.source && chan->tp.freq==desc->tp.freq && chan->sid==desc->sid ) {
+ chan->category=desc->category;
+ chan->num=desc->num;
+ chan->name=desc->name;
+ chan->fta=desc->fta;
+ for ( j=0; j<chan->napid; j++ ) {
+ if ( desc->apid[0].pid==chan->apid[j].pid ) {
+ if ( j>0 ) {
+ a = chan->apid[0];
+ chan->apid[0]=chan->apid[j];
+ chan->apid[j]=a;
+ }
+ break;
+ }
+ }
+ for ( j=0; j<chan->nsubpid; j++ ) {
+ if ( desc->subpid[0].pid==chan->subpid[j].pid ) {
+ if ( j>0 ) {
+ s = chan->subpid[0];
+ chan->subpid[0]=chan->subpid[j];
+ chan->subpid[j]=s;
+ }
+ break;
+ }
+ }
+ chandesc->replace(i,new ChannelDesc(*chan));
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void ScanDialog::addSelected()
+{
+ ChannelDesc *chan;
+ DListViewItem *dit, *odit;
+ QListViewItem *it;
+
+ dit = (DListViewItem*)foundList->firstChild();
+ while( dit ) {
+ chan = 0;
+ if ( !dit->isSelected( ) ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ chan = dit->chan;
+ if ( !chan ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if(checkChannUpdate(chan)){
+ checkDuplicateName( chan );
+
+ chan->num = chandesc->count()+1;
+ chandesc->append( new ChannelDesc( *chan ) );
+ it = new QListViewItem( channelsList, chan->name );
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ it->setPixmap( 0, tvcPix );
+ else
+ it->setPixmap( 0, tvPix );
+ }
+ else {
+ if ( chan->fta )
+ it->setPixmap( 0, racPix );
+ else
+ it->setPixmap( 0, raPix );
+ }
+ }
+ odit = dit;
+ dit = (DListViewItem*)dit->nextSibling();
+ delete odit;
+ dvbsi->channels.remove( chan );
+ }
+}
+
+
+
+void ScanDialog::working( bool b )
+{
+ offsetGroup->setEnabled( !b );
+ addfilteredBtn->setEnabled( !b );
+ addselectedBtn->setEnabled( !b );
+ //if ( !isTuned ) searchGroup->setEnabled( !b );
+ newBtn->setEnabled( !b );
+ delBtn->setEnabled( !b );
+}
+
+
+
+void ScanDialog::addFiltered()
+{
+ ChannelDesc *chan;
+ QListViewItem *it;
+ DListViewItem *dit, *odit;
+ int m = dvbsi->channels.count();
+ int t=0;
+
+ working( true );
+ startBtn->setEnabled( false );
+ progress->setProgress(0);
+ qApp->processEvents();
+
+ dit = (DListViewItem*)foundList->firstChild();
+ while( dit ) {
+ t++;
+ progress->setProgress( t*100/m );
+ chan = dit->chan;
+ if ( !chan->completed ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( chan->name.isEmpty() ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( chan->type<1 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( chan->type>2 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( chan->type==1 && chan->vpid==0 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( chan->type==1 && chan->napid==0 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( chan->type==2 && chan->napid==0 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( chan->type==2 && chan->vpid!=0 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( ftaCb->isChecked() && chan->fta ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( !tvCb->isChecked() && chan->type==1 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( !radioCb->isChecked() && chan->type==2 ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if ( providerCb->isChecked() && chan->provider!=providerComb->currentText() ) {
+ dit = (DListViewItem*)dit->nextSibling();
+ continue;
+ }
+ if(checkChannUpdate(chan)){
+ checkDuplicateName( chan );
+
+ chan->num = chandesc->count()+1;
+ chandesc->append( new ChannelDesc( *chan ) );
+ it = new QListViewItem( channelsList, chan->name );
+ if ( chan->type==1 ) {
+ if ( chan->fta )
+ it->setPixmap( 0, tvcPix );
+ else
+ it->setPixmap( 0, tvPix );
+ }
+ else {
+ if ( chan->fta )
+ it->setPixmap( 0, racPix );
+ else
+ it->setPixmap( 0, raPix );
+ }
+ }
+ odit = dit;
+ dit = (DListViewItem*)dit->nextSibling();
+ delete odit;
+ dvbsi->channels.remove( chan );
+ }
+
+ progress->setProgress(0);
+ startBtn->setEnabled( true );
+ working( false );
+}
+
+
+
+void ScanDialog::siEnded( bool b )
+{
+ checkTimer.stop();
+ progressTimer.stop();
+ checkNewChannel();
+ snr->setProgress( 0 );
+ signal->setProgress( 0 );
+ setLock( false );
+ progress->setProgress( 0 );
+ startBtn->setOn( !b );
+ working( false );
+ startBtn->setText( i18n("START scan") );
+ startBtn->setPaletteForegroundColor( QColor(255,0,0) );
+}
+
+
+
+void ScanDialog::scan( bool b )
+{
+ if ( b ) {
+ if ( checkTimer.isActive() )
+ checkTimer.stop();
+ foundList->clear();
+ nChannels = 0;
+ ntv = nradio = 0;
+ if ( ds->isTuned() )
+ dvbsi->go( transponders, 2 );
+ else {
+ if ( !getTransData() )
+ return;
+ if ( searchComb->currentText().startsWith("AUTO") )
+ dvbsi->go( transponders, 0 ); // no NIT
+ else
+ dvbsi->go( transponders );
+ }
+ checkTimer.start( 100 );
+ progressTimer.start( 1000 );
+ working( true );
+ startBtn->setText( i18n("STOP scan") );
+ startBtn->setPaletteForegroundColor( QColor(0,255,0) );
+ searchComb->setEnabled( false );
+ }
+ else {
+ //setCursor(QCursor(Qt::WaitCursor));
+ startBtn->setText( i18n("Stopping...") );
+ startBtn->setEnabled( false );
+ qApp->processEvents();
+ dvbsi->stop();
+ checkTimer.stop();
+ progressTimer.stop();
+ checkNewChannel();
+ snr->setProgress( 0 );
+ signal->setProgress( 0 );
+ setLock( false );
+ progress->setProgress( 0 );
+ working( false );
+ //setCursor(QCursor(Qt::ArrowCursor));
+ startBtn->setText( i18n("START scan") );
+ startBtn->setEnabled( true );
+ startBtn->setPaletteForegroundColor( QColor(255,0,0) );
+ searchComb->setEnabled( true );
+ }
+}
+
+
+
+void ScanDialog::setProgress()
+{
+ if ( !dvbsi->transponders.count() )
+ return;
+ progress->setProgress( dvbsi->progressTransponder*100/dvbsi->transponders.count() );
+}
+
+
+
+void ScanDialog::setLock( bool on )
+{
+ if ( on )
+ lock->on();
+ else
+ lock->off();
+}
+
+
+
+void ScanDialog::checkNewChannel()
+{
+ ChannelDesc *chan;
+ int j;
+
+ for ( j=nChannels; j<(int)dvbsi->channels.count(); j++ ) {
+ chan = dvbsi->channels.at(j);
+ if ( chan->completed==0 )
+ break;
+ nChannels++;
+ if ( chan->name.isEmpty() )
+ continue;
+ if ( chan->type<1 )
+ continue;
+ if ( chan->type>2 )
+ continue;
+ if ( chan->type==1 && chan->vpid==0 )
+ continue;
+ if ( chan->type==1 && chan->napid==0 )
+ continue;
+ if ( chan->type==2 && chan->napid==0 )
+ continue;
+ if ( chan->type==2 && chan->vpid!=0 )
+ continue;
+ addFound( chan, true );
+ }
+}
+
+
+
+void ScanDialog::addFound( ChannelDesc *chan, bool scan )
+{
+ int i;
+ DListViewItem *it;
+
+ it = new DListViewItem( foundList, chan, QString( "%1").arg( chan->tp.snr ), chan->name );
+
+ if ( chan->type==1 ) {
+ if ( scan )
+ ntv++;
+ if ( chan->fta )
+ it->setPixmap( 1, tvcPix );
+ else
+ it->setPixmap( 1, tvPix );
+ }
+ else {
+ if ( scan )
+ nradio++;
+ if ( chan->fta )
+ it->setPixmap( 1, racPix );
+ else
+ it->setPixmap( 1, raPix );
+ }
+
+ if ( scan )
+ progressLab->setText( QString( i18n("Found: %1 TV - %2 radio") ).arg(ntv).arg(nradio) );
+ if ( chan->provider.isEmpty() )
+ return;
+ for ( i=0; i<providerComb->count(); i++ ) {
+ if ( chan->provider==providerComb->text(i) ) {
+ i = -1;
+ break;
+ }
+ }
+ if ( i>-1 )
+ providerComb->insertItem( chan->provider );
+}
+
+
+
+ScanDialog::~ScanDialog()
+{
+ if ( checkTimer.isActive() )
+ checkTimer.stop();
+ if ( progressTimer.isActive() )
+ progressTimer.stop();
+ dvbsi->stop();
+ delete dvbsi;
+
+ ds->setScanning( false );
+ transponders.clear();
+}
+
+#include "scandialog.moc"
diff --git a/kaffeine/src/input/dvb/scandialog.h b/kaffeine/src/input/dvb/scandialog.h
new file mode 100644
index 0000000..b73e6d2
--- /dev/null
+++ b/kaffeine/src/input/dvb/scandialog.h
@@ -0,0 +1,106 @@
+/*
+ * scandialog.h
+ *
+ * Copyright (C) 2004-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef SCANDIALOG_H
+#define SCANDIALOG_H
+
+#include <qtimer.h>
+#include <qprogressbar.h>
+#include <qlabel.h>
+
+#include <kled.h>
+
+#include "kgradprogress.h"
+#include "scandialogui.h"
+#include "channeldesc.h"
+
+class DVBsi;
+class DvbStream;
+
+
+
+class DListViewItem : public QListViewItem
+{
+
+public:
+
+ DListViewItem( QListView *parent, ChannelDesc *desc, QString label1, QString label2 );
+
+ ChannelDesc *chan;
+};
+
+
+
+class ScanDialog : public ScanDialogUI
+{
+ Q_OBJECT
+
+public:
+
+ ScanDialog( QPtrList<DvbStream> *d, QPtrList<ChannelDesc> *ch, QSize size, QString src, const QString &charset );
+ ~ScanDialog();
+
+ QPtrList<Transponder> transponders;
+ QPtrList<ChannelDesc> *chandesc;
+
+private slots:
+
+ void scan( bool b );
+ void checkNewChannel();
+ void setLock( bool on );
+ void siEnded( bool b );
+ void addFiltered();
+ void addSelected();
+ void setProgress();
+ void pop( QListViewItem *it, const QPoint &pos, int col );
+ void deleteAll();
+ void selectAll();
+ void newChannel();
+ void deleteChannel( QString name );
+ void deleteChannel();
+ void setDvb(int);
+ void slotChannelChanged( QListViewItem*, const QPoint &, int );
+
+private:
+
+ bool getTransData();
+ bool edit( QString &name, QPixmap &pix );
+ void working( bool b );
+ void parseTp( QString s, fe_type_t type, QString src );
+ void addFound( ChannelDesc *chan, bool scan );
+ void checkDuplicateName( ChannelDesc *chan );
+ bool checkChannUpdate( ChannelDesc *chan );
+
+ QPtrList<DvbStream> *dvb;
+ DvbStream *ds;
+ KGradProgress *snr, *signal;
+ QProgressBar *progress;
+ KLed *lock;
+ DVBsi *dvbsi;
+ QTimer checkTimer, progressTimer;
+ int nChannels;
+ QPixmap tvPix, raPix, tvcPix, racPix;
+ int ntv, nradio;
+ QLabel *progressLab;
+ QString sourcesPath;
+ QString defaultCharset;
+};
+
+#endif /* SCANDIALOG_H */
diff --git a/kaffeine/src/input/dvb/scandialogui.ui b/kaffeine/src/input/dvb/scandialogui.ui
new file mode 100644
index 0000000..04cbdd1
--- /dev/null
+++ b/kaffeine/src/input/dvb/scandialogui.ui
@@ -0,0 +1,514 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ScanDialogUI</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ScanDialogUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>725</width>
+ <height>560</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Channels</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox10</cstring>
+ </property>
+ <property name="title">
+ <string>Channels</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>(Right click to edit/delete)</string>
+ </property>
+ </widget>
+ <widget class="QListView" row="1" column="0" rowspan="1" colspan="3">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>channelsList</cstring>
+ </property>
+ <property name="rootIsDecorated">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="2" column="0">
+ <property name="name">
+ <cstring>newBtn</cstring>
+ </property>
+ <property name="text">
+ <string>New...</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="2" column="2">
+ <property name="name">
+ <cstring>delBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Delete All</string>
+ </property>
+ </widget>
+ <spacer row="2" column="1">
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>searchGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Search On</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>searchComb</cstring>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>offsetGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Offset (KHz)</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>offset0</cstring>
+ </property>
+ <property name="text">
+ <string>0</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>offset167p</cstring>
+ </property>
+ <property name="text">
+ <string>+167</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>offset167m</cstring>
+ </property>
+ <property name="text">
+ <string>-167</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>startBtn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Start Scan</string>
+ </property>
+ <property name="toggleButton">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer15</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>statusFrame</cstring>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout38</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>filtersGroup</cstring>
+ </property>
+ <property name="title">
+ <string>Filters</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>ftaCb</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Free to air</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>radioCb</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Radio</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>tvCb</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TV</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0">
+ <property name="name">
+ <cstring>providerCb</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Provider:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>providerComb</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>addselectedBtn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;&lt; Add Selected</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>addfilteredBtn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&lt;&lt; Add Filtered</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox11</cstring>
+ </property>
+ <property name="title">
+ <string>Found</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>SNR</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>foundList</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>selectallBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Select All</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="Line">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Done</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>ScanDialogUI</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>okBtn</tabstop>
+ <tabstop>searchComb</tabstop>
+ <tabstop>startBtn</tabstop>
+ <tabstop>ftaCb</tabstop>
+ <tabstop>tvCb</tabstop>
+ <tabstop>radioCb</tabstop>
+ <tabstop>providerCb</tabstop>
+ <tabstop>providerComb</tabstop>
+ <tabstop>addselectedBtn</tabstop>
+ <tabstop>addfilteredBtn</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kaffeine/src/input/dvb/sender.cpp b/kaffeine/src/input/dvb/sender.cpp
new file mode 100644
index 0000000..27e5d9d
--- /dev/null
+++ b/kaffeine/src/input/dvb/sender.cpp
@@ -0,0 +1,114 @@
+/*
+ * sender.cpp
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include "sender.h"
+
+
+
+Sender::Sender()
+{
+ isRunning = false;
+ senderSocket = 0;
+ sendList = "\n";
+}
+
+
+
+bool Sender::makeSenderSocket( const QString &addr, int m_senderPort )
+{
+ int sockopt=1;
+
+ if ( senderSocket ) return true;
+
+ if ( ( senderSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ KMessageBox::error( 0, i18n("Can't open DVB info socket.") );
+ senderSocket = 0;
+ return false;
+ }
+
+ senderAddr.sin_family = AF_INET; // host byte order
+ senderAddr.sin_port = htons( m_senderPort ); // short, network byte order
+ senderAddr.sin_addr.s_addr = inet_addr( addr.ascii() );
+
+ memset( &( senderAddr.sin_zero ), '\0', 8 ); // zero the rest of the struct
+
+ if ( setsockopt( senderSocket, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt) ) < 0 ) {
+ KMessageBox::error( 0, i18n("Can't open DVB info socket.") );
+ close( senderSocket );
+ senderSocket = 0;
+ return false;
+ }
+ fprintf( stderr, "Sender socket opened\n" );
+ return true;
+}
+
+
+
+Sender::~Sender()
+{
+ stop();
+}
+
+
+
+void Sender::closeSender()
+{
+ if ( senderSocket ) {
+ sendto( senderSocket, "quit\n", 5, 0, (struct sockaddr *)&senderAddr, sizeof(senderAddr) );
+ close( senderSocket );
+ senderSocket = 0;
+ fprintf( stderr, "Sender socket closed\n" );
+ }
+}
+
+
+
+void Sender::run()
+{
+ int i;
+
+ while( isRunning ) {
+ sendto( senderSocket, sendList.latin1(), sendList.length(), 0, (struct sockaddr *)&senderAddr, sizeof(senderAddr) );
+ msleep(500);
+ }
+}
+
+
+
+void Sender::go()
+{
+ isRunning = true;
+ start();
+}
+
+
+
+void Sender::stop()
+{
+ isRunning = false;
+ if ( !wait(10000) ) {
+ terminate();
+ wait();
+ }
+ closeSender();
+}
diff --git a/kaffeine/src/input/dvb/sender.h b/kaffeine/src/input/dvb/sender.h
new file mode 100644
index 0000000..22e3a08
--- /dev/null
+++ b/kaffeine/src/input/dvb/sender.h
@@ -0,0 +1,59 @@
+/*
+ * sender.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef SENDER_H
+#define SENDER_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <qthread.h>
+#include <qstring.h>
+#include <qobject.h>
+
+
+
+class Sender : public QThread, public QObject
+{
+
+public:
+
+ Sender();
+ ~Sender();
+ void run();
+ void stop();
+ void go();
+
+ int senderSocket;
+ struct sockaddr_in senderAddr;
+
+protected:
+
+ bool makeSenderSocket( const QString &addr, int m_senderPort );
+ void closeSender();
+
+ bool isRunning;
+ QString sendList;
+
+};
+
+#endif /* SENDER_H */
diff --git a/kaffeine/src/input/dvb/subeditor.cpp b/kaffeine/src/input/dvb/subeditor.cpp
new file mode 100644
index 0000000..1863606
--- /dev/null
+++ b/kaffeine/src/input/dvb/subeditor.cpp
@@ -0,0 +1,182 @@
+/*
+ * subeditor.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qlistbox.h>
+#include <qspinbox.h>
+#include <qpushbutton.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include "subeditor.h"
+
+
+
+SubEditor::SubEditor( ChannelDesc *chan, QWidget *parent ) : SubEditorUI( parent )
+{
+ QString s, t;
+ int i;
+
+ channel = chan;
+ pidList->clear();
+
+ for ( i=0; i<channel->nsubpid; i++ ) insertItem( i );
+
+ if ( channel->nsubpid==channel->maxsubpid ) newBtn->setEnabled( false );
+
+ connect( pidList, SIGNAL(highlighted(int)), this, SLOT(showProp(int)) );
+ connect( upBtn, SIGNAL(clicked()), this, SLOT(itemUp()) );
+ connect( downBtn, SIGNAL(clicked()), this, SLOT(itemDown()) );
+ connect( delBtn, SIGNAL(clicked()), this, SLOT(itemDelete()) );
+ connect( updateBtn, SIGNAL(clicked()), this, SLOT(itemUpdate()) );
+ connect( newBtn, SIGNAL(clicked()), this, SLOT(itemNew()) );
+}
+
+
+
+void SubEditor::insertItem( int index, bool updt )
+{
+ QString s, t;
+
+ s = t.setNum( channel->subpid[index].pid );
+ s = s+"("+t.setNum( channel->subpid[index].page )+")";
+ s = s+"("+t.setNum( channel->subpid[index].id )+")";
+ if ( !channel->subpid[index].lang.isEmpty() ) s = s+"("+channel->subpid[index].lang+")";
+ if ( updt ) pidList->changeItem( s, index );
+ else pidList->insertItem( s, index );
+}
+
+
+
+void SubEditor::showProp( int index )
+{
+ if ( index<0 ) {
+ pidSpin->setValue( 0 );
+ pageSpin->setValue( 0 );
+ ancSpin->setValue( 0 );
+ langLe->setText( "" );
+ }
+ else {
+ pidSpin->setValue( channel->subpid[index].pid );
+ pageSpin->setValue( channel->subpid[index].page );
+ ancSpin->setValue( channel->subpid[index].id );
+ langLe->setText( channel->subpid[index].lang );
+ }
+}
+
+
+
+void SubEditor::itemUp()
+{
+ SubPid a;
+
+ int n = pidList->currentItem();
+
+ if ( n<1 ) return;
+
+ a = channel->subpid[n-1];
+ channel->subpid[n-1] = channel->subpid[n];
+ channel->subpid[n] = a;
+
+ insertItem( n, true );
+ insertItem( n-1, true );
+}
+
+
+
+void SubEditor::itemDown()
+{
+ SubPid a;
+
+ int n = pidList->currentItem();
+
+ if ( (n<0) || (n>(channel->nsubpid-2)) ) return;
+
+ a = channel->subpid[n+1];
+ channel->subpid[n+1] = channel->subpid[n];
+ channel->subpid[n] = a;
+
+ insertItem( n, true );
+ insertItem( n+1, true );
+}
+
+
+
+void SubEditor::itemDelete()
+{
+ int n = pidList->currentItem();
+
+ if ( channel->nsubpid==0 || (n<0) ) return; //for sure
+
+ for ( int i=n; i<channel->nsubpid-1; i++ ) channel->subpid[i] = channel->subpid[i+1];
+ channel->nsubpid--;
+ pidList->removeItem( n );
+
+ newBtn->setEnabled( true );
+}
+
+
+
+void SubEditor::itemUpdate()
+{
+ int n = pidList->currentItem();
+
+ if ( n<0 ) return;
+
+ channel->subpid[n].pid = pidSpin->value();
+ channel->subpid[n].page = pageSpin->value();
+ channel->subpid[n].id = ancSpin->value();
+ channel->subpid[n].lang = langLe->text().stripWhiteSpace();
+
+ insertItem( n, true );
+}
+
+
+
+void SubEditor::itemNew()
+{
+ if ( channel->nsubpid==channel->maxsubpid ) { //for sure
+ newBtn->setEnabled( false );
+ return;
+ }
+
+ if ( !pidSpin->value() ) {
+ KMessageBox::sorry( this, i18n("Pid must be non zero!") );
+ return;
+ }
+ channel->nsubpid++;
+ channel->subpid[channel->nsubpid-1].pid = pidSpin->value();
+ channel->subpid[channel->nsubpid-1].page = pageSpin->value();
+ channel->subpid[channel->nsubpid-1].id = ancSpin->value();
+ channel->subpid[channel->nsubpid-1].lang = langLe->text().stripWhiteSpace();
+ insertItem( channel->nsubpid-1 );
+ if ( channel->nsubpid==channel->maxsubpid ) newBtn->setEnabled( false );
+}
+
+
+
+SubEditor::~SubEditor()
+{
+
+}
+
+#include "subeditor.moc"
diff --git a/kaffeine/src/input/dvb/subeditor.h b/kaffeine/src/input/dvb/subeditor.h
new file mode 100644
index 0000000..0a2b332
--- /dev/null
+++ b/kaffeine/src/input/dvb/subeditor.h
@@ -0,0 +1,55 @@
+/*
+ * subeditor.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef SUBEDITOR_H
+#define SUBEDITOR_H
+
+#include "channeldesc.h"
+#include "subeditorui.h"
+
+
+
+class SubEditor : public SubEditorUI
+{
+ Q_OBJECT
+
+public:
+
+ SubEditor( ChannelDesc *chan, QWidget *parent );
+ ~SubEditor();
+
+private slots:
+
+ void showProp( int index );
+ void itemUp();
+ void itemDown();
+ void itemDelete();
+ void itemUpdate();
+ void itemNew();
+
+private:
+
+ void insertItem( int index, bool updt=false );
+
+ ChannelDesc *channel;
+
+};
+
+#endif /* SUBEDITOR_H */
diff --git a/kaffeine/src/input/dvb/subeditorui.ui b/kaffeine/src/input/dvb/subeditorui.ui
new file mode 100644
index 0000000..790b089
--- /dev/null
+++ b/kaffeine/src/input/dvb/subeditorui.ui
@@ -0,0 +1,354 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SubEditorUI</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>SubEditorUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>558</width>
+ <height>444</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Subtitle PIDs Editor</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="Line" row="1" column="0">
+ <property name="name">
+ <cstring>line3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0">
+ <property name="name">
+ <cstring>layout19</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>okBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox10</cstring>
+ </property>
+ <property name="title">
+ <string>Subtitle PIDs</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListBox" row="0" column="0">
+ <item>
+ <property name="text">
+ <string>New Item</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>pidList</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout12</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout15</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>upBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Move Up</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>downBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Move Down</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>delBtn</cstring>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer8</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>180</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout11</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout13</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>updateBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;&lt; Update Selected</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>newBtn</cstring>
+ </property>
+ <property name="text">
+ <string>&lt;&lt; New</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox9</cstring>
+ </property>
+ <property name="title">
+ <string>Properties</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout10</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Pid:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Page:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Sub page:</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Lang:</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>pidSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>8191</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>pageSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>ancSpin</cstring>
+ </property>
+ <property name="maxValue">
+ <number>99999</number>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>langLe</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>2</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>okBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SubEditorUI</receiver>
+ <slot>accept()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>okBtn</tabstop>
+ <tabstop>pidList</tabstop>
+ <tabstop>upBtn</tabstop>
+ <tabstop>downBtn</tabstop>
+ <tabstop>delBtn</tabstop>
+ <tabstop>updateBtn</tabstop>
+ <tabstop>newBtn</tabstop>
+ <tabstop>pidSpin</tabstop>
+ <tabstop>pageSpin</tabstop>
+ <tabstop>ancSpin</tabstop>
+ <tabstop>langLe</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kaffeine/src/input/dvb/ts2rtp.cpp b/kaffeine/src/input/dvb/ts2rtp.cpp
new file mode 100644
index 0000000..9f87a84
--- /dev/null
+++ b/kaffeine/src/input/dvb/ts2rtp.cpp
@@ -0,0 +1,478 @@
+/*
+ * ts2rtp.cpp
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * some code from dvbstream (GPL)
+ * Copyright (C) 2001,2002 Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <sys/time.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include "ts2rtp.h"
+#include "gdvb.h"
+#include "channeldesc.h"
+
+#define TS_SIZE 188
+
+
+
+Ts2Rtp::Ts2Rtp()
+{
+ unsigned int i, j=0, k;
+
+ for( i = 0 ; i < 256 ; i++ ) {
+ k = 0;
+ for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) {
+ k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
+ }
+ CRC32[i] = k;
+ }
+
+ thWrite = 0;
+ rtpSocket = 0;
+ writePsi = false;
+ psiPackets = 0;
+ // fill in the MPEG-2 TS deefaults
+ // Note: MPEG-2 TS defines a timestamping base frequency of 90000 Hz.
+ hRtp.b.v=2;
+ hRtp.b.p=0;
+ hRtp.b.x=0;
+ hRtp.b.cc=0;
+ hRtp.b.m=0;
+ hRtp.b.pt=33;
+ hRtp.b.sequence=rand() & 65535;
+ hRtp.timestamp=rand();
+ hRtp.ssrc=rand();
+
+ psiBufferSize = 20*TS_SIZE;
+ psiBuffer = (unsigned char*)malloc(psiBufferSize);
+
+ connect( &psiTimer, SIGNAL(timeout()), this, SLOT(setPSI()) );
+}
+
+
+
+Ts2Rtp::~Ts2Rtp()
+{
+ stop();
+ if ( rtpSocket ) {
+ close( rtpSocket );
+ }
+ free( psiBuffer );
+}
+
+
+
+void Ts2Rtp::setSocket( const QString &addr, int m_port, int m_senderPort )
+{
+ address = addr;
+ port = m_port;
+ senderPort = m_senderPort;
+}
+
+
+
+bool Ts2Rtp::addChannels( QPtrList<ChannelDesc> *channels )
+{
+ int i, j, k, pmtpid=8191;
+ ChannelDesc *desc, *d;
+ QValueList<int> pids;
+
+ if ( !rtpSocket && !makeSocket() )
+ return false;
+
+ sendList = "";
+ for ( i=0; i<(int)channels->count(); i++ ) {
+ desc = channels->at( i );
+ sendList = sendList+desc->name+"|"+QString().setNum(desc->vpid)+"|"+QString().setNum(desc->apid[0].pid)+"|";
+ if ( desc->apid[0].ac3 ) sendList+= "y|";
+ else sendList+= "n|";
+ sendList+= QString().setNum(desc->subpid[0].pid);
+ sendList+= "|";
+ sendList+= QString().setNum(desc->subpid[0].page);
+ sendList+= "|";
+ sendList+= QString().setNum(desc->subpid[0].id);
+ sendList+= "|";
+ sendList+= QString().setNum(desc->subpid[0].type);
+ sendList+= "|";
+ sendList+= desc->subpid[0].lang+"|";
+ for ( j=i; j<(int)channels->count(); j++ ) {
+ pids.clear();
+ d = channels->at( j );
+ if ( d->vpid )
+ pids.append( d->vpid );
+ for ( k=0; k<d->napid && k<MAX_AUDIO; k++ )
+ pids.append( d->apid[k].pid );
+ for ( k=0; k<d->nsubpid && k<MAX_DVBSUB; k++ )
+ pids.append( d->subpid[k].pid );
+ while ( pmtpid==17 || pids.contains( pmtpid ) )
+ --pmtpid;
+ }
+ desc->pmtpid = pmtpid--;
+ }
+ sendList+="\n";
+ psiTables( channels );
+ writePsi = true;
+ psiTimer.start( 500 );
+ return true;
+}
+
+
+
+void Ts2Rtp::removeChannels()
+{
+ if ( !rtpSocket )
+ return;
+ stop();
+ close( rtpSocket );
+ rtpSocket = 0;
+ fprintf( stderr, "rtp socket closed\n" );
+ thWrite = 0;
+ psiPackets = 0;
+ if ( psiTimer.isActive() )
+ psiTimer.stop();
+}
+
+
+
+bool Ts2Rtp::makeSocket()
+{
+ int iRet, iLoop = 1;
+
+ if ( !makeSenderSocket( address, senderPort ) ) return false;
+
+ rtpSocket = socket( AF_INET, SOCK_DGRAM, 0 );
+
+ if ( rtpSocket < 0) {
+ KMessageBox::error( 0, i18n("Can't open DVB broadcast socket.") );
+ rtpSocket = 0;
+ closeSender();
+ return false;
+ }
+
+ rtpAddr.sin_family = AF_INET;
+ rtpAddr.sin_port = htons( port );
+ rtpAddr.sin_addr.s_addr = inet_addr( address.ascii() );
+
+ iRet = setsockopt( rtpSocket, SOL_SOCKET, SO_BROADCAST, &iLoop, sizeof(iLoop));
+ if (iRet < 0) {
+ KMessageBox::error( 0, i18n("Can't init DVB broadcast socket.") );
+ close( rtpSocket );
+ rtpSocket = 0;
+ closeSender();
+ return false;
+ }
+ go();
+ fprintf( stderr, "rtp socket opened\n" );
+ return true;
+}
+
+
+
+void Ts2Rtp::process( unsigned char *buf, int size )
+{
+ int i, n;
+ unsigned char *buffer=buf;
+
+ if ( writePsi ) {
+ i = 0;
+ while ( i<psiPackets ) {
+ n = psiPackets-i;
+ if ( n>8 )
+ n = 8;
+ sendrtp( (char*)(psiBuffer+(TS_SIZE*i)), TS_SIZE*n );
+ i+= n;
+ }
+ writePsi = false;
+ }
+
+ for ( i=0; i<size; i+=TS_SIZE ) {
+ memcpy( thBuf+thWrite, buffer, TS_SIZE );
+ thWrite+=TS_SIZE;
+ if ( thWrite==(TS_SIZE*8 ) ) {
+ sendrtp( (char*)thBuf, TS_SIZE*8 );
+ thWrite = 0;
+ }
+ buffer+=TS_SIZE;
+ }
+}
+
+
+
+/* Send a single RTP packet, converting the RTP header to network byte order. */
+void Ts2Rtp::sendrtp( char *data, int len )
+{
+ struct timeval tv;
+
+ gettimeofday( &tv, (struct timezone*) NULL );
+ hRtp.timestamp = ((tv.tv_sec%1000000)*1000 + tv.tv_usec/1000)*90;
+
+ char *buf=(char*)alloca(len+72);
+ unsigned int intP;
+ char* charP = (char*) &intP;
+ int headerSize;
+ buf[0] = 0x00;
+ buf[0] |= ((((char) hRtp.b.v)<<6)&0xc0);
+ buf[0] |= ((((char) hRtp.b.p)<<5)&0x20);
+ buf[0] |= ((((char) hRtp.b.x)<<4)&0x10);
+ buf[0] |= ((((char) hRtp.b.cc)<<0)&0x0f);
+ buf[1] = 0x00;
+ buf[1] |= ((((char) hRtp.b.m)<<7)&0x80);
+ buf[1] |= ((((char) hRtp.b.pt)<<0)&0x7f);
+ intP = htonl(hRtp.b.sequence);
+ memcpy(&buf[2],charP+2,2);
+ intP = htonl(hRtp.timestamp);
+ memcpy(&buf[4],&intP,4);
+ /* SSRC: not implemented */
+ buf[8] = 0x0f;
+ buf[9] = 0x0f;
+ buf[10] = 0x0f;
+ buf[11] = 0x0f;
+ headerSize = 12 + 4*hRtp.b.cc; /* in bytes */
+ memcpy(buf+headerSize,data,len);
+
+ hRtp.b.sequence++;
+ if ( rtpSocket ) sendto( rtpSocket, buf, len+headerSize, 0, (struct sockaddr *)&rtpAddr, sizeof(rtpAddr) );
+}
+
+
+
+void Ts2Rtp::setPSI()
+{
+ writePsi = true;
+}
+
+
+void Ts2Rtp::psiTables( QPtrList<ChannelDesc> *channels )
+{
+ unsigned char buf[15000];
+ int off, i, j, sectionOff, loopOff, descOff, max;
+ int npack=0;
+ unsigned short tsid = channels->at(0)->tp.tsid;
+ ChannelDesc *desc;
+
+ psiPackets = 0;
+
+ // SDT
+ off = 0;
+ // CRC calculation begins here
+ buf[off++] = 0x42; // service description section
+ buf[off++] = 0x80;
+ sectionOff = off;
+ buf[off++] = 0x00; // section_length (12bits)
+ buf[off++] = tsid>>8; buf[off++] = tsid&0xff;
+ buf[off++] = 0x01; // current_next_indicator
+ buf[off++] = 0x00; // section_number
+ buf[off++] = 0x00; // last_section_number
+ buf[off++] = 0x00; buf[off++] = 0x00; // network_id
+ buf[off++] = 0x00; // reserved
+
+ for ( i=0; i<(int)channels->count(); i++ ) {
+ desc = channels->at( i );
+ buf[off++] = desc->sid>>8; buf[off++] = desc->sid&0xff; // service_id
+ buf[off++] = 0x00; // reserved
+ buf[off++] = 0x80; // running_status(3bits) + free_ca(1bit) + descriptors_loop_length
+ loopOff = off;
+ buf[off++] = 0x00; // descriptors_loop_length
+
+ buf[off++] = 0x48; // descriptor_tag
+ descOff = off;
+ buf[off++] = 0x00; //descriptor_length
+ buf[off++] = desc->type; //service_type
+ buf[off++] = 0x03; // provider_name_length
+ buf[off++] = 0x4c; buf[off++] = 0x41; buf[off++] = 0x4e; // provider_name
+ buf[off++] = desc->name.length(); // service_name_length
+ memcpy( buf+off, desc->name.latin1(), desc->name.length() );
+ off+= desc->name.length();
+ buf[descOff] = off-descOff-1;
+ buf[loopOff] = off-loopOff-1;
+ }
+ buf[sectionOff-1] |= (off+1)>>8;
+ buf[sectionOff] = (off+1)&0xff;
+ calculateCRC( buf, buf+off );
+ fillPackets( 17, buf, off+4, npack );
+
+ // PAT
+ off = 0;
+ // CRC calculation begins here
+ buf[off++] = 0x00; // program association section
+ buf[off++] = 0x80;
+ sectionOff = off;
+ buf[off++] = 0x00; // section_length (12bits)
+ buf[off++] = tsid>>8; buf[off++] = tsid&0xff;
+ buf[off++] = 0x01; // current_next_indicator
+ buf[off++] = 0x00; // section_number
+ buf[off++] = 0x00; // last_section_number
+
+ for ( i=0; i<(int)channels->count(); i++ ) {
+ desc = channels->at( i );
+ buf[off++] = desc->sid>>8; buf[off++] = desc->sid&0xff; // service_id
+ buf[off++] = desc->pmtpid>>8; buf[off++] = desc->pmtpid&0xff; // program_map_PID(13bits)
+ }
+ buf[sectionOff-1] |= (off+1)>>8;
+ buf[sectionOff] = (off+1)&0xff;
+ calculateCRC( buf, buf+off );
+ fillPackets( 0, buf, off+4, npack );
+
+ // PMT
+ for ( i=0; i<(int)channels->count(); i++ ) {
+ desc = channels->at( i );
+ off = 0;
+ // CRC calculation begins here
+ buf[off++] = 0x02; // program map section
+ buf[off++] = 0x80;
+ sectionOff = off;
+ buf[off++] = 0x00; // section_length (12bits)
+ buf[off++] = desc->sid>>8; buf[off++] = desc->sid&0xff;
+ buf[off++] = 0x01; // current_next_indicator
+ buf[off++] = 0x00; // section_number
+ buf[off++] = 0x00; // last_section_number
+ buf[off++] = desc->vpid>>8; buf[off++] = desc->vpid&0xff; // PCR pid
+ buf[off++] = 0x00; buf[off++] = 0x00; // infos_length
+ if ( desc->vpid ) {
+ buf[off++] = desc->vType; // stream_type
+ buf[off++] = desc->vpid>>8; buf[off++] = desc->vpid&0xff; // pid
+ buf[off++] = 0x00; buf[off++] = 0x00; // infos_length
+ }
+
+ for ( j=0; j<desc->napid && j<MAX_AUDIO; j++ ) {
+ if ( desc->apid[j].ac3 ) {
+ buf[off++] = 0x06; // stream type
+ buf[off++] = desc->apid[j].pid>>8; buf[off++] = desc->apid[j].pid&0xff;
+ buf[off++] = 0x00; buf[off++] = 0x09; // es info length
+ buf[off++] = 0x6a; // descriptor tag
+ buf[off++] = 0x01; // descriptor length
+ buf[off++] = 0x00;
+ }
+ else {
+ buf[off++] = 0x04; // stream type = audio
+ buf[off++] = desc->apid[j].pid>>8; buf[off++] = desc->apid[j].pid&0xff;
+ buf[off++] = 0x00; buf[off++] = 0x06; // es info length
+ }
+ buf[off++] = 0x0a; // iso639 descriptor tag
+ buf[off++] = 0x04; // descriptor length
+ if ( !desc->apid[j].lang.isEmpty() ) {
+ buf[off++] = desc->apid[j].lang.constref(0);
+ buf[off++] = desc->apid[j].lang.constref(1);
+ if ( desc->apid[j].ac3 )
+ buf[off++] = '_';
+ else
+ buf[off++] = desc->apid[j].lang.constref(2);
+ }
+ else if ( desc->apid[j].ac3 ) {
+ buf[off++] = 'd';
+ buf[off++] = 'd';
+ buf[off++] = 49+j;
+ }
+ else {
+ buf[off++] = 'c';
+ buf[off++] = 'h';
+ buf[off++] = 49+j;
+ }
+ buf[off++] = 0x00; // audio type
+ }
+
+ for ( j=0; j<desc->nsubpid && j<MAX_DVBSUB; j++ ) {
+ buf[off++] = 0x06; // stream type = ISO_13818_PES_PRIVATE
+ buf[off++] = desc->subpid[j].pid>>8; buf[off++] = desc->subpid[j].pid&0xff;
+ buf[off++] = 0x00; buf[off++] = 0x0a; // es info length
+ buf[off++] = 0x59; //DVB sub tag
+ buf[off++] = 0x08; // descriptor length
+ if ( !desc->subpid[j].lang.isEmpty() ) {
+ buf[off++] = desc->subpid[j].lang.constref(0);
+ buf[off++] = desc->subpid[j].lang.constref(1);
+ buf[off++] = desc->subpid[j].lang.constref(2);
+ }
+ else {
+ buf[off++] = 'c';
+ buf[off++] = 'h';
+ buf[off++] = 49+j;
+ }
+ buf[off++] = desc->subpid[j].type; //sub type
+ buf[off++] = desc->subpid[j].page>>8; buf[off++] = desc->subpid[j].page&0xff; // comp_page_id
+ buf[off++] = desc->subpid[j].id>>8; buf[off++] = desc->subpid[j].id&0xff; // anc_page_id
+ }
+
+ buf[sectionOff-1] |= (off+1)>>8;
+ buf[sectionOff] = (off+1)&0xff;
+ calculateCRC( buf, buf+off );
+ fillPackets( desc->pmtpid, buf, off+4, npack );
+ }
+
+ psiPackets = npack;
+}
+
+
+
+void Ts2Rtp::fillPackets( unsigned short pid, unsigned char *buf, int len, int &npack )
+{
+ int i, off=npack*TS_SIZE, offbuf=0, inc;
+ bool pus=true;
+ int continuity=0;
+
+ while ( (off-(npack*TS_SIZE))<len ) {
+ if ( (off+TS_SIZE)>(psiBufferSize-(10*TS_SIZE)) ) {
+ psiBufferSize+= 10*TS_SIZE;
+ psiBuffer = (unsigned char*)realloc( psiBuffer, psiBufferSize );
+ fprintf(stderr,"psiBufferSize = %d\n",psiBufferSize);
+ }
+ psiBuffer[off++] = 0x47; // sync_byte
+ if ( pus )
+ psiBuffer[off++] = 0x40|(pid>>8);
+ else
+ psiBuffer[off++] = pid>>8;
+ psiBuffer[off++] = pid&0xff; // PID
+ psiBuffer[off++] = 0x10|continuity;
+ if ( pus ) {
+ psiBuffer[off++] = 0x00; // pointer_field
+ pus = false;
+ }
+ inc = TS_SIZE-(off%TS_SIZE);
+ if ( (len-offbuf)<inc )
+ inc = len-offbuf;
+ memcpy( psiBuffer+off, buf+offbuf, inc );
+ off+= inc;
+ offbuf+= inc;
+ ++continuity;
+ }
+ // needed stuffing bytes
+ for ( i=0 ; i<(off%TS_SIZE) ; i++)
+ psiBuffer[off++] = 0xff;
+ npack+= (off-(npack*TS_SIZE))/TS_SIZE;
+}
+
+
+
+void Ts2Rtp::calculateCRC( unsigned char *p_begin, unsigned char *p_end )
+{
+ unsigned int i_crc = 0xffffffff;
+
+ // Calculate the CRC
+ while( p_begin < p_end ) {
+ i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((unsigned int)*p_begin) ];
+ p_begin++;
+ }
+ // Store it after the data
+ p_end[0] = (i_crc >> 24) & 0xff;
+ p_end[1] = (i_crc >> 16) & 0xff;
+ p_end[2] = (i_crc >> 8) & 0xff;
+ p_end[3] = (i_crc >> 0) & 0xff;
+}
diff --git a/kaffeine/src/input/dvb/ts2rtp.h b/kaffeine/src/input/dvb/ts2rtp.h
new file mode 100644
index 0000000..36165e9
--- /dev/null
+++ b/kaffeine/src/input/dvb/ts2rtp.h
@@ -0,0 +1,99 @@
+/*
+ * ts2rtp.h
+ *
+ * Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef TS2RTP_H
+#define TS2RTP_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <qptrlist.h>
+#include <qtimer.h>
+
+#include "sender.h"
+
+class ChannelDesc;
+
+
+
+struct rtpbits {
+ unsigned int v:2; /* version: 2 */
+ unsigned int p:1; /* is there padding appended: 0 */
+ unsigned int x:1; /* number of extension headers: 0 */
+ unsigned int cc:4; /* number of CSRC identifiers: 0 */
+ unsigned int m:1; /* marker: 0 */
+ unsigned int pt:7; /* payload type: 33 for MPEG2 TS - RFC 1890 */
+ unsigned int sequence:16; /* sequence number: random */
+};
+
+struct rtpheader { /* in network byte order */
+ struct rtpbits b;
+ int timestamp; /* start: random */
+ int ssrc; /* random */
+};
+
+
+
+class Ts2Rtp : public Sender
+{
+ Q_OBJECT
+public:
+
+ Ts2Rtp();
+ ~Ts2Rtp();
+ void setSocket( const QString &addr, int m_port, int m_senderPort );
+ bool addChannels( QPtrList<ChannelDesc> *channels );
+ void removeChannels();
+ void process( unsigned char *buf, int size );
+
+private:
+
+ bool makeSocket();
+ void sendrtp( char *data, int len );
+ void psiTables( QPtrList<ChannelDesc> *channels );
+ void fillPackets( unsigned short pid, unsigned char *buf, int len, int &npack );
+ void calculateCRC( unsigned char *p_begin, unsigned char *p_end );
+
+ int rtpSocket;
+ struct sockaddr_in rtpAddr;
+ struct rtpheader hRtp;
+ QString address;
+ int port, senderPort;
+ unsigned char thBuf[188*10];
+ unsigned int CRC32[256];
+ int thWrite;
+ unsigned char *psiBuffer;
+ int psiBufferSize;
+ int psiPackets;
+ QTimer psiTimer;
+ bool writePsi;
+
+private slots:
+ void setPSI();
+};
+
+#endif /* TS2RTP_H */
diff --git a/kaffeine/src/input/dvbclient/Makefile.am b/kaffeine/src/input/dvbclient/Makefile.am
new file mode 100644
index 0000000..fb4a110
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/Makefile.am
@@ -0,0 +1,23 @@
+INCLUDES = -I$(top_srcdir)/kaffeine/src/input/ \
+ $(all_includes)
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libkaffeinedvbclient.la
+
+libkaffeinedvbclient_la_SOURCES = cdchannel.cpp \
+ cdchannel.h \
+ cdwidget.cpp \
+ cdwidget.h \
+ cddump.cpp \
+ cddump.h \
+ cdlisten.cpp \
+ cdlisten.h \
+ cdcleaner.cpp \
+ cdcleaner.h
+
+libkaffeinedvbclient_la_LDFLAGS = $(KDE_RPATH) \
+ $(all_libraries) \
+ -L$(top_srcdir)/kaffeine/src/input
+
+libkaffeinedvbclient_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la
diff --git a/kaffeine/src/input/dvbclient/cdchannel.cpp b/kaffeine/src/input/dvbclient/cdchannel.cpp
new file mode 100644
index 0000000..6b0fad1
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdchannel.cpp
@@ -0,0 +1,54 @@
+/*
+ * cdchannel.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "cdchannel.h"
+
+
+
+CdChannel::CdChannel()
+{
+ name = "";
+ vpid = apid = 0;
+ ac3 = 0;
+ subpid = page = id = 0;
+ type = 0;
+ lang = "";
+}
+
+
+
+CdChannel::CdChannel( const QString &n, int vp, int ap, int ac, int spid, int pg, int an, int tp, const QString &lg )
+{
+ name = n;
+ vpid = vp;
+ apid = ap;
+ ac3 = ac;
+ subpid = spid;
+ page = pg;
+ id = an;
+ type = tp;
+ lang = lg;
+}
+
+
+
+CdChannel::~CdChannel()
+{
+}
diff --git a/kaffeine/src/input/dvbclient/cdchannel.h b/kaffeine/src/input/dvbclient/cdchannel.h
new file mode 100644
index 0000000..880d95e
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdchannel.h
@@ -0,0 +1,45 @@
+/*
+ * cdchannel.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CDCHANNEL_H
+#define CDCHANNEL_H
+
+#include <qstring.h>
+
+
+
+class CdChannel
+{
+
+public:
+
+ CdChannel();
+ CdChannel( const QString &n, int vp, int ap, int ac, int spid, int pg, int an, int tp, const QString &lg );
+ ~CdChannel();
+
+ QString name;
+ unsigned short vpid, apid;
+ char ac3;
+ unsigned short subpid, page, id;
+ unsigned char type;
+ QString lang;
+};
+
+#endif /* CDCHANNEL_H */
diff --git a/kaffeine/src/input/dvbclient/cdcleaner.cpp b/kaffeine/src/input/dvbclient/cdcleaner.cpp
new file mode 100644
index 0000000..58445a5
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdcleaner.cpp
@@ -0,0 +1,69 @@
+/*
+ * cdcleaner.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qdir.h>
+#include <qstringlist.h>
+
+#include "cdcleaner.h"
+
+
+
+CdCleaner::CdCleaner( const QString &path )
+{
+ livePath = path;
+
+ connect( &timer, SIGNAL(timeout()), this, SLOT(doClean()) );
+ timer.start( 60*1000 );
+}
+
+
+
+CdCleaner::~CdCleaner()
+{
+ wait();
+}
+
+
+
+void CdCleaner::doClean()
+{
+ start( QThread::LowestPriority );
+}
+
+
+
+void CdCleaner::setPath( const QString &path )
+{
+ livePath = path;
+}
+
+
+
+void CdCleaner::run()
+{
+ QStringList list;
+ QDir d;
+
+ d.setPath( livePath );
+ list = d.entryList( "DVBClient-*.ts", QDir::Files, QDir::Name );
+ if ( list.count()>1 ) d.remove( list[0] );
+}
+
+#include "cdcleaner.moc"
diff --git a/kaffeine/src/input/dvbclient/cdcleaner.h b/kaffeine/src/input/dvbclient/cdcleaner.h
new file mode 100644
index 0000000..e4423d6
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdcleaner.h
@@ -0,0 +1,56 @@
+/*
+ * cdcleaner.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CDCLEANER_H
+#define CDCLEANER_H
+
+#include <qobject.h>
+#include <qthread.h>
+#include <qstring.h>
+#include <qtimer.h>
+
+
+
+class CdCleaner : public QObject, public QThread
+{
+
+ Q_OBJECT
+
+public:
+
+ CdCleaner( const QString &path );
+ ~CdCleaner();
+ void setPath( const QString &path );
+
+protected:
+
+ virtual void run();
+
+private slots:
+
+ void doClean();
+
+private:
+
+ QTimer timer;
+ QString livePath;
+};
+
+#endif /* CDCLEANER_H */
diff --git a/kaffeine/src/input/dvbclient/cddump.cpp b/kaffeine/src/input/dvbclient/cddump.cpp
new file mode 100644
index 0000000..075025a
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cddump.cpp
@@ -0,0 +1,362 @@
+/*
+ * cddump.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <klocale.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+
+#include "cddump.h"
+
+
+
+CdDump::CdDump( const QString &pipe )
+{
+ unsigned int i, j, k;
+
+ for( i = 0 ; i < 256 ; i++ ) {
+ k = 0;
+ for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) {
+ k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
+ }
+ CRC32[i] = k;
+ }
+
+ isRunning = false;
+ fifoName = pipe;
+ connect( &timerPatPmt, SIGNAL(timeout()), this, SLOT(setPatPmt()) );
+ timerPatPmt.start( 500 );
+}
+
+
+
+void CdDump::calculateCRC( unsigned char *p_begin, unsigned char *p_end )
+{
+ unsigned int i_crc = 0xffffffff;
+
+ // Calculate the CRC
+ while( p_begin < p_end ) {
+ i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((unsigned int)*p_begin) ];
+ p_begin++;
+ }
+
+ // Store it after the data
+ p_end[0] = (i_crc >> 24) & 0xff;
+ p_end[1] = (i_crc >> 16) & 0xff;
+ p_end[2] = (i_crc >> 8) & 0xff;
+ p_end[3] = (i_crc >> 0) & 0xff;
+}
+
+
+
+void CdDump::writePat()
+{
+ int i;
+
+ tspat[0x00] = 0x47; // sync_byte
+ tspat[0x01] = 0x40;
+ tspat[0x02] = 0x00; // PID = 0x0000
+ tspat[0x03] = 0x10; // | (ps->pat_counter & 0x0f);
+ tspat[0x04] = 0x00; // CRC calculation begins here
+ tspat[0x05] = 0x00; // 0x00: Program association section
+ tspat[0x06] = 0xb0;
+ tspat[0x07] = 0x11; // section_length = 0x011
+ tspat[0x08] = 0x00;
+ tspat[0x09] = 0xbb; // TS id = 0x00b0 (what the vlc calls "Stream ID")
+ tspat[0x0a] = 0xc1;
+ // section # and last section #
+ tspat[0x0b] = tspat[0x0c] = 0x00;
+ // Network PID (useless)
+ tspat[0x0d] = tspat[0x0e] = 0x00; tspat[0x0f] = 0xe0; tspat[0x10] = 0x10;
+ // Program Map PID
+ pmtpid = 0x64;
+ while ( pmtpid==chan.vpid || pmtpid==chan.apid ) pmtpid--;
+ tspat[0x11] = 0x03; tspat[0x12] = 0xe8; tspat[0x13] = 0xe0; tspat[0x14] = pmtpid;
+ // Put CRC in ts[0x15...0x18]
+ calculateCRC( tspat + 0x05, tspat + 0x15 );
+ // needed stuffing bytes
+ for (i=0x19 ; i < 188 ; i++) tspat[i]=0xff;
+}
+
+
+
+void CdDump::writePmt()
+{
+ int i, off=0;
+
+ tspmt[0x00] = 0x47; //sync_byte
+ tspmt[0x01] = 0x40;
+ tspmt[0x02] = pmtpid;
+ tspmt[0x03] = 0x10;
+ tspmt[0x04] = 0x00; // CRC calculation begins here
+ tspmt[0x05] = 0x02; // 0x02: Program map section
+ tspmt[0x06] = 0xb0;
+ tspmt[0x07] = 0x20; // section_length
+ tspmt[0x08] = 0x03;
+ tspmt[0x09] = 0xe8; // prog number
+ tspmt[0x0a] = 0xc1;
+ // section # and last section #
+ tspmt[0x0b] = tspmt[0x0c] = 0x00;
+ // PCR PID
+ tspmt[0x0d] = chan.vpid>>8; tspmt[0x0e] = chan.vpid&0xff;
+ // program_info_length == 0
+ tspmt[0x0f] = 0xf0; tspmt[0x10] = 0x00;
+ // Program Map / Video PID
+ tspmt[0x11] = 0x02; // stream type = video
+ tspmt[0x12] = chan.vpid>>8; tspmt[0x13] = chan.vpid&0xff;
+ tspmt[0x14] = 0xf0; tspmt[0x15] = 0x09; // es info length
+ // useless info
+ tspmt[0x16] = 0x07; tspmt[0x17] = 0x04; tspmt[0x18] = 0x08; tspmt[0x19] = 0x80;
+ tspmt[0x1a] = 0x24; tspmt[0x1b] = 0x02; tspmt[0x1c] = 0x11; tspmt[0x1d] = 0x01;
+ tspmt[0x1e] = 0xfe;
+ off = 0x1e;
+ // audio pid
+ if ( chan.ac3 ) {
+ tspmt[++off] = 0x81; // stream type = xine see this as ac3
+ tspmt[++off] = chan.apid>>8; tspmt[++off] = chan.apid&0xff;
+ tspmt[++off] = 0xf0; tspmt[++off] = 0x0c; // es info length
+ tspmt[++off] = 0x05; tspmt[++off] = 0x04; tspmt[++off] = 0x41;
+ tspmt[++off] = 0x43; tspmt[++off] = 0x2d; tspmt[++off] = 0x33;
+ }
+ else {
+ tspmt[++off] = 0x04; // stream type = audio
+ tspmt[++off] = chan.apid>>8; tspmt[++off] = chan.apid&0xff;
+ tspmt[++off] = 0xf0; tspmt[++off] = 0x06; // es info length
+ }
+ tspmt[++off] = 0x0a; // iso639 descriptor tag
+ tspmt[++off] = 0x04; // descriptor length
+ tspmt[++off] = '?';
+ tspmt[++off] = '?';
+ tspmt[++off] = '?';
+ tspmt[++off] = 0x00; // audio type
+ // subtitles
+ if ( chan.subpid ) {
+ tspmt[++off] = 0x06; // stream type = ISO_13818_PES_PRIVATE
+ tspmt[++off] = chan.subpid>>8; tspmt[++off] = chan.subpid&0xff;
+ tspmt[++off] = 0xf0; tspmt[++off] = 0x0a; // es info length
+ tspmt[++off] = 0x59; //DVB sub tag
+ tspmt[++off] = 0x08; // descriptor length
+ if ( !chan.lang.isEmpty() ) {
+ tspmt[++off] = chan.lang.constref(0);
+ tspmt[++off] = chan.lang.constref(1);
+ tspmt[++off] = chan.lang.constref(2);
+ }
+ else {
+ tspmt[++off] = '?';
+ tspmt[++off] = '?';
+ tspmt[++off] = '?';
+ }
+ tspmt[++off] = chan.type; //sub type
+ tspmt[++off] = chan.page>>8; tspmt[++off] = chan.page&0xff; // comp_page_id
+ tspmt[++off] = chan.id>>8; tspmt[++off] = chan.id&0xff; // anc_page_id
+ }
+ tspmt[0x07] = off-3; // update section_length
+ // Put CRC in ts[0x29...0x2c]
+ calculateCRC( tspmt+0x05, tspmt+off+1 );
+ // needed stuffing bytes
+ for (i=off+5 ; i < 188 ; i++) tspmt[i]=0xff;
+}
+
+
+
+void CdDump::setPatPmt()
+{
+ patpmt = true;
+}
+
+
+
+bool CdDump::go( const QString &ad, int port, CdChannel c )
+{
+ int sockopt=1;
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ KMessageBox::information( 0, i18n("Can't open socket."), i18n("DVB Client") );
+ sock = 0;
+ return false;
+ }
+
+ addr.sin_family = AF_INET; // host byte order
+ addr.sin_port = htons( port ); // short, network byte order
+ addr.sin_addr.s_addr = inet_addr( ad.ascii() );
+ memset( &( addr.sin_zero ), '\0', 8 ); // zero the rest of the struct
+
+ if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt) ) < 0 ){
+ KMessageBox::information( 0, i18n("Can't set socket option!!!"), i18n("DVB Client") );
+ close( sock );
+ sock = 0;
+ return false;
+ }
+
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ KMessageBox::information( 0, i18n("Can't bind socket!!!"), i18n("DVB Client") );
+ close( sock );
+ sock = 0;
+ return false;
+ }
+
+ chan = c;
+ writePat();
+ writePmt();
+ patpmt = true;
+ timeShiftFileName = "";
+ timeShifting = false;
+ isRunning = true;
+ start();
+ return true;
+}
+
+
+
+void CdDump::stop()
+{
+ isRunning = false;
+ if ( !wait(1000) ) {
+ terminate();
+ wait();
+ }
+ if ( fdPipe ) {
+ close( fdPipe );
+ fdPipe = 0;
+ }
+ if ( timeShifting )
+ liveFile.close();
+ if ( sock ) {
+ close( sock );
+ sock = 0;
+ }
+}
+
+
+
+bool CdDump::running() const
+{
+ return isRunning;
+}
+
+
+
+CdDump::~CdDump()
+{
+ stop();
+}
+
+
+
+bool CdDump::doPause( const QString &name )
+{
+ if ( !timeShifting ) {
+ timeShiftFileName = name;
+ liveFile.setName( timeShiftFileName );
+ liveFile.open( IO_WriteOnly|IO_Truncate );
+ liveFile.writeBlock( (char*)tspat, 188 );
+ liveFile.writeBlock( (char*)tspmt, 188 );
+ timeShifting = true;
+ return true;
+ }
+ return false;
+}
+
+
+
+void CdDump::run()
+{
+ struct srtpheader rh;
+ int lengthData;
+ char buf[1600];
+ unsigned char *b;
+#define NTS 64
+ unsigned char tbuf[NTS*188];
+ int twrite;
+ unsigned int intP;
+ char* charP = (char*) &intP;
+ int headerSize;
+ int lengthPacket;
+ int len;
+ int pid;
+
+ if ( (fdPipe=open( fifoName.ascii(), O_WRONLY))<0 ) {
+ perror("DUMP PIPE FILE: ");
+ return;
+ }
+ fprintf(stderr,"Dump pipe opened\n");
+
+ twrite = 0;
+
+ while( isRunning ) {
+ lengthPacket = recv( sock, buf, 1590, 0 );
+ rh.b.v = (unsigned int) ((buf[0]>>6)&0x03);
+ rh.b.p = (unsigned int) ((buf[0]>>5)&0x01);
+ rh.b.x = (unsigned int) ((buf[0]>>4)&0x01);
+ rh.b.cc = (unsigned int) ((buf[0]>>0)&0x0f);
+ rh.b.m = (unsigned int) ((buf[1]>>7)&0x01);
+ rh.b.pt = (unsigned int) ((buf[1]>>0)&0x7f);
+ intP = 0;
+ memcpy( charP+2, &buf[2], 2 );
+ rh.b.sequence = ntohl( intP );
+ intP = 0;
+ memcpy( charP, &buf[4], 4 );
+ rh.timestamp = ntohl( intP );
+ headerSize = 12 + 4*rh.b.cc; /* in bytes */
+ lengthData = lengthPacket - headerSize;
+
+ b = (unsigned char*)buf+headerSize;
+ len = lengthData;
+ while ( len>0 ) {
+ pid = (((b[1] & 0x1f) << 8) | b[2]);
+ if ( pid==chan.vpid || pid==chan.apid || pid==chan.subpid ) {
+ memcpy( tbuf+twrite, b, 188 );
+ twrite+= 188;
+ if ( twrite==NTS*188 ) {
+ if ( fdPipe ) {
+ if ( patpmt ) {
+ write( fdPipe, tspat, 188 );
+ write( fdPipe, tspmt, 188 );
+ }
+ write( fdPipe, tbuf, NTS*188 );
+ if ( timeShifting ) {
+ if ( close( fdPipe )<0 )
+ perror("close out pipe: ");
+ else {
+ fprintf(stderr,"out pipe closed\n");
+ fdPipe = 0;
+ }
+ }
+ }
+ else {
+ if ( patpmt ) {
+ liveFile.writeBlock( (char*)tspat, 188 );
+ liveFile.writeBlock( (char*)tspmt, 188 );
+ }
+ liveFile.writeBlock( (char*)tbuf, 188*NTS );
+ }
+ patpmt = false;
+ twrite = 0;
+ }
+ }
+ b+=188;
+ len-=188;
+ }
+ }
+}
+
+#include "cddump.moc"
diff --git a/kaffeine/src/input/dvbclient/cddump.h b/kaffeine/src/input/dvbclient/cddump.h
new file mode 100644
index 0000000..695eb4b
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cddump.h
@@ -0,0 +1,106 @@
+/*
+ * cddump.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CDDUMP_H
+#define CDDUMP_H
+
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <qthread.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qfile.h>
+#include <qtimer.h>
+
+#include "cdchannel.h"
+
+
+
+struct srtpbits {
+ unsigned int v:2; /* version: 2 */
+ unsigned int p:1; /* is there padding appended: 0 */
+ unsigned int x:1; /* number of extension headers: 0 */
+ unsigned int cc:4; /* number of CSRC identifiers: 0 */
+ unsigned int m:1; /* marker: 0 */
+ unsigned int pt:7; /* payload type: 33 for MPEG2 TS - RFC 1890 */
+ unsigned int sequence:16; /* sequence number: random */
+};
+
+struct srtpheader { /* in network byte order */
+ struct srtpbits b;
+ int timestamp; /* start: random */
+ int ssrc; /* random */
+};
+
+
+
+class CdDump : public QObject, public QThread
+{
+ Q_OBJECT
+
+public :
+
+ CdDump( const QString &pipe );
+ ~CdDump();
+ virtual void run();
+ bool go( const QString &ad, int port, CdChannel c );
+ void stop();
+ bool doPause( const QString &name );
+ bool running() const;
+
+private slots:
+
+ void setPatPmt();
+
+private :
+
+ void writePmt();
+ void writePat();
+ void calculateCRC( unsigned char *p_begin, unsigned char *p_end );
+
+ QFile liveFile;
+ bool timeShifting;
+ QString timeShiftFileName;
+ int waitPause;
+ int fdPipe;
+ QString fifoName;
+ bool isRunning;
+ int sock;
+ struct sockaddr_in addr;
+ CdChannel chan;
+ unsigned char tspat[188];
+ unsigned char tspmt[188];
+ unsigned int CRC32[256];
+ int pmtpid;
+ QTimer timerPatPmt;
+ bool patpmt;
+
+signals:
+
+ void playDvb();
+ void shifting( bool );
+
+};
+
+#endif /* CDDUMP_H */
diff --git a/kaffeine/src/input/dvbclient/cdlisten.cpp b/kaffeine/src/input/dvbclient/cdlisten.cpp
new file mode 100644
index 0000000..89ea3c7
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdlisten.cpp
@@ -0,0 +1,113 @@
+/*
+ * cdlisten.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <unistd.h>
+
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include "cdlisten.h"
+
+
+
+CdListen::CdListen()
+{
+ connect( &timer, SIGNAL(timeout()), this, SLOT(updateList()) );
+}
+
+
+
+CdListen::~CdListen()
+{
+ stop();
+}
+
+
+
+void CdListen::updateList()
+{
+ if ( newList==currentList ) return;
+
+ currentList = newList;
+ emit listChanged( currentList );
+}
+
+
+
+void CdListen::stop()
+{
+ isRunning = false;
+ timer.stop();
+ if ( !wait(100) ) {
+ terminate();
+ wait();
+ }
+ close( sock );
+ sock = 0;
+}
+
+
+
+bool CdListen::go( const QString &ad, int port )
+{
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+ KMessageBox::information( 0, i18n("Can't open info socket."), i18n("DVB Client") );
+ sock = 0;
+ return false;
+ }
+
+ addr.sin_family = AF_INET; // host byte order
+ addr.sin_port = htons( port ); // short, network byte order
+ addr.sin_addr.s_addr = inet_addr( ad.ascii() );
+ memset( &( addr.sin_zero ), '\0', 8 ); // zero the rest of the struct
+
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+ KMessageBox::information( 0, i18n("Can't bind info socket!!!"), i18n("DVB Client") );
+ close( sock );
+ sock = 0;
+ return false;
+ }
+
+ currentList = "";
+ newList = currentList;
+ isRunning = true;
+ timer.start( 500, false );
+ start();
+ return true;
+}
+
+
+
+void CdListen::run()
+{
+ char buf[1500];
+ int n;
+ struct sockaddr_in a;
+ socklen_t len = sizeof(struct sockaddr);
+
+ while ( isRunning ) {
+ memset( buf, '\0', 1500 );
+ n = recvfrom( sock, buf, 1500, 0, (struct sockaddr *)&a, &len );
+ if ( n>0 ) newList = buf;
+ else msleep(500);
+ }
+}
+
+#include "cdlisten.moc"
diff --git a/kaffeine/src/input/dvbclient/cdlisten.h b/kaffeine/src/input/dvbclient/cdlisten.h
new file mode 100644
index 0000000..2e1bc7e
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdlisten.h
@@ -0,0 +1,62 @@
+/*
+ * cdlisten.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CDLISTEN_H
+#define CDLISTEN_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <qobject.h>
+#include <qthread.h>
+#include <qtimer.h>
+#include <qstring.h>
+
+class CdListen : public QObject, public QThread
+{
+ Q_OBJECT
+
+public:
+
+ CdListen();
+ ~CdListen();
+ virtual void run();
+ bool go( const QString &ad, int port );
+ void stop();
+
+private slots:
+
+ void updateList();
+
+private:
+
+ int sock;
+ struct sockaddr_in addr;
+ bool isRunning;
+ QTimer timer;
+ QString currentList, newList;
+
+signals:
+
+ void listChanged( const QString& );
+};
+
+#endif /* CDLISTEN_H */
diff --git a/kaffeine/src/input/dvbclient/cdwidget.cpp b/kaffeine/src/input/dvbclient/cdwidget.cpp
new file mode 100644
index 0000000..f28d128
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdwidget.cpp
@@ -0,0 +1,371 @@
+/*
+ * cdwidget.cpp
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <qapplication.h>
+#include <qlayout.h>
+#include <qdir.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "cdwidget.h"
+
+
+
+CdWidget::CdWidget( const QString &ad, int port, int info, const QString &tspath, QWidget *parent, QObject *objParent, const char *name )
+ : KaffeineInput( objParent, name )
+{
+ mainWidget = new QVBox( parent );
+ mainWidget->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred) );
+ split = new QSplitter( mainWidget );
+ split->setOpaqueResize( true );
+ playerBox = new QVBox( split );
+ playerBox->setMinimumWidth( 200 );
+ channelsLb = new QListBox( split );
+ split->moveToFirst( channelsLb );
+ channelsLb->setSizePolicy( QSizePolicy (QSizePolicy::Preferred, QSizePolicy::MinimumExpanding) );
+ split->setResizeMode( channelsLb, QSplitter::KeepSize );
+
+ cdAddress = ad;
+ cdPort = port;
+ cdInfo = info;
+ cdShiftDir = tspath;
+ if ( !cdShiftDir.endsWith("/") ) cdShiftDir+= "/";
+
+ cleaner = new CdCleaner( cdShiftDir );
+
+ chan.setAutoDelete( true );
+
+ KIconLoader *icon = new KIconLoader();
+
+ tvPix = icon->loadIcon( "kdvbtv", KIcon::Small );
+ raPix = icon->loadIcon( "kdvbra", KIcon::Small );
+ delete icon;
+
+ listen = new CdListen();
+ listen->go( cdAddress, cdInfo );
+
+ fifoName = QDir::homeDirPath()+"/.kaxclient.ts";
+ QFile f( fifoName );
+ if ( f.exists() ) f.remove();
+ if ( (mkfifo( fifoName.ascii(), 0644 ))<0 ) {
+ perror( fifoName.latin1() );
+ fifoName = "";
+ dump = 0;
+ }
+ else {
+ dump = new CdDump( fifoName );
+ connect( channelsLb, SIGNAL(selected(const QString &)), this, SLOT(channelSelected(const QString &)) );
+ connect( listen, SIGNAL(listChanged(const QString&)), this, SLOT(updateList(const QString&)) );
+ }
+
+ lastChannel = 0;
+ enableLive( false );
+ loadConfig( KGlobal::config() );
+}
+
+
+
+void CdWidget::togglePanel()
+{
+ if ( channelsLb->isHidden() )
+ channelsLb->show();
+ else
+ channelsLb->hide();
+}
+
+
+
+void CdWidget::getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames )
+{
+ uiNames.append( i18n("DVB Client") );
+ iconNames.append( "network" );
+ targetNames.append( "DVBCLIENT" );
+}
+
+
+
+bool CdWidget::execTarget( const QString &target )
+{
+ if ( target=="DVBCLIENT" ) {
+ emit showMe( this );
+ QTimer::singleShot( 100, this, SLOT(playLastChannel()) );
+ return true;
+ }
+ return false;
+}
+
+
+
+QWidget* CdWidget::wantPlayerWindow()
+{
+ return playerBox;
+}
+
+
+
+QWidget* CdWidget::inputMainWidget()
+{
+ return mainWidget;
+}
+
+
+
+CdWidget::~CdWidget()
+{
+ if ( dump->running() )
+ emit dvbStop();
+ stopLive();
+ delete dump;
+ delete listen;
+ delete cleaner;
+}
+
+
+
+void CdWidget::loadConfig( KConfig* config )
+{
+ QValueList<int> sl;
+
+ config->setGroup("DVBClient");
+ sl = config->readIntListEntry("SplitSizes");
+ if ( !sl.count() ) {
+ sl.append( 200 );
+ sl.append( 200 );
+ }
+ split->setSizes( sl );
+}
+
+
+
+void CdWidget::saveConfig()
+{
+ KConfig* config = KGlobal::config();
+ config->setGroup("DVBClient");
+ config->writeEntry( "SplitSizes", split->sizes() );
+}
+
+
+
+void CdWidget::updateList( const QString &list )
+{
+ QString c;
+ QString s = list;
+ int pos;
+ QString name, lang;
+ int apid, vpid, ac3, subpid, page, id, type;
+
+ if ( dump->running() )
+ emit dvbStop();
+ dump->stop();
+
+ channelsLb->clear();
+ chan.clear();
+ if ( list=="quit" ) return;
+
+ while ( (pos = s.find("|"))!=-1 ) {
+ name = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ vpid = s.left( pos ).toInt();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ apid = s.left( pos ).toInt();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ if ( s.left( pos )=="n" ) ac3 = 0;
+ else ac3 = 1;
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ subpid = s.left( pos ).toInt();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ page = s.left( pos ).toInt();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ id = s.left( pos ).toInt();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ type = s.left( pos ).toInt();
+ s = s.right( s.length()-pos-1 );
+ pos = s.find("|");
+ lang = s.left( pos );
+ s = s.right( s.length()-pos-1 );
+ chan.append( new CdChannel( name, vpid, apid, ac3, subpid, page, id, type, lang ) );
+ if ( vpid ) channelsLb->insertItem( tvPix, name );
+ else channelsLb->insertItem( raPix, name );
+ }
+}
+
+
+
+bool CdWidget::nextTrack( MRL& )
+{
+ next();
+ return false;
+}
+
+
+
+bool CdWidget::previousTrack( MRL& )
+{
+ previous();
+ return false;
+}
+
+
+
+bool CdWidget::currentTrack( MRL& )
+{
+ playLastChannel();
+ return false;
+}
+
+
+
+bool CdWidget::trackNumber( int num, MRL& )
+{
+ playNumChannel( num );
+ return false;
+}
+
+
+
+bool CdWidget::playbackFinished( MRL& )
+{
+ return false;
+}
+
+
+
+void CdWidget::playLastChannel()
+{
+ if ( !channelsLb->count() )
+ return;
+ if ( !lastChannel ) {
+ lastChannel++;
+ }
+ else if ( lastChannel>(int)channelsLb->count() ) {
+ lastChannel = 1;
+ }
+ channelSelected( channelsLb->text( lastChannel-1 ) );
+}
+
+
+
+void CdWidget::playNumChannel( int num )
+{
+ if ( num>0 && num<=(int)channelsLb->count() )
+ channelSelected( channelsLb->text( num-1 ) );
+}
+
+
+
+void CdWidget::next()
+{
+ if ( !channelsLb->count() )
+ return;
+ if ( (lastChannel+1)>(int)channelsLb->count() )
+ return;
+ lastChannel++;
+ channelSelected( channelsLb->text( lastChannel-1 ) );
+}
+
+
+
+void CdWidget::previous()
+{
+ if ( !channelsLb->count() )
+ return;
+ if ( (lastChannel-1)<1 )
+ return;
+ lastChannel--;
+ channelSelected( channelsLb->text( lastChannel-1 ) );
+}
+
+
+
+void CdWidget::channelSelected( const QString &name )
+{
+ int i;
+
+ for ( i=0; i<(int)chan.count(); i++ ) {
+ if ( chan.at(i)->name==name ) {
+ emit setCurrentPlugin( this );
+ dump->stop();
+ dump->go( cdAddress, cdPort, *chan.at(i) );
+ emit dvbOpen( fifoName, chan.at(i)->name, chan.at(i)->vpid );
+ break;
+ }
+ }
+}
+
+
+
+void CdWidget::pauseLiveTV()
+{
+ if ( !dump )
+ return;
+ if ( dump->running() ) {
+ timeShiftFileName = cdShiftDir+"DVBClient-"+QDateTime::currentDateTime().toString( Qt::ISODate )+".ts";
+ if ( dump->doPause( timeShiftFileName ) ) emit setTimeShiftFilename( timeShiftFileName );
+ }
+}
+
+
+
+void CdWidget::stopLive()
+{
+ if ( !dump )
+ return;
+ dump->stop();
+ emit setTimeShiftFilename( "" );
+}
+
+
+
+void CdWidget::enableLive( bool b )
+{
+ channelsLb->setEnabled( b );
+}
+
+
+
+void CdWidget::setParam( const QString &ad, int port, int info, const QString &tspath )
+{
+ cdAddress = ad;
+ cdPort = port;
+ cdInfo = info;
+ cdShiftDir = tspath;
+ if ( !cdShiftDir.endsWith("/") ) cdShiftDir+= "/";
+ cleaner->setPath( cdShiftDir );
+
+ channelsLb->clear();
+ chan.clear();
+ if ( dump ) {
+ if ( dump->running() )
+ emit dvbStop();
+ dump->stop();
+ }
+ listen->stop();
+ listen->go( cdAddress, cdInfo );
+}
+
+#include "cdwidget.moc"
diff --git a/kaffeine/src/input/dvbclient/cdwidget.h b/kaffeine/src/input/dvbclient/cdwidget.h
new file mode 100644
index 0000000..2862320
--- /dev/null
+++ b/kaffeine/src/input/dvbclient/cdwidget.h
@@ -0,0 +1,107 @@
+/*
+ * cdwidget.h
+ *
+ * Copyright (C) 2005 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CDWIDGET_H
+#define CDWIDGET_H
+
+#include <qlistbox.h>
+#include <qpixmap.h>
+#include <qptrlist.h>
+#include <qvbox.h>
+#include <qsplitter.h>
+
+#include <kconfig.h>
+
+#include "cddump.h"
+#include "cdlisten.h"
+#include "cdcleaner.h"
+#include "kaffeineinput.h"
+
+
+
+class CdWidget : public KaffeineInput
+{
+ Q_OBJECT
+
+public:
+
+ CdWidget( const QString &ad, int port, int info, const QString &tspath, QWidget *parent, QObject *objParent, const char *name );
+ ~CdWidget();
+ void setParam( const QString &ad, int port, int info, const QString &tspath );
+ void enableLive( bool b );
+ void playNumChannel( int num );
+ void next();
+ void previous();
+
+ // Reimplemented from KaffeineInput
+ QWidget *wantPlayerWindow();
+ QWidget *inputMainWidget();
+ bool nextTrack( MRL& );
+ bool previousTrack( MRL& );
+ bool currentTrack( MRL& );
+ bool trackNumber( int, MRL& );
+ bool playbackFinished( MRL& );
+ void getTargets( QStringList &uiNames, QStringList &iconNames, QStringList &targetNames );
+ void togglePanel();
+ bool execTarget( const QString& );
+ void saveConfig();
+ //***************************************
+
+ QListBox *channelsLb;
+ QVBox *mainWidget;
+ QVBox *playerBox;
+
+public slots:
+
+ void playLastChannel();
+ void stopLive();
+ void pauseLiveTV();
+
+private:
+ void loadConfig( KConfig* config );
+ void saveConfig( KConfig* config );
+
+ QSplitter *split;
+ CdDump *dump;
+ CdListen *listen;
+ QString cdAddress;
+ int cdPort;
+ int cdInfo;
+ QString cdShiftDir;
+ QPixmap tvPix, raPix;
+ QPtrList<CdChannel> chan;
+ QString fifoName;
+ QString timeShiftFileName;
+ CdCleaner *cleaner;
+ int lastChannel;
+
+private slots:
+
+ void updateList( const QString &list );
+ void channelSelected( const QString &name );
+
+signals:
+
+ void dvbOpen(const QString&, const QString&, int);
+ void dvbStop();
+ void setTimeShiftFilename( const QString& );
+};
+
+#endif /* CDWIDGET_H */
diff --git a/kaffeine/src/input/kaffeineinput.cpp b/kaffeine/src/input/kaffeineinput.cpp
new file mode 100644
index 0000000..74d4a8b
--- /dev/null
+++ b/kaffeine/src/input/kaffeineinput.cpp
@@ -0,0 +1,31 @@
+/*
+ * kaffeineinput.cpp
+ *
+ * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "kaffeineinput.h"
+
+KaffeineInput::KaffeineInput(QObject* parent, const char* name) : QObject( parent, name )
+{
+}
+
+KaffeineInput::~KaffeineInput()
+{
+}
+
+#include "kaffeineinput.moc"
diff --git a/kaffeine/src/input/kaffeineinput.h b/kaffeine/src/input/kaffeineinput.h
new file mode 100644
index 0000000..0670178
--- /dev/null
+++ b/kaffeine/src/input/kaffeineinput.h
@@ -0,0 +1,115 @@
+/*
+ * kaffeineinput.h
+ *
+ * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KAFFEINEINPUT_H
+#define KAFFEINEINPUT_H
+
+#include <qstring.h>
+#include <qwidget.h>
+
+#include <kxmlguiclient.h>
+
+class MRL;
+
+class KaffeineInput : public QObject, public KXMLGUIClient
+{
+ Q_OBJECT
+public:
+ KaffeineInput(QObject* parent, const char* name);
+ virtual ~KaffeineInput();
+
+ // if you want the player window to be displayed on one of your widgets, return a pointer to that one.
+ virtual QWidget *wantPlayerWindow() {return NULL;}
+
+ // you MUST return your main widget (the one containing all your gui).
+ virtual QWidget *inputMainWidget() {return NULL;}
+
+ // called when the user want next track and you are the current input.
+ // fill the MRL and return true to play your next track.
+ virtual bool nextTrack( MRL& ) {return false;}
+
+ // called when the user want previous track and you are the current input.
+ // fill the MRL and return true to play your previous track.
+ virtual bool previousTrack( MRL& ) {return false;}
+
+ // called when the user starts playing and you are the current input.
+ // fill the MRL and return true to play your current track.
+ virtual bool currentTrack( MRL& ) {return false;}
+
+ // called when the user enters a track number and you are the current input.
+ // fill the MRL and return true to play that track.
+ virtual bool trackNumber( int, MRL& ) {return false;}
+
+ // called when the player has reached the end of current track and you are the current input.
+ // fill the MRL and return true to play your next track.
+ virtual bool playbackFinished( MRL& ) {return false;}
+
+ // called when the player is paused and you are the current input.
+ virtual void playerPaused() {}
+
+ // called when the player is stopped and you are the current input.
+ virtual void playerStopped() {}
+
+ // called when playing failed and you are the current input.
+ virtual void playbackFailed() {}
+
+ // called when the player finds metadata(tags) and you are the current input.
+ virtual void mergeMeta(const MRL&) {}
+
+ // shortcuts buttons to be displayed in the start window.
+ virtual void getTargets( QStringList&/*uiNames*/, QStringList&/*iconNames*/, QStringList&/*targetNames*/ ) {}
+
+ // play shortcut, return false if the target is not yours;
+ virtual bool execTarget( const QString&/*target*/ ) {return false;}
+
+ // toggle your panel (show / hide) if any
+ virtual void togglePanel() {}
+
+ // called when kaffeine is about to quit. Here, you could ask the user to confirm if you have pending
+ // operations. Return accordingly.
+ virtual bool close() {return true;}
+
+ // called when kaffeine is about to quit. Save your settings now.
+ virtual void saveConfig() {}
+
+ // called when a video is to be played, return false to not automatically switch to player window.
+ virtual bool showPlayer() {return true;}
+
+signals:
+ // emit that to play your mrl (you'll become the current input, if not yet).
+ void play(const MRL&, KaffeineInput*/*this*/);
+
+ // emit that if you want a message to be displayed in statusbar. (do that only if you are the current input, e.g. after play())
+ void statusBarMessage(const QString&);
+
+ // emit that if you want to stop the player. Be aware that it'll end with a call to playerStopped().
+ // you usually don't need that.
+ void stop();
+
+ // emit that if you want to pause the player. Be aware that it'll end with a call to playerPaused().
+ // you usually don't need that.
+ void pause();
+
+ // for special uses.
+ void setCurrentPlugin( KaffeineInput* );
+ void showMe( KaffeineInput* );
+};
+
+#endif /* KAFFEINEINPUT_H */