Exemplo n.º 1
0
        internal VideoParams264(TrackEntry videoTrack)
        {
            // File.WriteAllBytes( @"C:\Temp\2remove\mkv\videoPrivateData.bin", videoTrack.codecPrivate );
            ReadOnlySpan <byte> codecPrivate = videoTrack.codecPrivate.AsSpan();
            int          cbHeader            = Marshal.SizeOf <NativeStruct>();
            NativeStruct ns = codecPrivate.Slice(0, cbHeader).cast <NativeStruct>()[0];

            profile = ns.profileCode;
            profileCompatibility = ns.profileCompatibility;
            levelCode            = ns.levelCode;

            int offset = cbHeader;

            sps = ContainerUtils.copyBlobs(ns.numOfSequenceParameterSets, codecPrivate, ref offset);

            // File.WriteAllBytes( @"C:\Temp\2remove\mkv\sps.bin", sps[ 0 ] );

            int ppsCount = codecPrivate[offset++];

            pps = ContainerUtils.copyBlobs(ppsCount, codecPrivate, ref offset);

            ReadOnlySpan <byte> spsBlob = sps[0].AsSpan();

            if (MiscUtils.getNaluType(spsBlob[0]) != eNaluType.SPS)
            {
                throw new ApplicationException("The SPS is invalid, wrong NALU type");
            }
            spsBlob = spsBlob.Slice(1);

            BitReader spsReader = new BitReader(spsBlob);

            parsedSps = new SequenceParameterSet(ref spsReader);

            chromaFormat   = parsedSps.chromaFormat;
            bitDepthLuma   = parsedSps.bitDepthLuma;
            bitDepthChroma = parsedSps.bitDepthChroma;
            m_decodedSize  = new sDecodedVideoSize(parsedSps.decodedSize, parsedSps.cropRectangle, chromaFormat);
        }
Exemplo n.º 2
0
        public AVC1SampleEntry(Mp4Reader reader, int bytesLeft) :
            base(reader, ref bytesLeft)
        {
            var avcc = reader.readStructure <Structures.AVCDecoderConfigurationRecord>();

            if (avcc.boxType != eAVC1BoxType.avcC)
            {
                throw new NotImplementedException();
            }
            bytesLeft -= decoderConfigSizeof;

            profile = avcc.profileCode;
            profileCompatibility = avcc.profileCompatibility;
            levelCode            = avcc.levelCode;
            naluLengthSize       = checked ((byte)(avcc.lengthSizeMinusOne + 1));

            Span <byte> remainingStuff = stackalloc byte[bytesLeft];

            reader.read(remainingStuff);

            int readOffset = 0;

            sps = ContainerUtils.copyBlobs(avcc.numOfSequenceParameterSets, remainingStuff, ref readOffset);

            if (null == sps)
            {
                throw new ArgumentException("The file doesn't have an SPS");
            }
            // SpsData spsData = new SpsData( sps[ 0 ] );
            // File.WriteAllBytes( @"C:\Temp\2remove\h264\sps.bin", sps[ 0 ] );

            int ppsCount = remainingStuff[readOffset++];

            pps = ContainerUtils.copyBlobs(ppsCount, remainingStuff, ref readOffset);

            if (null == sps || null == pps)
            {
                throw new NotImplementedException("Vrmac Video only supports mp4 files with out-of-band SPS and PPS blobs, in the `avcC` atom of the file.");
            }
            if (sps.Length > 1 || pps.Length > 1)
            {
                throw new NotImplementedException("Vrmac Video only supports mp4 files with a single out-of-band SPS and PPS for the complete video.");                     // The video payload may include other PPS-es, these are fine.
            }
            if (readOffset >= remainingStuff.Length)
            {
                return;
            }

            remainingStuff = remainingStuff.Slice(readOffset);

            if (readOffset + decoderConfigSizeof < avcc.length)
            {
                // The spec I have says the files with profile IDs 100, 110, 122, 144 have this.
                // The mp4 file I use to test this code has 100, but misses this data.
                chromaFormat   = (eChromaFormat)(remainingStuff[0] & 3);
                bitDepthLuma   = (byte)((remainingStuff[1] & 7) + 8);
                bitDepthChroma = (byte)((remainingStuff[2] & 7) + 8);
                int numPpsEx = remainingStuff[3];
                readOffset = 4;                 // Resetting because sliced the span
                ppsExt     = ContainerUtils.copyBlobs(numPpsEx, remainingStuff, ref readOffset);

                remainingStuff = remainingStuff.Slice(readOffset);
            }
            else
            {
                // https://en.wikipedia.org/wiki/Advanced_Video_Coding#Feature_support_in_particular_profiles
                chromaFormat   = eChromaFormat.c420;
                bitDepthLuma   = 8;
                bitDepthChroma = 8;
            }

            while (!remainingStuff.IsEmpty)
            {
                int          size = BitConverter.ToInt32(remainingStuff).endian();
                eAVC1BoxType code = (eAVC1BoxType)BitConverter.ToUInt32(remainingStuff.Slice(4));
                switch (code)
                {
                case eAVC1BoxType.btrt:
                    bitRate           = new MPEG4BitRateBox(remainingStuff);
                    m_maxBytesInFrame = bitRate.decodingBufferSize;
                    break;
                }
                remainingStuff = remainingStuff.Slice(size);
            }
        }
Exemplo n.º 3
0
        internal SequenceParameterSet(ref BitReader reader)
        {
            // Ported from C++ in Chromium, \chromium-master\media\video\h264_parser.cc

            profile = (eAvcProfile)reader.readInt(8);
            reader.skipBits(8);                                       // constraint_set0_flag x6 + 2 reserved bits
            levelIndex     = (byte)reader.readInt(8);
            parameterSetId = checked ((byte)reader.unsignedGolomb()); // seq_parameter_set_id
            if (parameterSetId >= 32)
            {
                throw new ArgumentException();
            }

            if (extraBs.Contains((byte)profile))
            {
                uint chromaFormatIndex = reader.unsignedGolomb();                   // uint chroma_format_idc
                if (chromaFormatIndex >= 4)
                {
                    throw new ArgumentException();
                }
                chromaFormat = (eChromaFormat)chromaFormatIndex;
                if (3 == chromaFormatIndex)
                {
                    separateColourPlaneFlag = reader.readBit();
                }
                else
                {
                    separateColourPlaneFlag = false;
                }

                uint bit_depth_luma_minus8 = reader.unsignedGolomb();
                if (bit_depth_luma_minus8 >= 7)
                {
                    throw new ArgumentException();
                }
                bitDepthLuma = (byte)(bit_depth_luma_minus8 + 8);

                uint bit_depth_chroma_minus8 = reader.unsignedGolomb();
                if (bit_depth_chroma_minus8 >= 7)
                {
                    throw new ArgumentException();
                }
                bitDepthChroma = (byte)(bit_depth_chroma_minus8 + 8);

                bool qpprime_y_zero_transform_bypass_flag = reader.readBit();
                bool seq_scaling_matrix_present_flag      = reader.readBit();
                if (seq_scaling_matrix_present_flag)
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                chromaFormat            = eChromaFormat.c420;
                separateColourPlaneFlag = false;
                bitDepthLuma            = bitDepthChroma = 8;
            }

            uint log2_max_frame_num_minus4 = reader.unsignedGolomb();

            frameIndexBits = checked ((byte)(log2_max_frame_num_minus4 + 4));

            uint pic_order_cnt_type = reader.unsignedGolomb();

            switch (pic_order_cnt_type)
            {
            case 0:
                reader.skipGolomb();                            // log2_max_pic_order_cnt_lsb_minus4
                break;

            case 1:
                reader.skipBits(1);                           // delta_pic_order_always_zero_flag
                reader.skipGolomb();                          // int offset_for_non_ref_pic
                reader.skipGolomb();                          // int offset_for_top_to_bottom_field
                uint num_ref_frames_in_pic_order_cnt_cycle = reader.unsignedGolomb();
                if (num_ref_frames_in_pic_order_cnt_cycle >= 0xFF)
                {
                    throw new ArgumentException();
                }
                for (int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
                {
                    reader.skipGolomb();                                // int offset_for_ref_frame
                }
                break;
            }
            reader.skipGolomb();            // uint max_num_ref_frames
            reader.skipBits(1);             // bool gaps_in_frame_num_value_allowed_flag

            // Decoded size
            int  pic_width_in_mbs_minus1        = (int)reader.unsignedGolomb();
            int  pic_height_in_map_units_minus1 = (int)reader.unsignedGolomb();
            bool frame_mbs_only_flag            = reader.readBit();

            decodedSize    = default;
            decodedSize.cx = (pic_width_in_mbs_minus1 + 1) * 16;
            if (false == frame_mbs_only_flag)
            {
                reader.skipBits(1);                     // bool mb_adaptive_frame_field_flag
            }
            int map_unit = frame_mbs_only_flag ? 16 : 32;

            decodedSize.cy = map_unit * (pic_height_in_map_units_minus1 + 1);

            reader.skipBits(1);               // direct_8x8_inference_flag

            // Frame cropping
            bool frame_cropping_flag = reader.readBit();

            if (frame_cropping_flag)
            {
                int frame_crop_left_offset   = (int)reader.unsignedGolomb();
                int frame_crop_right_offset  = (int)reader.unsignedGolomb();
                int frame_crop_top_offset    = (int)reader.unsignedGolomb();
                int frame_crop_bottom_offset = (int)reader.unsignedGolomb();

                CSize cropUnit;
                switch (chromaFormat)
                {
                case eChromaFormat.c420:
                    cropUnit = new CSize(2, 2);
                    break;

                case eChromaFormat.c422:
                    cropUnit = new CSize(2, 1);
                    break;

                case eChromaFormat.c444:
                    cropUnit = new CSize(1, 1);
                    break;

                default:
                    throw new ArgumentException();
                }

                cropRectangle        = default;
                cropRectangle.left   = frame_crop_left_offset * cropUnit.cx;
                cropRectangle.top    = frame_crop_top_offset * cropUnit.cy;
                cropRectangle.right  = decodedSize.cx - frame_crop_right_offset * cropUnit.cx;
                cropRectangle.bottom = decodedSize.cy - frame_crop_bottom_offset * cropUnit.cy;
            }
            else
            {
                cropRectangle = new CRect(default, decodedSize);