예제 #1
0
        /// <summary>
        /// parse an PDS packet which contain palette info
        /// </summary>
        /// <param name="buffer">Buffer of raw byte data, 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>number of valid palette entries (-1 for fault)</returns>
        private static int ParsePds(byte[] buffer, SupSegment segment, BluRaySupPicture pic, string[] msg)
        {
            int paletteId = buffer[0];  // 8bit palette ID (0..7)
            // 8bit palette version number (incremented for each palette change)
            int paletteUpdate = buffer[1];

            if (pic.Palettes == null)
            {
                pic.Palettes = new List <List <PaletteInfo> >();
                for (int i = 0; i < 8; i++)
                {
                    pic.Palettes.Add(new List <PaletteInfo>());
                }
            }
            if (paletteId > 7)
            {
                msg[0] = "Illegal palette id at offset " + ToolBox.ToHex(buffer, 0, 8);
                return(-1);
            }
            List <PaletteInfo> al = pic.Palettes[paletteId];

            if (al == null)
            {
                al = new List <PaletteInfo>();
            }
            PaletteInfo p = new PaletteInfo();

            p.PaletteSize   = (segment.Size - 2) / 5;
            p.PaletteBuffer = new byte[p.PaletteSize * 5];
            Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object
            al.Add(p);
            msg[0] = "ID: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries";
            return(p.PaletteSize);
        }
예제 #2
0
        /// <summary>
        /// parse an PDS packet which contain palette info
        /// </summary>
        /// <param name="buffer">Buffer of raw byte data, starting right after segment</param>
        /// <param name="segment">object containing info about the current segment</param>
        /// <returns>number of valid palette entries (-1 for fault)</returns>
        private static PdsData ParsePds(byte[] buffer, SupSegment segment)
        {
            int paletteId = buffer[0];  // 8bit palette ID (0..7)
            // 8bit palette version number (incremented for each palette change)
            int paletteUpdate = buffer[1];

            var p = new PaletteInfo {
                PaletteSize = (segment.Size - 2) / 5
            };

            if (p.PaletteSize <= 0)
            {
                return(new PdsData {
                    Message = "Empty palette"
                });
            }

            p.PaletteBuffer = new byte[p.PaletteSize * 5];
            Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object

            return(new PdsData
            {
                Message = "PalId: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries",
                PaletteId = paletteId,
                PaletteVersion = paletteUpdate,
                PaletteInfo = p,
            });
        }
예제 #3
0
        private static SupSegment ParseSegmentHeaderFromMatroska(byte[] buffer)
        {
            var segment = new SupSegment();

            segment.Type = buffer[0];
            segment.Size = BigEndianInt16(buffer, 1);
            return(segment);
        }
예제 #4
0
        /// <summary>
        /// Matroska bd sup skips first 9 bytes as timecodes are in Matroska structure
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="log"></param>
        /// <returns></returns>
        private static SupSegment ReadSegmentFromMatroska(byte[] buffer, StringBuilder log)
        {
            SupSegment segment = new SupSegment();

//            segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS
//            segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS
            segment.Type = buffer[0];
            segment.Size = BigEndianInt16(buffer, 1);
            return(segment);
        }
예제 #5
0
        /// <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
                    }
                }
            }
        }
예제 #6
0
        private static PcsData ParsePicture(byte[] buffer, SupSegment segment)
        {
            if (buffer.Length < 11)
            {
                return(new PcsData
                {
                    CompositionState = CompositionState.Invalid
                });
            }

            var sb  = new StringBuilder();
            var pcs = new PcsData
            {
                Size = new Size(BigEndianInt16(buffer, 0), BigEndianInt16(buffer, 2)),
                FramesPerSecondType = buffer[4],
                CompNum             = BigEndianInt16(buffer, 5),
                CompositionState    = GetCompositionState(buffer[7]),
                StartTime           = segment.PtsTimestamp,
                PaletteUpdate       = buffer[8] == 0x80,
                PaletteId           = buffer[9]
            };
            // hi nibble: frame_rate, lo nibble: reserved
            // 8bit  palette_update_flag (0x80), 7bit reserved
            // 8bit  palette_id_ref
            int compositionObjectCount = buffer[10];    // 8bit  number_of_composition_objects (0..2)

            sb.AppendFormat("CompNum: {0}, Pts: {1}, State: {2}, PalUpdate: {3}, PalId {4}", pcs.CompNum, ToolBox.PtsToTimeString(pcs.StartTime), pcs.CompositionState, pcs.PaletteUpdate, pcs.PaletteId);

            if (pcs.CompositionState == CompositionState.Invalid)
            {
                sb.Append("Illegal composition state Invalid");
            }
            else
            {
                int offset = 0;
                pcs.PcsObjects = new List <PcsObject>();
                for (int compObjIndex = 0; compObjIndex < compositionObjectCount; compObjIndex++)
                {
                    var pcsObj = ParsePcs(buffer, offset);
                    pcs.PcsObjects.Add(pcsObj);
                    sb.AppendLine();
                    sb.AppendFormat("ObjId: {0}, WinId: {1}, Forced: {2}, X: {3}, Y: {4}",
                                    pcsObj.ObjectId, pcsObj.WindowId, pcsObj.IsForced, pcsObj.Origin.X, pcsObj.Origin.Y);
                    offset += 8;
                }
            }
            pcs.Message = sb.ToString();
            return(pcs);
        }
예제 #7
0
        /// <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 PcsObject ParsePcs(byte[] buffer, SupSegment segment, int offset)
        {
            var pcs = new PcsObject();

            // composition_object:
            pcs.ObjectId = BigEndianInt16(buffer, 11 + offset); // 16bit object_id_ref
            pcs.WindowId = buffer[13 + offset];
            // skipped:  8bit  window_id_ref
            // object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved
            int forcedCropped = buffer[14 + offset];

            pcs.IsForced = ((forcedCropped & 0x40) == 0x40);
            pcs.Origin   = new Point(BigEndianInt16(buffer, 15 + offset), BigEndianInt16(buffer, 17 + offset));
            return(pcs);
        }
예제 #8
0
        /// <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 OdsData ParseOds(byte[] buffer, SupSegment segment, bool forceFirst)
        {
            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) || forceFirst;
            bool last  = (objSeq & 0x40) == 0x40;

            var info = new ImageObjectFragment();

            if (first)
            {
                int width = BigEndianInt16(buffer, 7);    // object_width

                int height = BigEndianInt16(buffer, 9);   // object_height

                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);

                return(new OdsData
                {
                    IsFirst = true,
                    Size = new Size(width, height),
                    ObjectId = objId,
                    ObjectVersion = objVer,
                    Fragment = info,
                    Message = "ObjId: " + objId + ", ver: " + objVer + ", seq: " + (first ? "first" : "") + ((first && last) ? "/" : "") + (last ? "" + "last" : "") + ", width: " + width + ", height: " + height,
                });
            }
            else
            {
                info.ImagePacketSize = segment.Size - 4;
                info.ImageBuffer     = new byte[info.ImagePacketSize];
                Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize);

                return(new OdsData
                {
                    IsFirst = false,
                    ObjectId = objId,
                    ObjectVersion = objVer,
                    Fragment = info,
                    Message = "Continued ObjId: " + objId + ", ver: " + objVer + ", seq: " + (last ? "" + "last" : ""),
                });
            }
        }
예제 #9
0
        private static SupSegment ParseSegmentHeader(byte[] buffer, StringBuilder log)
        {
            var segment = new SupSegment();

            if (buffer[0] == 0x50 && buffer[1] == 0x47)           // 80 + 71 - P G
            {
                segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS
                segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS
                segment.Type         = buffer[10];
                segment.Size         = BigEndianInt16(buffer, 11);
            }
            else
            {
                log.AppendLine("Unable to read segment - PG missing!");
            }
            return(segment);
        }
예제 #10
0
 private static SupSegment ParseSegmentHeaderFromMatroska(byte[] buffer)
 {
     var segment = new SupSegment();
     segment.Type = buffer[0];
     segment.Size = BigEndianInt16(buffer, 1);
     return segment;
 }
예제 #11
0
 private static SupSegment ParseSegmentHeader(byte[] buffer, StringBuilder log)
 {
     var segment = new SupSegment();
     if (buffer[0] == 0x50 && buffer[1] == 0x47) // 80 + 71 - P G
     {
         segment.PtsTimestamp = BigEndianInt32(buffer, 2); // read PTS
         segment.DtsTimestamp = BigEndianInt32(buffer, 6); // read PTS
         segment.Type = buffer[10];
         segment.Size = BigEndianInt16(buffer, 11);
     }
     else
     {
         log.AppendLine("Unable to read segment - PG missing!");
     }
     return segment;
 }
예제 #12
0
        private static PcsData ParsePicture(byte[] buffer, SupSegment segment)
        {
            var sb = new StringBuilder();
            var pcs = new PcsData();
            pcs.Size = new Size(BigEndianInt16(buffer, 0), BigEndianInt16(buffer, 2));
            pcs.FramesPerSecondType = buffer[4];                // hi nibble: frame_rate, lo nibble: reserved
            pcs.CompNum = BigEndianInt16(buffer, 5);
            pcs.CompositionState = GetCompositionState(buffer[7]);
            pcs.StartTime = segment.PtsTimestamp;
            // 8bit  palette_update_flag (0x80), 7bit reserved
            pcs.PaletteUpdate = (buffer[8] == 0x80);
            pcs.PaletteId = buffer[9];  // 8bit  palette_id_ref
            int compositionObjectCount = buffer[10];    // 8bit  number_of_composition_objects (0..2)

            sb.AppendFormat("CompNum: {0}, Pts: {1}, State: {2}, PalUpdate: {3}, PalId {4}", pcs.CompNum, ToolBox.PtsToTimeString(pcs.StartTime), pcs.CompositionState, pcs.PaletteUpdate, pcs.PaletteId);

            if (pcs.CompositionState == CompositionState.Invalid)
            {
                sb.Append("Illegal composition state Invalid");
            }
            else
            {
                int offset = 0;
                pcs.PcsObjects = new List<PcsObject>();
                for (int compObjIndex = 0; compObjIndex < compositionObjectCount; compObjIndex++)
                {
                    PcsObject pcsObj = ParsePcs(buffer, offset);
                    pcs.PcsObjects.Add(pcsObj);
                    sb.AppendLine();
                    sb.AppendFormat("ObjId: {0}, WinId: {1}, Forced: {2}, X: {3}, Y: {4}",
                        pcsObj.ObjectId, pcsObj.WindowId, pcsObj.IsForced, pcsObj.Origin.X, pcsObj.Origin.Y);
                    offset += 8;
                }
            }
            pcs.Message = sb.ToString();
            return pcs;
        }
예제 #13
0
        /// <summary>
        /// parse an PDS packet which contain palette info
        /// </summary>
        /// <param name="buffer">Buffer of raw byte data, starting right after segment</param>
        /// <param name="segment">object containing info about the current segment</param>
        /// <returns>number of valid palette entries (-1 for fault)</returns>
        private static PdsData ParsePds(byte[] buffer, SupSegment segment)
        {
            int paletteId = buffer[0];  // 8bit palette ID (0..7)
            // 8bit palette version number (incremented for each palette change)
            int paletteUpdate = buffer[1];

            var p = new PaletteInfo();
            p.PaletteSize = (segment.Size - 2) / 5;

            if (p.PaletteSize <= 0)
                return new PdsData { Message = "Empty palette" };

            p.PaletteBuffer = new byte[p.PaletteSize * 5];
            Buffer.BlockCopy(buffer, 2, p.PaletteBuffer, 0, p.PaletteSize * 5); // save palette buffer in palette object

            return new PdsData
            {
                Message = "PalId: " + paletteId + ", update: " + paletteUpdate + ", " + p.PaletteSize + " entries",
                PaletteId = paletteId,
                PaletteVersion = paletteUpdate,
                PaletteInfo = p,
            };
        }
예제 #14
0
        /// <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>
        /// <returns>true if this is a valid new object (neither invalid nor a fragment)</returns>
        private static OdsData ParseOds(byte[] buffer, SupSegment segment, bool forceFirst)
        {
            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) || forceFirst;
            bool last = (objSeq & 0x40) == 0x40;

            var info = new ImageObjectFragment();
            if (first)
            {
                int width = BigEndianInt16(buffer, 7);      // object_width
                int height = BigEndianInt16(buffer, 9);     // object_height

                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);

                return new OdsData
                {
                    IsFirst = true,
                    Size = new Size(width, height),
                    ObjectId = objId,
                    ObjectVersion = objVer,
                    Fragment = info,
                    Message = "ObjId: " + objId + ", ver: " + objVer + ", seq: first" + (last ? "/" : "") + (last ? "" + "last" : "") + ", width: " + width + ", height: " + height,
                };
            }
            else
            {
                info.ImagePacketSize = segment.Size - 4;
                info.ImageBuffer = new byte[info.ImagePacketSize];
                Buffer.BlockCopy(buffer, 4, info.ImageBuffer, 0, info.ImagePacketSize);

                return new OdsData
                {
                    IsFirst = false,
                    ObjectId = objId,
                    ObjectVersion = objVer,
                    Fragment = info,
                    Message = "Continued ObjId: " + objId + ", ver: " + objVer + ", seq: " + (last ? "" + "last" : ""),
                };
            }
        }
예제 #15
0
 /// <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 PcsObject ParsePcs(byte[] buffer, SupSegment segment, int offset)
 {
     var pcs = new PcsObject();
     // composition_object:
     pcs.ObjectId = BigEndianInt16(buffer, 11 + offset); // 16bit object_id_ref
     pcs.WindowId = buffer[13 + offset];
     // skipped:  8bit  window_id_ref
     // object_cropped_flag: 0x80, forced_on_flag = 0x040, 6bit reserved
     int forcedCropped = buffer[14 + offset];
     pcs.IsForced = ((forcedCropped & 0x40) == 0x40);
     pcs.Origin = new Point(BigEndianInt16(buffer, 15 + offset), BigEndianInt16(buffer, 17 + offset));
     return pcs;
 }
예제 #16
0
        /// <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);
        }