Package: ariblib
ariblib=======速度優先の Transport Stream パーサです。Python 3.2 での動作が前提ですが、3.1 でも動くかもしれません。```$ sudo python3.2 setup.py install```ARIB-STD で定義されているデータ構造をなるべく近い形でPython コードとして記述できるようにしています。たとえば、 Program Map Section のデータ構造は ARIB-STD-B10 第2部付録E 表E-3 で以下のように記述されています:```TS_program_map_section(){table_id                   8  uimsbfsection_syntax_indicator   1  bslbf‘0’                        1  bslbfreserved                   2  bslbfsection_length            12  uimsbfprogram_number            16  uimsbfreserved                   2  bslbfversion_number             5  uimsbfcurrent_next_indicator     1  bslbfsection_number             8  uimsbflast_section_number        8  uimsbfreserved                   3  bslbfPCR_PID                   13  uimsbfreserved                   4  bslbfprogram_info_length       12  uimsbffor (i=0;i<N;i++){descriptor()}for (i=0;i<N1;i++){stream_type            8  uimsbfreserved               3  bslbfelementary_PID        13  uimsbfreserved               4  bslbfES_info_length        12  uimsbffor (i=0;i<N2;i++){descriptor()}}CRC_32                    32 rpchof```これを ariblib では以下のように記述します。 (説明に必要でない行は省略しています)```pythonclass ProgramMapSection(Section):table_id = uimsbf(8)section_syntax_indicator = bslbf(1)reserved_future_use = bslbf(1)reserved_1 = bslbf(2)section_length = uimsbf(12)program_number = uimsbf(16)reserved_2 = bslbf(2)version_number = uimsbf(5)current_next_indicator = bslbf(1)section_number = uimsbf(8)last_section_number = uimsbf(8)reserved_3 = bslbf(3)PCR_PID = uimsbf(13)reserved_4 = bslbf(4)program_info_length = uimsbf(12)descriptors = descriptors(program_info_length)@loop(lambda self: self.section_length - (13 + self.program_info_length))class maps(Syntax):stream_type = uimsbf(8)reserved_1 = bslbf(3)elementary_PID = uimsbf(13)reserved_2 = bslbf(4)ES_info_length = uimsbf(12)descriptors = descriptors(ES_info_length)CRC_32 = rpchof(32)```ビット列表記をディスクリプタとして実装したり、繰り返し構造や制御構造をデコレータとして実装したりすることで、なるべく仕様書に近い形でクラスの表記ができるようにしてます。使い方例1 字幕を表示```pythonfrom ariblib import tsopenfrom ariblib.caption import captionsimport syswith tsopen(sys.argv[1]) as ts:for caption in captions(ts, color=True):body = str(caption.body)# アダプテーションフィールドの PCR の値と、そこから一番近い TOT テーブルの値から、# 字幕の表示された時刻を計算します (若干誤差が出ます)# PCR が一周した場合の処理は実装されていませんdatetime = caption.datetime.strftime('%Y-%m-%d %H:%M:%S')print('\033[35m' + datetime + '\33[37m')print(body)```使い方例2 いま放送中の番組と次の番組を表示```pythonimport sysfrom ariblib import tsopenfrom ariblib.descriptors import ShortEventDescriptorfrom ariblib.sections import EventInformationSectiondef show_program(eit):event = eit.events.__next__()program_title = event.descriptors[ShortEventDescriptor][0].event_name_charstart = event.start_timereturn "{} {}".format(program_title, start)with tsopen(sys.argv[1]) as ts:# 自ストリームの現在と次の番組を表示するEventInformationSection._table_ids = [0x4E]current = next(table for table in ts.sections(EventInformationSection)if table.section_number == 0)following = next(table for table in ts.sections(EventInformationSection)if table.section_number == 1)print('今の番組', show_program(current))print('次の番組', show_program(following))```使い方例3: 放送局名の一欄を表示(地上波ではその局, BSでは全局が表示される)```pythonimport sysfrom ariblib import tsopenfrom ariblib.constant import SERVICE_TYPESfrom ariblib.descriptors import ServiceDescriptorfrom ariblib.sections import ServiceDescriptionSectionwith tsopen(sys.argv[1]) as ts:for sdt in ts.sections(ServiceDescriptionSection):for service in sdt.services:for sd in service.descriptors[ServiceDescriptor]:print(service.service_id, SERVICE_TYPE[sd.service_type],sd.service_provider_name, sd.service_name)```使い方例4: 動画パケットの PID とその動画の解像度を表示```pythonimport sysfrom ariblib import tsopenfrom ariblib.constants import VIDEO_ENCODE_FORMATSfrom ariblib.descriptors import VideoDecodeControlDescriptorfrom ariblib.sections import ProgramAssociationSection, ProgramMapSectionwith tsopen(sys.argv[1]) as ts:pat = next(ts.sections(ProgramAssociationSection))ProgramMapSection._pids = list(pat.pmt_pids)for pmt in ts.sections(ProgramMapSection):for tsmap in pmt.maps:for vd in tsmap.descriptors.get(VideoDecodeControlDescriptor, []):print(tsmap.elementary_PID, VIDEO_ENCODE_FORMAT[vd.video_encode_format])```使い方例5: EPG情報の表示```pythonfrom ariblib import tsopenfrom ariblib.event import eventsimport syswith tsopen(sys.argv[1]) as ts:for event in events(ts):max_len = max(map(len, event.__dict__.keys()))template = "{:%ds}  {}" % max_lenfor key, value in event.__dict__.items():print(template.format(key, value))print('-' * 80)```使い方例6: 深夜アニメの出力```pythonimport sysfrom ariblib import tsopenfrom ariblib.descriptors import ContentDescriptor, ShortEventDescriptorfrom ariblib.sections import EventInformationSectionwith tsopen(sys.argv[1]) as ts:EventInformationSection._table_ids = range(0x50, 0x70)for eit in ts.sections(EventInformationSection):for event in eit.events:for genre in event.descriptors.get(ContentDescriptor, []):nibble = genre.nibbles[0]# ジャンルがアニメでないイベント、アニメであっても放送開始時刻が5時から21時のものを除きますif nibble.content_nibble_level_1 != 0x07 or 4 < event.start_time.hour < 22:continuefor sed in event.descriptors.get(ShortEventDescriptor, []):print(eit.service_id, event.event_id, event.start_time,event.duration, sed.event_name_char, sed.text_char)```