/// <summary>
        /// Parse an PCS packet which contains width/height info
        /// </summary>
        /// <param name="segment">object containing info about the current segment</param>
        /// <param name="pic">SubPicture object containing info about the current caption</param>
        /// <param name="msg">reference to message string</param>
        /// <param name="buffer">Raw data buffer, starting right after segment</param>
        private static void ParsePcs(SupSegment segment, BluRaySupPicture pic, string[] msg, byte[] buffer)
        {
            if (segment.Size >= 4)
            {
                pic.Width  = BigEndianInt16(buffer, 0); // video_width
                pic.Height = BigEndianInt16(buffer, 2); // video_height
                int type = buffer[4];                   // hi nibble: frame_rate, lo nibble: reserved
                int num  = BigEndianInt16(buffer, 5);   // composition_number
                // skipped:
                // 8bit  composition_state: 0x00: normal,       0x40: acquisition point
                //                          0x80: epoch start,  0xC0: epoch continue, 6bit reserved
                // 8bit  palette_update_flag (0x80), 7bit reserved
                int palId = buffer[9];  // 8bit  palette_id_ref
                int coNum = buffer[10]; // 8bit  number_of_composition_objects (0..2)
                if (coNum > 0)
                {
                    // composition_object:
                    int objId = BigEndianInt16(buffer, 11); // 16bit object_id_ref
                    msg[0] = "palID: " + palId + ", objID: " + objId;
                    if (pic.ImageObjects == null)
                    {
                        pic.ImageObjects = new List <ImageObject>();
                    }
                    ImageObject imgObj;
                    if (objId >= pic.ImageObjects.Count)
                    {
                        imgObj = new ImageObject();
                        pic.ImageObjects.Add(imgObj);
                    }
                    else
                    {
                        imgObj = pic.GetImageObject(objId);
                    }
                    imgObj.PaletteId = palId;
                    pic.ObjectId     = objId;

                    // skipped:  8bit  window_id_ref
                    if (segment.Size >= 0x13)
                    {
                        pic.FramesPerSecondType = type;
                        // object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved
                        int forcedCropped = buffer[14];
                        pic.CompositionNumber = num;
                        pic.IsForced          = ((forcedCropped & 0x40) == 0x40);
                        imgObj.XOffset        = BigEndianInt16(buffer, 15); // composition_object_horizontal_position
                        imgObj.YOffset        = BigEndianInt16(buffer, 17); // composition_object_vertical_position
                        // if (object_cropped_flag==1)
                        //      16bit object_cropping_horizontal_position
                        //      16bit object_cropping_vertical_position
                        //      16bit object_cropping_width
                        //      object_cropping_height
                    }
                }
            }
        }
        /// <summary>
        /// parse an ODS packet which contain the image data
        /// </summary>
        /// <param name="buffer">raw byte date, starting right after segment</param>
        /// <param name="segment">object containing info about the current segment</param>
        /// <param name="pic">SubPicture object containing info about the current caption</param>
        /// <param name="msg">reference to message string</param>
        /// <returns>true if this is a valid new object (neither invalid nor a fragment)</returns>
        private static bool ParseOds(byte[] buffer, SupSegment segment, BluRaySupPicture pic, string[] msg)
        {
            ImageObjectFragment info;

            int objId  = BigEndianInt16(buffer, 0); // 16bit object_id
            int objVer = buffer[2];                 // 16bit object_id nikse - index 2 or 1???
            int objSeq = buffer[3];                 // 8bit  first_in_sequence (0x80),
            // last_in_sequence (0x40), 6bits reserved
            bool first = (objSeq & 0x80) == 0x80;
            bool last  = (objSeq & 0x40) == 0x40;

            if (pic.ImageObjects == null)
            {
                pic.ImageObjects = new List <ImageObject>();
            }
            ImageObject imgObj;

            if (objId >= pic.ImageObjects.Count)
            {
                imgObj = new ImageObject();
                pic.ImageObjects.Add(imgObj);
            }
            else
            {
                imgObj = pic.GetImageObject(objId);
            }

            if (imgObj.Fragments == null || first)
            {   // 8bit  object_version_number
                // skipped:
                //  24bit object_data_length - full RLE buffer length (including 4 bytes size info)
                int width  = BigEndianInt16(buffer, 7);     // object_width
                int height = BigEndianInt16(buffer, 9);     // object_height

                if (width <= pic.Width && height <= pic.Height)
                {
                    imgObj.Fragments     = new List <ImageObjectFragment>();
                    info                 = new ImageObjectFragment();
                    info.ImagePacketSize = segment.Size - 11; // Image packet size (image bytes)
                    info.ImageBuffer     = new byte[info.ImagePacketSize];
                    Buffer.BlockCopy(buffer, 11, info.ImageBuffer, 0, info.ImagePacketSize);
                    imgObj.Fragments.Add(info);
                    imgObj.BufferSize = info.ImagePacketSize;
                    imgObj.Height     = height;
                    imgObj.Width      = width;
                    msg[0]            = "ID: " + objId + ", update: " + objVer + ", seq: " + (first ? "first" : "") +
                                        ((first && last) ? "/" : "") + (last ? "" + "last" : "");
                    return(true);
                }
                System.Diagnostics.Debug.Print("Invalid image size - ignored");
                return(false);
            }
            // object_data_fragment
            // skipped:
            //  16bit object_id
            //  8bit  object_version_number
            //  8bit  first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved
            info = new ImageObjectFragment();
            info.ImagePacketSize = segment.Size - 4;
            info.ImageBuffer     = new byte[info.ImagePacketSize];
            Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize);
            imgObj.Fragments.Add(info);
            imgObj.BufferSize += info.ImagePacketSize; // total size (may contain several packets)
            msg[0]             = "ID: " + objId + ", update: " + objVer + ", seq: " + (first ? "first" : "") + ((first && last) ? "/" : "") + (last ? "" + "last" : "");
            return(false);
        }