예제 #1
0
파일: Mp4.cs 프로젝트: tidus9000/PopH264
    byte[] GetDataBytes(TPendingSample Sample)
    {
        var MdatIndex = Sample.MdatIndex;

        //Sample.DataPosition, Sample.DataSizeuint MdatIndex, long Position, long Size)
        if (!HasMdat(MdatIndex))
        {
            throw new System.Exception("Not yet recieved mdat #" + MdatIndex);
        }
        var Meta = Mdats[MdatIndex];

        long Position;

        if (Sample.DataFilePosition.HasValue)
        {
            Position = Sample.DataFilePosition.Value - Meta.Atom.AtomDataFilePosition;
        }
        else
        {
            Position = Sample.DataPosition.Value;
        }

        return(Meta.Bytes.SubArray(Position, Sample.DataSize));
    }
예제 #2
0
파일: Mp4.cs 프로젝트: tidus9000/PopH264
    void ParseNextMp4Header()
    {
        //	check if there's more data to be read
        var KnownFileSize = GetKnownFileSize();

        if (Mp4BytesRead >= KnownFileSize)
        {
            return;
        }


        int TimeOffset = 0;

        System.Action <PopX.Mpeg4.TTrack> EnumTrack = (Track) =>
        {
            System.Action <byte[], int> PushPacket;

            byte[] Sps_AnnexB;
            byte[] Pps_AnnexB;

            //	track has header (so if we have moov and moof's, this only comes up once, and that's when we need to decode SPS/PPS
            if (Track.SampleDescriptions != null)
            {
                if (Track.SampleDescriptions[0].Fourcc != "avc1")
                {
                    throw new System.Exception("Expecting fourcc avc1, got " + Track.SampleDescriptions[0].Fourcc);
                }

                H264.AvccHeader Header;
                Header = PopX.H264.ParseAvccHeader(Track.SampleDescriptions[0].AvccAtomData);

                //	wrong place to assign this! should be when we assign the track index
                H264TrackHeader = Header;

                var Pps = new List <byte>(new byte[] { 0, 0, 0, 1 });
                Pps.AddRange(Header.PPSs[0]);
                Pps_AnnexB = Pps.ToArray();

                var Sps = new List <byte>(new byte[] { 0, 0, 0, 1 });
                Sps.AddRange(Header.SPSs[0]);
                Sps_AnnexB = Sps.ToArray();

                PushPacket = (Packet, FrameNumber) =>
                {
                    H264.AvccToAnnexb4(Header, Packet, (Bytes) => { PushFrame_AnnexB(Bytes, FrameNumber); });
                };
            }
            else if (Preconfigured_SPS_Bytes != null && Preconfigured_SPS_Bytes.Length > 0)
            {
                throw new System.Exception("Need to refactor to process preconfigured SPS before handling tracks");
                //	split this header
                Sps_AnnexB = Preconfigured_SPS_Bytes;
                Pps_AnnexB = null;

                //	gr: turns out these are AVCC, not annexb
                //	gr: should be able to auto detect without header
                //PushPacket = PushAnnexB;
                H264.AvccHeader Header = new H264.AvccHeader();
                Header.NaluLength = 2;
                PushPacket        = (Packet, FrameNumber) =>
                {
                    H264.AvccToAnnexb4(Header, Packet, (Bytes) => { PushFrame_AnnexB(Bytes, FrameNumber); });
                };
            }
            else
            {
                //	track without header, assume it's already come via moov and this is a moof
                Sps_AnnexB = null;
                Pps_AnnexB = null;
                PushPacket = null;
            }


            //	load h264 header
            if (Sps_AnnexB != null)
            {
                H264.Profile Profile;
                float        Level;
                PopX.H264.GetProfileLevel(Sps_AnnexB, out Profile, out Level);
                if (Profile != H264.Profile.Baseline)
                {
                    Debug.LogWarning("PopH264 currently only supports baseline profile. This is " + Profile + " level=" + Level);
                }

                PushFrame_AnnexB(Sps_AnnexB, 0);
                PushFrame_AnnexB(Pps_AnnexB, 0);
            }

            //	load samples
            if (Track.Samples == null)
            {
                if (VerboseDebug)
                {
                    Debug.Log("Mp4 Track with null samples (next mdat=" + NextMdat + ")");
                }
            }
            else
            {
                //	gr: is there a better mdat ident? don't think so, it's just the upcoming one in mpeg sequence
                //	gr: sometimes, the mdat is before the tracks...
                //	gr: the sample offset also needs correcting
                var MdatIndex = MDatBeforeTrack ? NextMdat - 1 : 0;

                if (VerboseDebug)
                {
                    Debug.Log("Found mp4 track " + Track.Samples.Count + " for next mdat: " + MdatIndex);
                }

                if (Track.Samples.Count > 0)
                {
                    var LastSampleTime = Track.Samples[Track.Samples.Count - 1].PresentationTimeMs;
                    if (!LastFrameTime.HasValue)
                    {
                        LastFrameTime = LastSampleTime;
                    }
                    LastFrameTime = Mathf.Max(LastFrameTime.Value, LastSampleTime);
                }

                foreach (var Sample in Track.Samples)
                {
                    try
                    {
                        var NewSample = new TPendingSample();
                        if (PendingInputSamples == null)
                        {
                            PendingInputSamples = new List <TPendingSample>();
                        }

                        NewSample.Sample    = Sample;
                        NewSample.MdatIndex = MdatIndex;
                        //NewSample.DataPosition = Sample.DataPosition;
                        //NewSample.DataFilePosition = Sample.DataFilePosition;
                        //NewSample.DataSize = Sample.DataSize;
                        var TimeOffsetMs = (int)(TimeOffset / 10000.0f);
                        //NewSample.PresentationTime = Sample.PresentationTimeMs + TimeOffsetMs;
                        NewSample.Format = PacketFormat.Avcc;
                        PendingInputSamples.Add(NewSample);
                    }
                    catch (System.Exception e)
                    {
                        Debug.LogException(e);
                        break;
                    }
                }
            }
        };

        System.Action <List <PopX.Mpeg4.TTrack> > EnumTracks = (Tracks) =>
        {
            //	moof headers don't have track headers, so we should have our track by now
            //	this track may be the original though, so hunt down the h264 one
            if (!H264TrackIndex.HasValue)
            {
                for (int t = 0; t < Tracks.Count; t++)
                {
                    var Track = Tracks[t];
                    if (Track.SampleDescriptions == null)
                    {
                        continue;
                    }

                    if (Track.SampleDescriptions[0].Fourcc != "avc1")
                    {
                        Debug.Log("Skipping track codec: " + Track.SampleDescriptions[0].Fourcc);
                        continue;
                    }

                    H264TrackIndex = t;
                }
            }

            if (!H264TrackIndex.HasValue)
            {
                throw new System.Exception("Couldn't find avc1 track");
            }

            EnumTrack(Tracks[H264TrackIndex.Value]);
        };

        System.Action <PopX.TAtom> EnumMdat = (MdatAtom) =>
        {
            if (VerboseDebug)
            {
                Debug.Log("EnumMdat( NextMdat=" + NextMdat);
            }

            if (!H264TrackIndex.HasValue)
            {
                MDatBeforeTrack = true;
            }

            //	this is the meta for the pending mdat
            var MdatIndex = NextMdat;

            if (Mdats == null)
            {
                Mdats = new Dictionary <uint, MdatBlock>();
            }

            var Mdat = new MdatBlock();
            Mdat.Atom       = MdatAtom;
            Mdat.FileOffset = Mdat.Atom.AtomDataFilePosition;                   //	need a better way to do this

            if (VerboseDebug)
            {
                Debug.Log("Got MDat " + MdatIndex + " x" + Mdat.Bytes.Length + " bytes");
            }
            Mdats.Add(MdatIndex, Mdat);

            //	increment once everything succeeds
            NextMdat++;
        };

        //	ideally only once we've verified we have an mp4, but before moov. Maybe just if an ftyp is found
        if (Decoder == null)
        {
            Decoder = new PopH264.Decoder(DecoderParams, DecodeOnSeperateThread);
        }


        System.Func <long, byte[]> PopData = (long DataSize) =>
        {
            var Data = ReadFileFunction(Mp4BytesRead, DataSize);
            Mp4BytesRead += DataSize;
            return(Data);
        };

        try
        {
            PopX.Mpeg4.ParseNextAtom(PopData, Mp4BytesRead, EnumTracks, EnumMdat);
        }
        catch (System.Exception e)
        {
            Debug.LogException(e);
        }
    }