예제 #1
0
 void Dump(bool force, MMalBuffer buffer, int len)
 {
     if (force)
     {
         _logger.Error("buffer {0}", buffer.ToString());
         StringBuilder sb = new StringBuilder();
         for (int i = 0; i < buffer.Data.Length && i < len; ++i)
         {
             if ((i % 4) == 0)
             {
                 sb.Append(" ");
             }
             sb.AppendFormat("{0:x2}", buffer.Data[i]);
             if (((i + 1) % 30) == 0)
             {
                 sb.Append("\r\n");
             }
         }
         _logger.Error(sb.ToString());
     }
 }
예제 #2
0
        public void Parse(MMalBuffer buffer, MMalBuffer next)
        {
            if (_logger.IsDebugEnabled)
            {
                _logger.Debug("buffer.Len {0}, presentation time {1}", buffer.Length, buffer.Timestamp);
            }
            if (buffer.Data.Length < 4)
            {
                return;
            }



            bool         pictureEndMarker = false;
            MemoryStream ms = new MemoryStream(buffer.Data);

            if (NaluIsStartCode(ms) == 0)
            {
                Dump(true, buffer, 10);
                throw new Exception("No Start Code");
            }

            long nalStart = ms.Position;

            while (ms.Position < ms.Length)
            {
                int nalAndTrailingSize;
                int nalSize;
                int nalEnd;

                pictureEndMarker   = false;
                nalAndTrailingSize = nalSize = NaluNextStartCode(ms);
                if (true)
                {
                    nalSize = NaluPayloadEnd(ms);
                }


                byte[] nalunit = new byte[nalSize];
                ms.Read(nalunit, 0, (int)nalSize);



                ms.Seek(nalStart, SeekOrigin.Begin);

                byte nalunitType = (byte)(nalunit[0] & 0x1F);

                // Now that we have found (& copied) a NAL unit, process it if it's of special interest to us:
                if (IsVPS(nalunitType))
                {
                    // Video parameter set


                    // We haven't yet parsed a frame rate from the stream.
                    // So parse this NAL unit to check whether frame rate information is present:
                    // uint num_units_in_tick = 0, time_scale = 0;
                    // AnalyzeVPS(ref num_units_in_tick, ref time_scale);
                }
                else if (IsSPS(nalunitType))
                {
                    // Sequence parameter set
                    // We haven't yet parsed a frame rate from the stream.
                    // So parse this NAL unit to check whether frame rate information is present:
                    // uint num_units_in_tick = 0, time_scale = 0;
                    //AnalyzeSPS(nalunit, ref num_units_in_tick, ref time_scale);
                    //if (time_scale > 0 && num_units_in_tick > 0)
                    //{
                    //	fFrameRate = fParsedFrameRate = time_scale / (DeltaTfiDivisor * num_units_in_tick);
                    //}
                }
                else if (IsPPS(nalunitType))
                {
                }
                //else if (isSEI(nal_unit_type))
                //{ // Supplemental enhancement information (SEI)
                //	analyze_sei_data(nal_unit_type);
                //	// Later, perhaps adjust "fPresentationTime" if we saw a "pic_timing" SEI payload??? #####
                //}


                // Now, check whether this NAL unit ends an 'access unit'.
                // (RTP streamers need to know this in order to figure out whether or not to set the "M" bit.)
                bool thisNALUnitEndsAccessUnit = false;
                if (IsEOF(nalunitType))
                {
                    // There is no next NAL unit, so we assume that this one ends the current 'access unit':
                    thisNALUnitEndsAccessUnit = true;
                }
                else if (UsuallyBeginsAccessUnit(nalunitType))
                {
                    // These NAL units usually *begin* an access unit, so assume that they don't end one here:
                    thisNALUnitEndsAccessUnit = false;
                }
                else
                {
                    // We need to check the *next* NAL unit to figure out whether
                    // the current NAL unit ends an 'access unit':
                    byte nextNalunitType = 0;
                    nalEnd = (int)ms.Position;                    // gf_bs_get_position(bs);
                    Debug.Assert(nalStart <= nalEnd);
                    Debug.Assert(nalEnd <= nalStart + nalAndTrailingSize);
                    if (nalEnd != nalStart + nalAndTrailingSize)
                    {
                        ms.Seek(nalStart + nalAndTrailingSize, SeekOrigin.Begin);
                    }



                    if (ms.Position == ms.Length)
                    {
                        if (next.Data.Length > 5)
                        {
                            nextNalunitType = (byte)(next.Data[4] & 0x1F);
                        }
                    }
                    else
                    {
                        ms.Seek(nalStart + nalAndTrailingSize, SeekOrigin.Begin);

                        /*consume next start code*/
                        nalStart = NaluNextStartCode(ms);
                        if (nalStart != 0)
                        {
                            Console.WriteLine("[avc-h264] invalid nal_size ({0})? Skipping {1} bytes to reach next start code\n", nalSize, nalStart);
                            //gf_bs_skip_bytes(bs, nal_start);
                        }
                        nalStart = NaluIsStartCode(ms);
                        if (nalStart == 0)
                        {
                            _logger.Error("avc-h264 error: no start code found");
                            break;
                        }
                        nalStart           = ms.Position;              // gf_bs_get_position(bs);
                        nalAndTrailingSize = nalSize = NaluNextStartCode(ms);
                        if (true)
                        {
                            nalSize = NaluPayloadEnd(ms);
                        }


                        byte[] nextNalunit = new byte[nalSize];
                        ms.Read(nextNalunit, 0, (int)nalSize);
                        nextNalunitType = (byte)(next.Data[4] & 0x1F);

                        ms.Seek(nalStart, SeekOrigin.Begin);
                    }

                    if (IsVCL(nextNalunitType))
                    {
                        // The high-order bit of the byte after the "nal_unit_header" tells us whether it's
                        // the start of a new 'access unit' (and thus the current NAL unit ends an 'access unit'):
                        byte byteAfter_nal_unit_header = 0x80;
                        if (next.Data.Length >= 5)
                        {
                            byteAfter_nal_unit_header = next.Data[5];
                        }
                        thisNALUnitEndsAccessUnit = (byteAfter_nal_unit_header & 0x80) != 0;

                        if (_logger.IsDebugEnabled)
                        {
                            _logger.Debug("End of NalUnit {0}", thisNALUnitEndsAccessUnit);
                        }
                    }
                    else if (UsuallyBeginsAccessUnit(nextNalunitType))
                    {
                        // The next NAL unit's type is one that usually appears at the start of an 'access unit',
                        // so we assume that the current NAL unit ends an 'access unit':
                        thisNALUnitEndsAccessUnit = true;
                    }
                    else
                    {
                        // The next NAL unit definitely doesn't start a new 'access unit',
                        // which means that the current NAL unit doesn't end one:
                        thisNALUnitEndsAccessUnit = false;
                    }
                }


                if (thisNALUnitEndsAccessUnit)
                {
                    if (_logger.IsDebugEnabled)
                    {
                        _logger.Debug(" * ****This NAL unit ends the current access unit * ****\n");
                    }
                    pictureEndMarker = true;
                }


                if (_logger.IsDebugEnabled)
                {
                    _logger.Debug("EndNalAccessUnit {0}, presentation {1}", thisNALUnitEndsAccessUnit, buffer.Timestamp);
                }

                // TODO
                //byte[] tmp = new byte[nalSize + 4];
                //tmp[3] = 1;
                //Array.Copy(nalunit, 0, tmp, 4, nalunit.Length);
                //Dump(tmp, numNalunit);
                //numNalunit++;

                _fragmenter.OnNewNalUnit(nalunit, thisNALUnitEndsAccessUnit, pictureEndMarker);

                nalEnd = (int)ms.Position;
                Debug.Assert(nalStart <= nalEnd);
                Debug.Assert(nalEnd <= nalStart + nalAndTrailingSize);
                if (nalEnd != nalStart + nalAndTrailingSize)
                {
                    ms.Seek(nalStart + nalAndTrailingSize, SeekOrigin.Begin);
                }

                if (nalSize == 0)
                {
                    break;
                }

                if (ms.Position == ms.Length)
                {
                    break;
                }

                /*consume next start code*/
                nalStart = NaluNextStartCode(ms);
                if (nalStart != 0)
                {
                    _logger.Error("[avc-h264] invalid nal_size ({0})? Skipping {1} bytes to reach next start code", nalSize, nalStart);
                }
                nalStart = NaluIsStartCode(ms);
                if (nalStart == 0)
                {
                    _logger.Error("[avc-h264] error: no start code found");
                    break;
                }
                nalStart = ms.Position;
            }             // while
        }