예제 #1
0
파일: Mp4Atom.cs 프로젝트: GodLesZ/svn-dump
		/// <summary>
		/// Loads M4ESDAtom atom from the input bitstream.
		/// </summary>
		/// <param name="bitstream">The input bitstream.</param>
		/// <returns>The number of bytes loaded.</returns>
		public long create_esd_atom(Mp4DataStream bitstream) {
			create_full_atom(bitstream);
			esd_descriptor = Mp4Descriptor.CreateDescriptor(bitstream);
			_bytesRead += esd_descriptor.BytesRead;
			return _bytesRead;
		}
예제 #2
0
        /// <summary>
        /// This handles the moov atom being at the beginning or end of the file, so the mdat may also be before or after the moov atom.
        /// </summary>
        public void DecodeHeader()
        {
            try
            {
                // the first atom will/should be the type
                Mp4Atom type = Mp4Atom.CreateAtom(_inputStream);
                // expect ftyp
#if LOGGING
                log.Debug(string.Format("Type {0}", type));
#endif
                // keep a running count of the number of atoms found at the "top" levels
                int topAtoms = 0;
                // we want a moov and an mdat, anything else throw the invalid file type error
                while (topAtoms < 2)
                {
                    Mp4Atom atom = Mp4Atom.CreateAtom(_inputStream);
                    switch (atom.Type)
                    {
                    case 1836019574:     //moov
                        topAtoms++;
                        Mp4Atom moov = atom;
                        // expect moov
#if LOGGING
                        log.Debug(string.Format("Type {0}", moov));
#endif
                        //log.debug("moov children: {}", moov.getChildren());
                        _moovOffset = _inputStream.Offset - moov.Size;

                        Mp4Atom mvhd = moov.Lookup(Mp4Atom.TypeToInt("mvhd"), 0);
                        if (mvhd != null)
                        {
#if LOGGING
                            log.Debug("Movie header atom found");
#endif
                            //get the initial timescale
                            _timeScale = mvhd.TimeScale;
                            _duration  = mvhd.Duration;
#if LOGGING
                            log.Debug(string.Format("Time scale {0} Duration {1}", _timeScale, _duration));
#endif
                        }

                        /* nothing needed here yet
                         * MP4Atom meta = moov.lookup(MP4Atom.typeToInt("meta"), 0);
                         * if (meta != null) {
                         *  log.debug("Meta atom found");
                         *  log.debug("{}", ToStringBuilder.reflectionToString(meta));
                         * }
                         */

                        Mp4Atom trak = moov.Lookup(Mp4Atom.TypeToInt("trak"), 0);
                        if (trak != null)
                        {
#if LOGGING
                            log.Debug("Track atom found");
#endif
                            //log.debug("trak children: {}", trak.getChildren());
                            // trak: tkhd, edts, mdia

                            Mp4Atom edts = trak.Lookup(Mp4Atom.TypeToInt("edts"), 0);
                            if (edts != null)
                            {
#if LOGGING
                                log.Debug("Edit atom found");
#endif
                                //log.debug("edts children: {}", edts.getChildren());
                            }

                            Mp4Atom mdia = trak.Lookup(Mp4Atom.TypeToInt("mdia"), 0);
                            if (mdia != null)
                            {
#if LOGGING
                                log.Debug("Media atom found");
#endif
                                // mdia: mdhd, hdlr, minf

                                int scale = 0;
                                //get the media header atom
                                Mp4Atom mdhd = mdia.Lookup(Mp4Atom.TypeToInt("mdhd"), 0);
                                if (mdhd != null)
                                {
#if LOGGING
                                    log.Debug("Media data header atom found");
#endif
                                    //this will be for either video or audio depending media info
                                    scale = mdhd.TimeScale;
#if LOGGING
                                    log.Debug(string.Format("Time scale {0}", scale));
#endif
                                }

                                Mp4Atom hdlr = mdia.Lookup(Mp4Atom.TypeToInt("hdlr"), 0);
                                if (hdlr != null)
                                {
#if LOGGING
                                    log.Debug("Handler ref atom found");
#endif
// soun or vide
#if LOGGING
                                    log.Debug(string.Format("Handler type: {0}", Mp4Atom.IntToType(hdlr.HandlerType)));
#endif
                                    String hdlrType = Mp4Atom.IntToType(hdlr.HandlerType);
                                    if ("soun".Equals(hdlrType))
                                    {
                                        if (scale > 0)
                                        {
                                            _audioTimeScale = scale * 1.0;
#if LOGGING
                                            log.Debug(string.Format("Audio time scale: {0}", _audioTimeScale));
#endif
                                        }
                                    }
                                }

                                Mp4Atom minf = mdia.Lookup(Mp4Atom.TypeToInt("minf"), 0);
                                if (minf != null)
                                {
#if LOGGING
                                    log.Debug("Media info atom found");
#endif
                                    // minf: (audio) smhd, dinf, stbl / (video) vmhd,
                                    // dinf, stbl
                                    Mp4Atom smhd = minf.Lookup(Mp4Atom.TypeToInt("smhd"), 0);
                                    if (smhd != null)
                                    {
                                            #if LOGGING
                                        log.Debug("Sound header atom found");
#endif
                                        Mp4Atom dinf = minf.Lookup(Mp4Atom.TypeToInt("dinf"), 0);
                                        if (dinf != null)
                                        {
#if LOGGING
                                            log.Debug("Data info atom found");
#endif
                                            // dinf: dref
                                            //log.Debug("Sound dinf children: {}", dinf.getChildren());
                                            Mp4Atom dref = dinf.Lookup(Mp4Atom.TypeToInt("dref"), 0);
                                            if (dref != null)
                                            {
#if LOGGING
                                                log.Debug("Data reference atom found");
#endif
                                            }
                                        }
                                        Mp4Atom stbl = minf.Lookup(Mp4Atom.TypeToInt("stbl"), 0);
                                        if (stbl != null)
                                        {
#if LOGGING
                                            log.Debug("Sample table atom found");
#endif
                                            // stbl: stsd, stts, stss, stsc, stsz, stco,
                                            // stsh
                                            //log.debug("Sound stbl children: {}", stbl.getChildren());
                                            // stsd - sample description
                                            // stts - time to sample
                                            // stsc - sample to chunk
                                            // stsz - sample size
                                            // stco - chunk offset

                                            //stsd - has codec child
                                            Mp4Atom stsd = stbl.Lookup(Mp4Atom.TypeToInt("stsd"), 0);
                                            if (stsd != null)
                                            {
                                                //stsd: mp4a
#if LOGGING
                                                log.Debug("Sample description atom found");
#endif
                                                Mp4Atom mp4a = stsd.Children[0];
                                                //could set the audio codec here
                                                SetAudioCodecId(Mp4Atom.IntToType(mp4a.Type));
                                                //log.debug("{}", ToStringBuilder.reflectionToString(mp4a));
#if LOGGING
                                                log.Debug(string.Format("Sample size: {0}", mp4a.SampleSize));
#endif
                                                int ats = mp4a.TimeScale;
                                                //skip invalid audio time scale
                                                if (ats > 0)
                                                {
                                                    _audioTimeScale = ats * 1.0;
                                                }
                                                _audioChannels = mp4a.ChannelCount;
#if LOGGING
                                                log.Debug(string.Format("Sample rate (audio time scale): {0}", _audioTimeScale));
#endif
#if LOGGING
                                                log.Debug(string.Format("Channels: {0}", _audioChannels));
#endif
                                                //mp4a: esds
                                                if (mp4a.Children.Count > 0)
                                                {
#if LOGGING
                                                    log.Debug("Elementary stream descriptor atom found");
#endif
                                                    Mp4Atom esds = mp4a.Children[0];
                                                    //log.debug("{}", ToStringBuilder.reflectionToString(esds));
                                                    Mp4Descriptor descriptor = esds.EsdDescriptor;
                                                    //log.debug("{}", ToStringBuilder.reflectionToString(descriptor));
                                                    if (descriptor != null)
                                                    {
                                                        List <Mp4Descriptor> children = descriptor.Children;
                                                        for (int e = 0; e < children.Count; e++)
                                                        {
                                                            Mp4Descriptor descr = children[e];
                                                            //log.debug("{}", ToStringBuilder.reflectionToString(descr));
                                                            if (descr.Children.Count > 0)
                                                            {
                                                                List <Mp4Descriptor> children2 = descr.Children;
                                                                for (int e2 = 0; e2 < children2.Count; e2++)
                                                                {
                                                                    Mp4Descriptor descr2 = children2[e2];
                                                                    //log.debug("{}", ToStringBuilder.reflectionToString(descr2));
                                                                    if (descr2.Type == Mp4Descriptor.MP4DecSpecificInfoDescriptorTag)
                                                                    {
                                                                        //we only want the MP4DecSpecificInfoDescriptorTag
                                                                        _audioDecoderBytes = descr2.DSID;
                                                                        //compare the bytes to get the aacaot/aottype
                                                                        //match first byte
                                                                        switch (_audioDecoderBytes[0])
                                                                        {
                                                                        case 0x12:
                                                                        default:
                                                                            //AAC LC - 12 10
                                                                            _audioCodecType = 1;
                                                                            break;

                                                                        case 0x0a:
                                                                            //AAC Main - 0A 10
                                                                            _audioCodecType = 0;
                                                                            break;

                                                                        case 0x11:
                                                                        case 0x13:
                                                                            //AAC LC SBR - 11 90 & 13 xx
                                                                            _audioCodecType = 2;
                                                                            break;
                                                                        }
                                                                        //we want to break out of top level for loop
                                                                        e = 99;
                                                                        break;
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            //stsc - has Records
                                            Mp4Atom stsc = stbl.Lookup(Mp4Atom.TypeToInt("stsc"), 0);
                                            if (stsc != null)
                                            {
#if LOGGING
                                                log.Debug("Sample to chunk atom found");
#endif
                                                _audioSamplesToChunks = stsc.Records;
#if LOGGING
                                                log.Debug(string.Format("Record count: {0}", _audioSamplesToChunks.Count));
#endif
                                                Mp4Atom.Record rec = _audioSamplesToChunks[0];
#if LOGGING
                                                log.Debug(string.Format("Record data: Description index={0} Samples per chunk={1}", rec.SampleDescriptionIndex, rec.SamplesPerChunk));
#endif
                                            }
                                            //stsz - has Samples
                                            Mp4Atom stsz = stbl.Lookup(Mp4Atom.TypeToInt("stsz"), 0);
                                            if (stsz != null)
                                            {
#if LOGGING
                                                log.Debug("Sample size atom found");
#endif
                                                _audioSamples = stsz.Samples;
                                                //vector full of integers
#if LOGGING
                                                log.Debug(string.Format("Sample size: {0}", stsz.SampleSize));
#endif
#if LOGGING
                                                log.Debug(string.Format("Sample count: {0}", _audioSamples.Count));
#endif
                                            }
                                            //stco - has Chunks
                                            Mp4Atom stco = stbl.Lookup(Mp4Atom.TypeToInt("stco"), 0);
                                            if (stco != null)
                                            {
#if LOGGING
                                                log.Debug("Chunk offset atom found");
#endif
                                                //vector full of integers
                                                _audioChunkOffsets = stco.Chunks;
#if LOGGING
                                                log.Debug(string.Format("Chunk count: {0}", _audioChunkOffsets.Count));
#endif
                                            }
                                            //stts - has TimeSampleRecords
                                            Mp4Atom stts = stbl.Lookup(Mp4Atom.TypeToInt("stts"), 0);
                                            if (stts != null)
                                            {
#if LOGGING
                                                log.Debug("Time to sample atom found");
#endif
                                                List <Mp4Atom.TimeSampleRecord> records = stts.TimeToSamplesRecords;
#if LOGGING
                                                log.Debug(string.Format("Record count: {0}", records.Count));
#endif
                                                Mp4Atom.TimeSampleRecord rec = records[0];
#if LOGGING
                                                log.Debug(string.Format("Record data: Consecutive samples={0} Duration={1}", rec.ConsecutiveSamples, rec.SampleDuration));
#endif
                                                //if we have 1 record then all samples have the same duration
                                                if (records.Count > 1)
                                                {
                                                    //TODO: handle audio samples with varying durations
#if LOGGING
                                                    log.Debug("Audio samples have differing durations, audio playback may fail");
#endif
                                                }
                                                _audioSampleDuration = rec.SampleDuration;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        //real duration
                        StringBuilder sb       = new StringBuilder();
                        double        clipTime = ((double)_duration / (double)_timeScale);
#if LOGGING
                        log.Debug(string.Format("Clip time: {0}", clipTime));
#endif
                        int minutes = (int)(clipTime / 60);
                        if (minutes > 0)
                        {
                            sb.Append(minutes);
                            sb.Append('.');
                        }
                        //formatter for seconds / millis
                        //NumberFormat df = DecimalFormat.getInstance();
                        //df.setMaximumFractionDigits(2);
                        //sb.append(df.format((clipTime % 60)));
                        sb.Append(clipTime % 60);
                        _formattedDuration = sb.ToString();
#if LOGGING
                        log.Debug(string.Format("Time: {0}", _formattedDuration));
#endif
                        break;

                    case 1835295092:     //mdat
                        topAtoms++;
                        long    dataSize = 0L;
                        Mp4Atom mdat     = atom;
                        dataSize = mdat.Size;
                        //log.debug("{}", ToStringBuilder.reflectionToString(mdat));
                        _mdatOffset = _inputStream.Offset - dataSize;
#if LOGGING
                        log.Debug(string.Format("File size: {0} mdat size: {1}", _file.Length, dataSize));
#endif
                        break;

                    case 1718773093:     //free
                    case 2003395685:     //wide
                        break;

                    default:
#if LOGGING
                        log.Warn(string.Format("Unexpected atom: {}", Mp4Atom.IntToType(atom.Type)));
#endif
                        break;
                    }
                }
                //add the tag name (size) to the offsets
                _moovOffset += 8;
                _mdatOffset += 8;
#if LOGGING
                log.Debug(string.Format("Offsets moov: {0} mdat: {1}", _moovOffset, _mdatOffset));
#endif
            }
            catch (Exception ex)
            {
#if LOGGING
                log.Error("Exception decoding header / atoms", ex);
#endif
            }
        }