package astits import ( "fmt" "time" "github.com/asticode/go-astikit" ) // Audio types // Page: 683 | https://books.google.fr/books?id=6dgWB3-rChYC&printsec=frontcover&hl=fr const ( AudioTypeCleanEffects = 0x1 AudioTypeHearingImpaired = 0x2 AudioTypeVisualImpairedCommentary = 0x3 ) // Data stream alignments // Page: 85 | Chapter:2.6.11 | Link: http://ecee.colorado.edu/~ecen5653/ecen5653/papers/iso13818-1.pdf const ( DataStreamAligmentAudioSyncWord = 0x1 DataStreamAligmentVideoSliceOrAccessUnit = 0x1 DataStreamAligmentVideoAccessUnit = 0x2 DataStreamAligmentVideoGOPOrSEQ = 0x3 DataStreamAligmentVideoSEQ = 0x4 ) // Descriptor tags // Chapter: 6.1 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf const ( DescriptorTagAC3 = 0x6a DescriptorTagAVCVideo = 0x28 DescriptorTagComponent = 0x50 DescriptorTagContent = 0x54 DescriptorTagDataStreamAlignment = 0x6 DescriptorTagEnhancedAC3 = 0x7a DescriptorTagExtendedEvent = 0x4e DescriptorTagExtension = 0x7f DescriptorTagISO639LanguageAndAudioType = 0xa DescriptorTagLocalTimeOffset = 0x58 DescriptorTagMaximumBitrate = 0xe DescriptorTagNetworkName = 0x40 DescriptorTagParentalRating = 0x55 DescriptorTagPrivateDataIndicator = 0xf DescriptorTagPrivateDataSpecifier = 0x5f DescriptorTagRegistration = 0x5 DescriptorTagService = 0x48 DescriptorTagShortEvent = 0x4d DescriptorTagStreamIdentifier = 0x52 DescriptorTagSubtitling = 0x59 DescriptorTagTeletext = 0x56 DescriptorTagVBIData = 0x45 DescriptorTagVBITeletext = 0x46 ) // Descriptor extension tags // Chapter: 6.3 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf const ( DescriptorTagExtensionSupplementaryAudio = 0x6 ) // Service types // Chapter: 6.2.33 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf const ( ServiceTypeDigitalTelevisionService = 0x1 ) // Teletext types // Chapter: 6.2.43 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf const ( TeletextTypeAdditionalInformationPage = 0x3 TeletextTypeInitialTeletextPage = 0x1 TeletextTypeProgramSchedulePage = 0x4 TeletextTypeTeletextSubtitlePage = 0x2 TeletextTypeTeletextSubtitlePageForHearingImpairedPeople = 0x5 ) // VBI data service id // Chapter: 6.2.47 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf const ( VBIDataServiceIDClosedCaptioning = 0x6 VBIDataServiceIDEBUTeletext = 0x1 VBIDataServiceIDInvertedTeletext = 0x2 VBIDataServiceIDMonochrome442Samples = 0x7 VBIDataServiceIDVPS = 0x4 VBIDataServiceIDWSS = 0x5 ) // Descriptor represents a descriptor // TODO Handle UTF8 type Descriptor struct { AC3 *DescriptorAC3 AVCVideo *DescriptorAVCVideo Component *DescriptorComponent Content *DescriptorContent DataStreamAlignment *DescriptorDataStreamAlignment EnhancedAC3 *DescriptorEnhancedAC3 ExtendedEvent *DescriptorExtendedEvent Extension *DescriptorExtension ISO639LanguageAndAudioType *DescriptorISO639LanguageAndAudioType Length uint8 LocalTimeOffset *DescriptorLocalTimeOffset MaximumBitrate *DescriptorMaximumBitrate NetworkName *DescriptorNetworkName ParentalRating *DescriptorParentalRating PrivateDataIndicator *DescriptorPrivateDataIndicator PrivateDataSpecifier *DescriptorPrivateDataSpecifier Registration *DescriptorRegistration Service *DescriptorService ShortEvent *DescriptorShortEvent StreamIdentifier *DescriptorStreamIdentifier Subtitling *DescriptorSubtitling Tag uint8 // the tag defines the structure of the contained data following the descriptor length. Teletext *DescriptorTeletext Unknown *DescriptorUnknown UserDefined []byte VBIData *DescriptorVBIData VBITeletext *DescriptorTeletext } // DescriptorAC3 represents an AC3 descriptor // Chapter: Annex D | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorAC3 struct { AdditionalInfo []byte ASVC uint8 BSID uint8 ComponentType uint8 HasASVC bool HasBSID bool HasComponentType bool HasMainID bool MainID uint8 } func newDescriptorAC3(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorAC3, err error) { // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Create descriptor d = &DescriptorAC3{ HasASVC: uint8(b&0x10) > 0, HasBSID: uint8(b&0x40) > 0, HasComponentType: uint8(b&0x80) > 0, HasMainID: uint8(b&0x20) > 0, } // Component type if d.HasComponentType { if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.ComponentType = uint8(b) } // BSID if d.HasBSID { if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.BSID = uint8(b) } // Main ID if d.HasMainID { if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.MainID = uint8(b) } // ASVC if d.HasASVC { if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.ASVC = uint8(b) } // Additional info if i.Offset() < offsetEnd { if d.AdditionalInfo, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } } return } // DescriptorAVCVideo represents an AVC video descriptor // No doc found unfortunately, basing the implementation on https://github.com/gfto/bitstream/blob/master/mpeg/psi/desc_28.h type DescriptorAVCVideo struct { AVC24HourPictureFlag bool AVCStillPresent bool CompatibleFlags uint8 ConstraintSet0Flag bool ConstraintSet1Flag bool ConstraintSet2Flag bool LevelIDC uint8 ProfileIDC uint8 } func newDescriptorAVCVideo(i *astikit.BytesIterator) (d *DescriptorAVCVideo, err error) { // Init d = &DescriptorAVCVideo{} // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Profile idc d.ProfileIDC = uint8(b) // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Flags d.ConstraintSet0Flag = b&0x80 > 0 d.ConstraintSet1Flag = b&0x40 > 0 d.ConstraintSet2Flag = b&0x20 > 0 d.CompatibleFlags = b & 0x1f // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Level idc d.LevelIDC = uint8(b) // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // AVC still present d.AVCStillPresent = b&0x80 > 0 // AVC 24 hour picture flag d.AVC24HourPictureFlag = b&0x40 > 0 return } // DescriptorComponent represents a component descriptor // Chapter: 6.2.8 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorComponent struct { ComponentTag uint8 ComponentType uint8 ISO639LanguageCode []byte StreamContent uint8 StreamContentExt uint8 Text []byte } func newDescriptorComponent(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorComponent, err error) { // Init d = &DescriptorComponent{} // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Stream content ext d.StreamContentExt = uint8(b >> 4) // Stream content d.StreamContent = uint8(b & 0xf) // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Component type d.ComponentType = uint8(b) // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Component tag d.ComponentTag = uint8(b) // ISO639 language code if d.ISO639LanguageCode, err = i.NextBytes(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Text if i.Offset() < offsetEnd { if d.Text, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } } return } // DescriptorContent represents a content descriptor // Chapter: 6.2.9 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorContent struct { Items []*DescriptorContentItem } // DescriptorContentItem represents a content item descriptor // Chapter: 6.2.9 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorContentItem struct { ContentNibbleLevel1 uint8 ContentNibbleLevel2 uint8 UserByte uint8 } func newDescriptorContent(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorContent, err error) { // Init d = &DescriptorContent{} // Add items for i.Offset() < offsetEnd { // Get next bytes var bs []byte if bs, err = i.NextBytesNoCopy(2); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Append item d.Items = append(d.Items, &DescriptorContentItem{ ContentNibbleLevel1: uint8(bs[0] >> 4), ContentNibbleLevel2: uint8(bs[0] & 0xf), UserByte: uint8(bs[1]), }) } return } // DescriptorDataStreamAlignment represents a data stream alignment descriptor type DescriptorDataStreamAlignment struct { Type uint8 } func newDescriptorDataStreamAlignment(i *astikit.BytesIterator) (d *DescriptorDataStreamAlignment, err error) { var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d = &DescriptorDataStreamAlignment{Type: uint8(b)} return } // DescriptorEnhancedAC3 represents an enhanced AC3 descriptor // Chapter: Annex D | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorEnhancedAC3 struct { AdditionalInfo []byte ASVC uint8 BSID uint8 ComponentType uint8 HasASVC bool HasBSID bool HasComponentType bool HasMainID bool HasSubStream1 bool HasSubStream2 bool HasSubStream3 bool MainID uint8 MixInfoExists bool SubStream1 uint8 SubStream2 uint8 SubStream3 uint8 } func newDescriptorEnhancedAC3(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorEnhancedAC3, err error) { // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Create descriptor d = &DescriptorEnhancedAC3{ HasASVC: uint8(b&0x10) > 0, HasBSID: uint8(b&0x40) > 0, HasComponentType: uint8(b&0x80) > 0, HasMainID: uint8(b&0x20) > 0, HasSubStream1: uint8(b&0x4) > 0, HasSubStream2: uint8(b&0x2) > 0, HasSubStream3: uint8(b&0x1) > 0, MixInfoExists: uint8(b&0x8) > 0, } // Component type if d.HasComponentType { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.ComponentType = uint8(b) } // BSID if d.HasBSID { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.BSID = uint8(b) } // Main ID if d.HasMainID { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.MainID = uint8(b) } // ASVC if d.HasASVC { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.ASVC = uint8(b) } // Substream 1 if d.HasSubStream1 { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.SubStream1 = uint8(b) } // Substream 2 if d.HasSubStream2 { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.SubStream2 = uint8(b) } // Substream 3 if d.HasSubStream3 { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d.SubStream3 = uint8(b) } // Additional info if i.Offset() < offsetEnd { if d.AdditionalInfo, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } } return } // DescriptorExtendedEvent represents an extended event descriptor // Chapter: 6.2.15 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorExtendedEvent struct { ISO639LanguageCode []byte Items []*DescriptorExtendedEventItem LastDescriptorNumber uint8 Number uint8 Text []byte } // DescriptorExtendedEventItem represents an extended event item descriptor // Chapter: 6.2.15 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorExtendedEventItem struct { Content []byte Description []byte } func newDescriptorExtendedEvent(i *astikit.BytesIterator) (d *DescriptorExtendedEvent, err error) { // Init d = &DescriptorExtendedEvent{} // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Number d.Number = uint8(b >> 4) // Last descriptor number d.LastDescriptorNumber = uint8(b & 0xf) // ISO639 language code if d.ISO639LanguageCode, err = i.NextBytes(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Items length itemsLength := int(b) // Items offsetEnd := i.Offset() + itemsLength for i.Offset() < offsetEnd { // Create item var item *DescriptorExtendedEventItem if item, err = newDescriptorExtendedEventItem(i); err != nil { err = fmt.Errorf("astits: creating extended event item failed: %w", err) return } // Append item d.Items = append(d.Items, item) } // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Text length textLength := int(b) // Text if d.Text, err = i.NextBytes(textLength); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } return } func newDescriptorExtendedEventItem(i *astikit.BytesIterator) (d *DescriptorExtendedEventItem, err error) { // Init d = &DescriptorExtendedEventItem{} // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Description length descriptionLength := int(b) // Description if d.Description, err = i.NextBytes(descriptionLength); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Content length contentLength := int(b) // Content if d.Content, err = i.NextBytes(contentLength); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } return } // DescriptorExtension represents an extension descriptor // Chapter: 6.2.16 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorExtension struct { SupplementaryAudio *DescriptorExtensionSupplementaryAudio Tag uint8 Unknown *[]byte } func newDescriptorExtension(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorExtension, err error) { // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Create descriptor d = &DescriptorExtension{Tag: uint8(b)} // Switch on tag switch d.Tag { case DescriptorTagExtensionSupplementaryAudio: if d.SupplementaryAudio, err = newDescriptorExtensionSupplementaryAudio(i, offsetEnd); err != nil { err = fmt.Errorf("astits: parsing extension supplementary audio descriptor failed: %w", err) return } default: // Get next bytes var b []byte if b, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Update unknown d.Unknown = &b } return } // DescriptorExtensionSupplementaryAudio represents a supplementary audio extension descriptor // Chapter: 6.4.10 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorExtensionSupplementaryAudio struct { EditorialClassification uint8 HasLanguageCode bool LanguageCode []byte MixType bool PrivateData []byte } func newDescriptorExtensionSupplementaryAudio(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorExtensionSupplementaryAudio, err error) { // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Init d = &DescriptorExtensionSupplementaryAudio{ EditorialClassification: uint8(b >> 2 & 0x1f), HasLanguageCode: b&0x1 > 0, MixType: b&0x80 > 0, } // Language code if d.HasLanguageCode { if d.LanguageCode, err = i.NextBytes(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } } // Private data if i.Offset() < offsetEnd { if d.PrivateData, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } } return } // DescriptorISO639LanguageAndAudioType represents an ISO639 language descriptor // https://github.com/gfto/bitstream/blob/master/mpeg/psi/desc_0a.h // FIXME (barbashov) according to Chapter 2.6.18 ISO/IEC 13818-1:2015 there could be not one, but multiple such descriptors type DescriptorISO639LanguageAndAudioType struct { Language []byte Type uint8 } // In some actual cases, the length is 3 and the language is described in only 2 bytes func newDescriptorISO639LanguageAndAudioType(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorISO639LanguageAndAudioType, err error) { // Get next bytes var bs []byte if bs, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Create descriptor d = &DescriptorISO639LanguageAndAudioType{ Language: bs[0 : len(bs)-1], Type: uint8(bs[len(bs)-1]), } return } // DescriptorLocalTimeOffset represents a local time offset descriptor // Chapter: 6.2.20 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorLocalTimeOffset struct { Items []*DescriptorLocalTimeOffsetItem } // DescriptorLocalTimeOffsetItem represents a local time offset item descriptor // Chapter: 6.2.20 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorLocalTimeOffsetItem struct { CountryCode []byte CountryRegionID uint8 LocalTimeOffset time.Duration LocalTimeOffsetPolarity bool NextTimeOffset time.Duration TimeOfChange time.Time } func newDescriptorLocalTimeOffset(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorLocalTimeOffset, err error) { // Init d = &DescriptorLocalTimeOffset{} // Add items for i.Offset() < offsetEnd { // Create item itm := &DescriptorLocalTimeOffsetItem{} // Country code if itm.CountryCode, err = i.NextBytes(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Country region ID itm.CountryRegionID = uint8(b >> 2) // Local time offset polarity itm.LocalTimeOffsetPolarity = b&0x1 > 0 // Local time offset if itm.LocalTimeOffset, err = parseDVBDurationMinutes(i); err != nil { err = fmt.Errorf("astits: parsing DVB durationminutes failed: %w", err) return } // Time of change if itm.TimeOfChange, err = parseDVBTime(i); err != nil { err = fmt.Errorf("astits: parsing DVB time failed: %w", err) return } // Next time offset if itm.NextTimeOffset, err = parseDVBDurationMinutes(i); err != nil { err = fmt.Errorf("astits: parsing DVB duration minutes failed: %w", err) return } // Append item d.Items = append(d.Items, itm) } return } // DescriptorMaximumBitrate represents a maximum bitrate descriptor type DescriptorMaximumBitrate struct { Bitrate uint32 // In bytes/second } func newDescriptorMaximumBitrate(i *astikit.BytesIterator) (d *DescriptorMaximumBitrate, err error) { // Get next bytes var bs []byte if bs, err = i.NextBytesNoCopy(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Create descriptor d = &DescriptorMaximumBitrate{Bitrate: (uint32(bs[0]&0x3f)<<16 | uint32(bs[1])<<8 | uint32(bs[2])) * 50} return } // DescriptorNetworkName represents a network name descriptor // Chapter: 6.2.27 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorNetworkName struct { Name []byte } func newDescriptorNetworkName(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorNetworkName, err error) { // Create descriptor d = &DescriptorNetworkName{} // Name if d.Name, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } return } // DescriptorParentalRating represents a parental rating descriptor // Chapter: 6.2.28 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorParentalRating struct { Items []*DescriptorParentalRatingItem } // DescriptorParentalRatingItem represents a parental rating item descriptor // Chapter: 6.2.28 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorParentalRatingItem struct { CountryCode []byte Rating uint8 } // MinimumAge returns the minimum age for the parental rating func (d DescriptorParentalRatingItem) MinimumAge() int { // Undefined or user defined ratings if d.Rating == 0 || d.Rating > 0x10 { return 0 } return int(d.Rating) + 3 } func newDescriptorParentalRating(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorParentalRating, err error) { // Create descriptor d = &DescriptorParentalRating{} // Add items for i.Offset() < offsetEnd { // Get next bytes var bs []byte if bs, err = i.NextBytes(4); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Append item d.Items = append(d.Items, &DescriptorParentalRatingItem{ CountryCode: bs[:3], Rating: uint8(bs[3]), }) } return } // DescriptorPrivateDataIndicator represents a private data Indicator descriptor type DescriptorPrivateDataIndicator struct { Indicator uint32 } func newDescriptorPrivateDataIndicator(i *astikit.BytesIterator) (d *DescriptorPrivateDataIndicator, err error) { // Get next bytes var bs []byte if bs, err = i.NextBytesNoCopy(4); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Create descriptor d = &DescriptorPrivateDataIndicator{Indicator: uint32(bs[0])<<24 | uint32(bs[1])<<16 | uint32(bs[2])<<8 | uint32(bs[3])} return } // DescriptorPrivateDataSpecifier represents a private data specifier descriptor type DescriptorPrivateDataSpecifier struct { Specifier uint32 } func newDescriptorPrivateDataSpecifier(i *astikit.BytesIterator) (d *DescriptorPrivateDataSpecifier, err error) { // Get next bytes var bs []byte if bs, err = i.NextBytesNoCopy(4); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Create descriptor d = &DescriptorPrivateDataSpecifier{Specifier: uint32(bs[0])<<24 | uint32(bs[1])<<16 | uint32(bs[2])<<8 | uint32(bs[3])} return } // DescriptorRegistration represents a registration descriptor // Page: 84 | http://ecee.colorado.edu/~ecen5653/ecen5653/papers/iso13818-1.pdf type DescriptorRegistration struct { AdditionalIdentificationInfo []byte FormatIdentifier uint32 } func newDescriptorRegistration(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorRegistration, err error) { // Get next bytes var bs []byte if bs, err = i.NextBytesNoCopy(4); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Create descriptor d = &DescriptorRegistration{FormatIdentifier: uint32(bs[0])<<24 | uint32(bs[1])<<16 | uint32(bs[2])<<8 | uint32(bs[3])} // Additional identification info if i.Offset() < offsetEnd { if d.AdditionalIdentificationInfo, err = i.NextBytes(offsetEnd - i.Offset()); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } } return } // DescriptorService represents a service descriptor // Chapter: 6.2.33 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorService struct { Name []byte Provider []byte Type uint8 } func newDescriptorService(i *astikit.BytesIterator) (d *DescriptorService, err error) { // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Create descriptor d = &DescriptorService{Type: uint8(b)} // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Provider length providerLength := int(b) // Provider if d.Provider, err = i.NextBytes(providerLength); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Name length nameLength := int(b) // Name if d.Name, err = i.NextBytes(nameLength); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } return } // DescriptorShortEvent represents a short event descriptor // Chapter: 6.2.37 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorShortEvent struct { EventName []byte Language []byte Text []byte } func newDescriptorShortEvent(i *astikit.BytesIterator) (d *DescriptorShortEvent, err error) { // Create descriptor d = &DescriptorShortEvent{} // Language if d.Language, err = i.NextBytes(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Event length eventLength := int(b) // Event name if d.EventName, err = i.NextBytes(eventLength); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Text length textLength := int(b) // Text if d.Text, err = i.NextBytes(textLength); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } return } // DescriptorStreamIdentifier represents a stream identifier descriptor // Chapter: 6.2.39 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorStreamIdentifier struct { ComponentTag uint8 } func newDescriptorStreamIdentifier(i *astikit.BytesIterator) (d *DescriptorStreamIdentifier, err error) { var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } d = &DescriptorStreamIdentifier{ComponentTag: uint8(b)} return } // DescriptorSubtitling represents a subtitling descriptor // Chapter: 6.2.41 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorSubtitling struct { Items []*DescriptorSubtitlingItem } // DescriptorSubtitlingItem represents subtitling descriptor item // Chapter: 6.2.41 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorSubtitlingItem struct { AncillaryPageID uint16 CompositionPageID uint16 Language []byte Type uint8 } func newDescriptorSubtitling(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorSubtitling, err error) { // Create descriptor d = &DescriptorSubtitling{} // Loop for i.Offset() < offsetEnd { // Create item itm := &DescriptorSubtitlingItem{} // Language if itm.Language, err = i.NextBytes(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Type itm.Type = uint8(b) // Get next bytes var bs []byte if bs, err = i.NextBytesNoCopy(2); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Composition page ID itm.CompositionPageID = uint16(bs[0])<<8 | uint16(bs[1]) // Get next bytes if bs, err = i.NextBytesNoCopy(2); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Ancillary page ID itm.AncillaryPageID = uint16(bs[0])<<8 | uint16(bs[1]) // Append item d.Items = append(d.Items, itm) } return } // DescriptorTeletext represents a teletext descriptor // Chapter: 6.2.43 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorTeletext struct { Items []*DescriptorTeletextItem } // DescriptorTeletextItem represents a teletext descriptor item // Chapter: 6.2.43 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorTeletextItem struct { Language []byte Magazine uint8 Page uint8 Type uint8 } func newDescriptorTeletext(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorTeletext, err error) { // Create descriptor d = &DescriptorTeletext{} // Loop for i.Offset() < offsetEnd { // Create item itm := &DescriptorTeletextItem{} // Language if itm.Language, err = i.NextBytes(3); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Type itm.Type = uint8(b) >> 3 // Magazine itm.Magazine = uint8(b & 0x7) // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Page itm.Page = uint8(b)>>4*10 + uint8(b&0xf) // Append item d.Items = append(d.Items, itm) } return } type DescriptorUnknown struct { Content []byte Tag uint8 } func newDescriptorUnknown(i *astikit.BytesIterator, tag, length uint8) (d *DescriptorUnknown, err error) { // Create descriptor d = &DescriptorUnknown{Tag: tag} // Get next bytes if d.Content, err = i.NextBytes(int(length)); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } return } // DescriptorVBIData represents a VBI data descriptor // Chapter: 6.2.47 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorVBIData struct { Services []*DescriptorVBIDataService } // DescriptorVBIDataService represents a vbi data service descriptor // Chapter: 6.2.47 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorVBIDataService struct { DataServiceID uint8 Descriptors []*DescriptorVBIDataDescriptor } // DescriptorVBIDataItem represents a vbi data descriptor item // Chapter: 6.2.47 | Link: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.15.01_60/en_300468v011501p.pdf type DescriptorVBIDataDescriptor struct { FieldParity bool LineOffset uint8 } func newDescriptorVBIData(i *astikit.BytesIterator, offsetEnd int) (d *DescriptorVBIData, err error) { // Create descriptor d = &DescriptorVBIData{} // Loop for i.Offset() < offsetEnd { // Create service srv := &DescriptorVBIDataService{} // Get next byte var b byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Data service ID srv.DataServiceID = uint8(b) // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Data service descriptor length dataServiceDescriptorLength := int(b) // Data service descriptor offsetDataEnd := i.Offset() + dataServiceDescriptorLength for i.Offset() < offsetDataEnd { if srv.DataServiceID == VBIDataServiceIDClosedCaptioning || srv.DataServiceID == VBIDataServiceIDEBUTeletext || srv.DataServiceID == VBIDataServiceIDInvertedTeletext || srv.DataServiceID == VBIDataServiceIDMonochrome442Samples || srv.DataServiceID == VBIDataServiceIDVPS || srv.DataServiceID == VBIDataServiceIDWSS { // Get next byte if b, err = i.NextByte(); err != nil { err = fmt.Errorf("astits: fetching next byte failed: %w", err) return } // Append data srv.Descriptors = append(srv.Descriptors, &DescriptorVBIDataDescriptor{ FieldParity: b&0x20 > 0, LineOffset: uint8(b & 0x1f), }) } } // Append service d.Services = append(d.Services, srv) } return } // parseDescriptors parses descriptors func parseDescriptors(i *astikit.BytesIterator) (o []*Descriptor, err error) { // Get next 2 bytes var bs []byte if bs, err = i.NextBytesNoCopy(2); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Get length length := int(uint16(bs[0]&0xf)<<8 | uint16(bs[1])) // Loop if length > 0 { offsetEnd := i.Offset() + length for i.Offset() < offsetEnd { // Get next 2 bytes if bs, err = i.NextBytesNoCopy(2); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } // Create descriptor d := &Descriptor{ Length: uint8(bs[1]), Tag: uint8(bs[0]), } // Parse data if d.Length > 0 { // Unfortunately there's no way to be sure the real descriptor length is the same as the one indicated // previously therefore we must fetch bytes in descriptor functions and seek at the end offsetDescriptorEnd := i.Offset() + int(d.Length) // User defined if d.Tag >= 0x80 && d.Tag <= 0xfe { // Get next bytes if d.UserDefined, err = i.NextBytes(int(d.Length)); err != nil { err = fmt.Errorf("astits: fetching next bytes failed: %w", err) return } } else { // Switch on tag switch d.Tag { case DescriptorTagAC3: if d.AC3, err = newDescriptorAC3(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing AC3 descriptor failed: %w", err) return } case DescriptorTagAVCVideo: if d.AVCVideo, err = newDescriptorAVCVideo(i); err != nil { err = fmt.Errorf("astits: parsing AVC Video descriptor failed: %w", err) return } case DescriptorTagComponent: if d.Component, err = newDescriptorComponent(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Component descriptor failed: %w", err) return } case DescriptorTagContent: if d.Content, err = newDescriptorContent(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Content descriptor failed: %w", err) return } case DescriptorTagDataStreamAlignment: if d.DataStreamAlignment, err = newDescriptorDataStreamAlignment(i); err != nil { err = fmt.Errorf("astits: parsing Data Stream Alignment descriptor failed: %w", err) return } case DescriptorTagEnhancedAC3: if d.EnhancedAC3, err = newDescriptorEnhancedAC3(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Enhanced AC3 descriptor failed: %w", err) return } case DescriptorTagExtendedEvent: if d.ExtendedEvent, err = newDescriptorExtendedEvent(i); err != nil { err = fmt.Errorf("astits: parsing Extended event descriptor failed: %w", err) return } case DescriptorTagExtension: if d.Extension, err = newDescriptorExtension(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Extension descriptor failed: %w", err) return } case DescriptorTagISO639LanguageAndAudioType: if d.ISO639LanguageAndAudioType, err = newDescriptorISO639LanguageAndAudioType(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing ISO639 Language and Audio Type descriptor failed: %w", err) return } case DescriptorTagLocalTimeOffset: if d.LocalTimeOffset, err = newDescriptorLocalTimeOffset(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Local Time Offset descriptor failed: %w", err) return } case DescriptorTagMaximumBitrate: if d.MaximumBitrate, err = newDescriptorMaximumBitrate(i); err != nil { err = fmt.Errorf("astits: parsing Maximum Bitrate descriptor failed: %w", err) return } case DescriptorTagNetworkName: if d.NetworkName, err = newDescriptorNetworkName(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Network Name descriptor failed: %w", err) return } case DescriptorTagParentalRating: if d.ParentalRating, err = newDescriptorParentalRating(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Parental Rating descriptor failed: %w", err) return } case DescriptorTagPrivateDataIndicator: if d.PrivateDataIndicator, err = newDescriptorPrivateDataIndicator(i); err != nil { err = fmt.Errorf("astits: parsing Private Data Indicator descriptor failed: %w", err) return } case DescriptorTagPrivateDataSpecifier: if d.PrivateDataSpecifier, err = newDescriptorPrivateDataSpecifier(i); err != nil { err = fmt.Errorf("astits: parsing Private Data Specifier descriptor failed: %w", err) return } case DescriptorTagRegistration: if d.Registration, err = newDescriptorRegistration(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Registration descriptor failed: %w", err) return } case DescriptorTagService: if d.Service, err = newDescriptorService(i); err != nil { err = fmt.Errorf("astits: parsing Service descriptor failed: %w", err) return } case DescriptorTagShortEvent: if d.ShortEvent, err = newDescriptorShortEvent(i); err != nil { err = fmt.Errorf("astits: parsing Short Event descriptor failed: %w", err) return } case DescriptorTagStreamIdentifier: if d.StreamIdentifier, err = newDescriptorStreamIdentifier(i); err != nil { err = fmt.Errorf("astits: parsing Stream Identifier descriptor failed: %w", err) return } case DescriptorTagSubtitling: if d.Subtitling, err = newDescriptorSubtitling(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Subtitling descriptor failed: %w", err) return } case DescriptorTagTeletext: if d.Teletext, err = newDescriptorTeletext(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing Teletext descriptor failed: %w", err) return } case DescriptorTagVBIData: if d.VBIData, err = newDescriptorVBIData(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing VBI Date descriptor failed: %w", err) return } case DescriptorTagVBITeletext: if d.VBITeletext, err = newDescriptorTeletext(i, offsetDescriptorEnd); err != nil { err = fmt.Errorf("astits: parsing VBI Teletext descriptor failed: %w", err) return } default: if d.Unknown, err = newDescriptorUnknown(i, d.Tag, d.Length); err != nil { err = fmt.Errorf("astits: parsing unknown descriptor failed: %w", err) return } } } // Seek in iterator to make sure we move to the end of the descriptor since its content may be // corrupted i.Seek(offsetDescriptorEnd) } o = append(o, d) } } return } func calcDescriptorUserDefinedLength(d []byte) uint8 { return uint8(len(d)) } func writeDescriptorUserDefined(w *astikit.BitsWriter, d []byte) error { b := astikit.NewBitsWriterBatch(w) b.Write(d) return b.Err() } func calcDescriptorAC3Length(d *DescriptorAC3) uint8 { ret := 1 // flags if d.HasComponentType { ret++ } if d.HasBSID { ret++ } if d.HasMainID { ret++ } if d.HasASVC { ret++ } ret += len(d.AdditionalInfo) return uint8(ret) } func writeDescriptorAC3(w *astikit.BitsWriter, d *DescriptorAC3) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.HasComponentType) b.Write(d.HasBSID) b.Write(d.HasMainID) b.Write(d.HasASVC) b.WriteN(uint8(0xff), 4) if d.HasComponentType { b.Write(d.ComponentType) } if d.HasBSID { b.Write(d.BSID) } if d.HasMainID { b.Write(d.MainID) } if d.HasASVC { b.Write(d.ASVC) } b.Write(d.AdditionalInfo) return b.Err() } func calcDescriptorAVCVideoLength(d *DescriptorAVCVideo) uint8 { return 4 } func writeDescriptorAVCVideo(w *astikit.BitsWriter, d *DescriptorAVCVideo) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.ProfileIDC) b.Write(d.ConstraintSet0Flag) b.Write(d.ConstraintSet1Flag) b.Write(d.ConstraintSet2Flag) b.WriteN(d.CompatibleFlags, 5) b.Write(d.LevelIDC) b.Write(d.AVCStillPresent) b.Write(d.AVC24HourPictureFlag) b.WriteN(uint8(0xff), 6) return b.Err() } func calcDescriptorComponentLength(d *DescriptorComponent) uint8 { return uint8(6 + len(d.Text)) } func writeDescriptorComponent(w *astikit.BitsWriter, d *DescriptorComponent) error { b := astikit.NewBitsWriterBatch(w) b.WriteN(d.StreamContentExt, 4) b.WriteN(d.StreamContent, 4) b.Write(d.ComponentType) b.Write(d.ComponentTag) b.WriteBytesN(d.ISO639LanguageCode, 3, 0) b.Write(d.Text) return b.Err() } func calcDescriptorContentLength(d *DescriptorContent) uint8 { return uint8(2 * len(d.Items)) } func writeDescriptorContent(w *astikit.BitsWriter, d *DescriptorContent) error { b := astikit.NewBitsWriterBatch(w) for _, item := range d.Items { b.WriteN(item.ContentNibbleLevel1, 4) b.WriteN(item.ContentNibbleLevel2, 4) b.Write(item.UserByte) } return b.Err() } func calcDescriptorDataStreamAlignmentLength(d *DescriptorDataStreamAlignment) uint8 { return 1 } func writeDescriptorDataStreamAlignment(w *astikit.BitsWriter, d *DescriptorDataStreamAlignment) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.Type) return b.Err() } func calcDescriptorEnhancedAC3Length(d *DescriptorEnhancedAC3) uint8 { ret := 1 // flags if d.HasComponentType { ret++ } if d.HasBSID { ret++ } if d.HasMainID { ret++ } if d.HasASVC { ret++ } if d.HasSubStream1 { ret++ } if d.HasSubStream2 { ret++ } if d.HasSubStream3 { ret++ } ret += len(d.AdditionalInfo) return uint8(ret) } func writeDescriptorEnhancedAC3(w *astikit.BitsWriter, d *DescriptorEnhancedAC3) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.HasComponentType) b.Write(d.HasBSID) b.Write(d.HasMainID) b.Write(d.HasASVC) b.Write(d.MixInfoExists) b.Write(d.HasSubStream1) b.Write(d.HasSubStream2) b.Write(d.HasSubStream3) if d.HasComponentType { b.Write(d.ComponentType) } if d.HasBSID { b.Write(d.BSID) } if d.HasMainID { b.Write(d.MainID) } if d.HasASVC { b.Write(d.ASVC) } if d.HasSubStream1 { b.Write(d.SubStream1) } if d.HasSubStream2 { b.Write(d.SubStream2) } if d.HasSubStream3 { b.Write(d.SubStream3) } b.Write(d.AdditionalInfo) return b.Err() } func calcDescriptorExtendedEventLength(d *DescriptorExtendedEvent) (descriptorLength, lengthOfItems uint8) { ret := 1 + 3 + 1 // numbers, language and items length itemsRet := 0 for _, item := range d.Items { itemsRet += 1 // description length itemsRet += len(item.Description) itemsRet += 1 // content length itemsRet += len(item.Content) } ret += itemsRet ret += 1 // text length ret += len(d.Text) return uint8(ret), uint8(itemsRet) } func writeDescriptorExtendedEvent(w *astikit.BitsWriter, d *DescriptorExtendedEvent) error { b := astikit.NewBitsWriterBatch(w) var lengthOfItems uint8 _, lengthOfItems = calcDescriptorExtendedEventLength(d) b.WriteN(d.Number, 4) b.WriteN(d.LastDescriptorNumber, 4) b.WriteBytesN(d.ISO639LanguageCode, 3, 0) b.Write(lengthOfItems) for _, item := range d.Items { b.Write(uint8(len(item.Description))) b.Write(item.Description) b.Write(uint8(len(item.Content))) b.Write(item.Content) } b.Write(uint8(len(d.Text))) b.Write(d.Text) return b.Err() } func calcDescriptorExtensionSupplementaryAudioLength(d *DescriptorExtensionSupplementaryAudio) int { ret := 1 if d.HasLanguageCode { ret += 3 } ret += len(d.PrivateData) return ret } func calcDescriptorExtensionLength(d *DescriptorExtension) uint8 { ret := 1 // tag switch d.Tag { case DescriptorTagExtensionSupplementaryAudio: ret += calcDescriptorExtensionSupplementaryAudioLength(d.SupplementaryAudio) default: if d.Unknown != nil { ret += len(*d.Unknown) } } return uint8(ret) } func writeDescriptorExtensionSupplementaryAudio(w *astikit.BitsWriter, d *DescriptorExtensionSupplementaryAudio) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.MixType) b.WriteN(d.EditorialClassification, 5) b.Write(true) // reserved b.Write(d.HasLanguageCode) if d.HasLanguageCode { b.WriteBytesN(d.LanguageCode, 3, 0) } b.Write(d.PrivateData) return b.Err() } func writeDescriptorExtension(w *astikit.BitsWriter, d *DescriptorExtension) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.Tag) switch d.Tag { case DescriptorTagExtensionSupplementaryAudio: err := writeDescriptorExtensionSupplementaryAudio(w, d.SupplementaryAudio) if err != nil { return err } default: if d.Unknown != nil { b.Write(*d.Unknown) } } return b.Err() } func calcDescriptorISO639LanguageAndAudioTypeLength(d *DescriptorISO639LanguageAndAudioType) uint8 { return 3 + 1 // language code + type } func writeDescriptorISO639LanguageAndAudioType(w *astikit.BitsWriter, d *DescriptorISO639LanguageAndAudioType) error { b := astikit.NewBitsWriterBatch(w) b.WriteBytesN(d.Language, 3, 0) b.Write(d.Type) return b.Err() } func calcDescriptorLocalTimeOffsetLength(d *DescriptorLocalTimeOffset) uint8 { return uint8(13 * len(d.Items)) } func writeDescriptorLocalTimeOffset(w *astikit.BitsWriter, d *DescriptorLocalTimeOffset) error { b := astikit.NewBitsWriterBatch(w) for _, item := range d.Items { b.WriteBytesN(item.CountryCode, 3, 0) b.WriteN(item.CountryRegionID, 6) b.WriteN(uint8(0xff), 1) b.Write(item.LocalTimeOffsetPolarity) if _, err := writeDVBDurationMinutes(w, item.LocalTimeOffset); err != nil { return err } if _, err := writeDVBTime(w, item.TimeOfChange); err != nil { return err } if _, err := writeDVBDurationMinutes(w, item.NextTimeOffset); err != nil { return err } } return b.Err() } func calcDescriptorMaximumBitrateLength(d *DescriptorMaximumBitrate) uint8 { return 3 } func writeDescriptorMaximumBitrate(w *astikit.BitsWriter, d *DescriptorMaximumBitrate) error { b := astikit.NewBitsWriterBatch(w) b.WriteN(uint8(0xff), 2) b.WriteN(uint32(d.Bitrate/50), 22) return b.Err() } func calcDescriptorNetworkNameLength(d *DescriptorNetworkName) uint8 { return uint8(len(d.Name)) } func writeDescriptorNetworkName(w *astikit.BitsWriter, d *DescriptorNetworkName) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.Name) return b.Err() } func calcDescriptorParentalRatingLength(d *DescriptorParentalRating) uint8 { return uint8(4 * len(d.Items)) } func writeDescriptorParentalRating(w *astikit.BitsWriter, d *DescriptorParentalRating) error { b := astikit.NewBitsWriterBatch(w) for _, item := range d.Items { b.WriteBytesN(item.CountryCode, 3, 0) b.Write(item.Rating) } return b.Err() } func calcDescriptorPrivateDataIndicatorLength(d *DescriptorPrivateDataIndicator) uint8 { return 4 } func writeDescriptorPrivateDataIndicator(w *astikit.BitsWriter, d *DescriptorPrivateDataIndicator) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.Indicator) return b.Err() } func calcDescriptorPrivateDataSpecifierLength(d *DescriptorPrivateDataSpecifier) uint8 { return 4 } func writeDescriptorPrivateDataSpecifier(w *astikit.BitsWriter, d *DescriptorPrivateDataSpecifier) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.Specifier) return b.Err() } func calcDescriptorRegistrationLength(d *DescriptorRegistration) uint8 { return uint8(4 + len(d.AdditionalIdentificationInfo)) } func writeDescriptorRegistration(w *astikit.BitsWriter, d *DescriptorRegistration) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.FormatIdentifier) b.Write(d.AdditionalIdentificationInfo) return b.Err() } func calcDescriptorServiceLength(d *DescriptorService) uint8 { ret := 3 // type and lengths ret += len(d.Name) ret += len(d.Provider) return uint8(ret) } func writeDescriptorService(w *astikit.BitsWriter, d *DescriptorService) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.Type) b.Write(uint8(len(d.Provider))) b.Write(d.Provider) b.Write(uint8(len(d.Name))) b.Write(d.Name) return b.Err() } func calcDescriptorShortEventLength(d *DescriptorShortEvent) uint8 { ret := 3 + 1 + 1 // language code and lengths ret += len(d.EventName) ret += len(d.Text) return uint8(ret) } func writeDescriptorShortEvent(w *astikit.BitsWriter, d *DescriptorShortEvent) error { b := astikit.NewBitsWriterBatch(w) b.WriteBytesN(d.Language, 3, 0) b.Write(uint8(len(d.EventName))) b.Write(d.EventName) b.Write(uint8(len(d.Text))) b.Write(d.Text) return b.Err() } func calcDescriptorStreamIdentifierLength(d *DescriptorStreamIdentifier) uint8 { return 1 } func writeDescriptorStreamIdentifier(w *astikit.BitsWriter, d *DescriptorStreamIdentifier) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.ComponentTag) return b.Err() } func calcDescriptorSubtitlingLength(d *DescriptorSubtitling) uint8 { return uint8(8 * len(d.Items)) } func writeDescriptorSubtitling(w *astikit.BitsWriter, d *DescriptorSubtitling) error { b := astikit.NewBitsWriterBatch(w) for _, item := range d.Items { b.WriteBytesN(item.Language, 3, 0) b.Write(item.Type) b.Write(item.CompositionPageID) b.Write(item.AncillaryPageID) } return b.Err() } func calcDescriptorTeletextLength(d *DescriptorTeletext) uint8 { return uint8(5 * len(d.Items)) } func writeDescriptorTeletext(w *astikit.BitsWriter, d *DescriptorTeletext) error { b := astikit.NewBitsWriterBatch(w) for _, item := range d.Items { b.WriteBytesN(item.Language, 3, 0) b.WriteN(item.Type, 5) b.WriteN(item.Magazine, 3) b.WriteN(item.Page/10, 4) b.WriteN(item.Page%10, 4) } return b.Err() } func calcDescriptorVBIDataLength(d *DescriptorVBIData) uint8 { return uint8(3 * len(d.Services)) } func writeDescriptorVBIData(w *astikit.BitsWriter, d *DescriptorVBIData) error { b := astikit.NewBitsWriterBatch(w) for _, item := range d.Services { b.Write(item.DataServiceID) if item.DataServiceID == VBIDataServiceIDClosedCaptioning || item.DataServiceID == VBIDataServiceIDEBUTeletext || item.DataServiceID == VBIDataServiceIDInvertedTeletext || item.DataServiceID == VBIDataServiceIDMonochrome442Samples || item.DataServiceID == VBIDataServiceIDVPS || item.DataServiceID == VBIDataServiceIDWSS { b.Write(uint8(len(item.Descriptors))) // each descriptor is 1 byte for _, desc := range item.Descriptors { b.WriteN(uint8(0xff), 2) b.Write(desc.FieldParity) b.WriteN(desc.LineOffset, 5) } } else { // let's put one reserved byte b.Write(uint8(1)) b.Write(uint8(0xff)) } } return b.Err() } func calcDescriptorUnknownLength(d *DescriptorUnknown) uint8 { return uint8(len(d.Content)) } func writeDescriptorUnknown(w *astikit.BitsWriter, d *DescriptorUnknown) error { b := astikit.NewBitsWriterBatch(w) b.Write(d.Content) return b.Err() } func calcDescriptorLength(d *Descriptor) uint8 { if d.Tag >= 0x80 && d.Tag <= 0xfe { return calcDescriptorUserDefinedLength(d.UserDefined) } switch d.Tag { case DescriptorTagAC3: return calcDescriptorAC3Length(d.AC3) case DescriptorTagAVCVideo: return calcDescriptorAVCVideoLength(d.AVCVideo) case DescriptorTagComponent: return calcDescriptorComponentLength(d.Component) case DescriptorTagContent: return calcDescriptorContentLength(d.Content) case DescriptorTagDataStreamAlignment: return calcDescriptorDataStreamAlignmentLength(d.DataStreamAlignment) case DescriptorTagEnhancedAC3: return calcDescriptorEnhancedAC3Length(d.EnhancedAC3) case DescriptorTagExtendedEvent: ret, _ := calcDescriptorExtendedEventLength(d.ExtendedEvent) return ret case DescriptorTagExtension: return calcDescriptorExtensionLength(d.Extension) case DescriptorTagISO639LanguageAndAudioType: return calcDescriptorISO639LanguageAndAudioTypeLength(d.ISO639LanguageAndAudioType) case DescriptorTagLocalTimeOffset: return calcDescriptorLocalTimeOffsetLength(d.LocalTimeOffset) case DescriptorTagMaximumBitrate: return calcDescriptorMaximumBitrateLength(d.MaximumBitrate) case DescriptorTagNetworkName: return calcDescriptorNetworkNameLength(d.NetworkName) case DescriptorTagParentalRating: return calcDescriptorParentalRatingLength(d.ParentalRating) case DescriptorTagPrivateDataIndicator: return calcDescriptorPrivateDataIndicatorLength(d.PrivateDataIndicator) case DescriptorTagPrivateDataSpecifier: return calcDescriptorPrivateDataSpecifierLength(d.PrivateDataSpecifier) case DescriptorTagRegistration: return calcDescriptorRegistrationLength(d.Registration) case DescriptorTagService: return calcDescriptorServiceLength(d.Service) case DescriptorTagShortEvent: return calcDescriptorShortEventLength(d.ShortEvent) case DescriptorTagStreamIdentifier: return calcDescriptorStreamIdentifierLength(d.StreamIdentifier) case DescriptorTagSubtitling: return calcDescriptorSubtitlingLength(d.Subtitling) case DescriptorTagTeletext: return calcDescriptorTeletextLength(d.Teletext) case DescriptorTagVBIData: return calcDescriptorVBIDataLength(d.VBIData) case DescriptorTagVBITeletext: return calcDescriptorTeletextLength(d.VBITeletext) } return calcDescriptorUnknownLength(d.Unknown) } func writeDescriptor(w *astikit.BitsWriter, d *Descriptor) (int, error) { b := astikit.NewBitsWriterBatch(w) length := calcDescriptorLength(d) b.Write(d.Tag) b.Write(length) if err := b.Err(); err != nil { return 0, err } written := int(length) + 2 if d.Tag >= 0x80 && d.Tag <= 0xfe { return written, writeDescriptorUserDefined(w, d.UserDefined) } switch d.Tag { case DescriptorTagAC3: return written, writeDescriptorAC3(w, d.AC3) case DescriptorTagAVCVideo: return written, writeDescriptorAVCVideo(w, d.AVCVideo) case DescriptorTagComponent: return written, writeDescriptorComponent(w, d.Component) case DescriptorTagContent: return written, writeDescriptorContent(w, d.Content) case DescriptorTagDataStreamAlignment: return written, writeDescriptorDataStreamAlignment(w, d.DataStreamAlignment) case DescriptorTagEnhancedAC3: return written, writeDescriptorEnhancedAC3(w, d.EnhancedAC3) case DescriptorTagExtendedEvent: return written, writeDescriptorExtendedEvent(w, d.ExtendedEvent) case DescriptorTagExtension: return written, writeDescriptorExtension(w, d.Extension) case DescriptorTagISO639LanguageAndAudioType: return written, writeDescriptorISO639LanguageAndAudioType(w, d.ISO639LanguageAndAudioType) case DescriptorTagLocalTimeOffset: return written, writeDescriptorLocalTimeOffset(w, d.LocalTimeOffset) case DescriptorTagMaximumBitrate: return written, writeDescriptorMaximumBitrate(w, d.MaximumBitrate) case DescriptorTagNetworkName: return written, writeDescriptorNetworkName(w, d.NetworkName) case DescriptorTagParentalRating: return written, writeDescriptorParentalRating(w, d.ParentalRating) case DescriptorTagPrivateDataIndicator: return written, writeDescriptorPrivateDataIndicator(w, d.PrivateDataIndicator) case DescriptorTagPrivateDataSpecifier: return written, writeDescriptorPrivateDataSpecifier(w, d.PrivateDataSpecifier) case DescriptorTagRegistration: return written, writeDescriptorRegistration(w, d.Registration) case DescriptorTagService: return written, writeDescriptorService(w, d.Service) case DescriptorTagShortEvent: return written, writeDescriptorShortEvent(w, d.ShortEvent) case DescriptorTagStreamIdentifier: return written, writeDescriptorStreamIdentifier(w, d.StreamIdentifier) case DescriptorTagSubtitling: return written, writeDescriptorSubtitling(w, d.Subtitling) case DescriptorTagTeletext: return written, writeDescriptorTeletext(w, d.Teletext) case DescriptorTagVBIData: return written, writeDescriptorVBIData(w, d.VBIData) case DescriptorTagVBITeletext: return written, writeDescriptorTeletext(w, d.VBITeletext) } return written, writeDescriptorUnknown(w, d.Unknown) } func calcDescriptorsLength(ds []*Descriptor) uint16 { length := uint16(0) for _, d := range ds { length += 2 // tag and length length += uint16(calcDescriptorLength(d)) } return length } func writeDescriptors(w *astikit.BitsWriter, ds []*Descriptor) (int, error) { written := 0 for _, d := range ds { n, err := writeDescriptor(w, d) if err != nil { return 0, err } written += n } return written, nil } func writeDescriptorsWithLength(w *astikit.BitsWriter, ds []*Descriptor) (int, error) { length := calcDescriptorsLength(ds) b := astikit.NewBitsWriterBatch(w) b.WriteN(uint8(0xff), 4) // reserved b.WriteN(length, 12) // program_info_length if err := b.Err(); err != nil { return 0, err } written, err := writeDescriptors(w, ds) return written + 2, err // 2 for length }