/// <summary> /// Loads the version of the full atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_full_atom(Mp4DataStream bitstream) { long value = bitstream.ReadBytes(4); version = (int)value >> 24; flags = (int)value & 0xffffff; _bytesRead += 4; return(_bytesRead); }
/// <summary> /// Loads MP4VideoSampleEntryAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_video_sample_entry_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Video entry atom contains wxh"); #endif bitstream.SkipBytes(6); int dataReferenceIndex = (int)bitstream.ReadBytes(2); bitstream.SkipBytes(2); bitstream.SkipBytes(2); bitstream.SkipBytes(12); width = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Width: {0}", width)); #endif height = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Height: {0}", height)); #endif int horizontalRez = (int)bitstream.ReadBytes(4) >> 16; #if !SILVERLIGHT log.Debug(string.Format("H Resolution: {0}", horizontalRez)); #endif int verticalRez = (int)bitstream.ReadBytes(4) >> 16; #if !SILVERLIGHT log.Debug(string.Format("V Resolution: {0}", verticalRez)); #endif bitstream.SkipBytes(4); int frameCount = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Frame to sample count: {0}", frameCount)); #endif int stringLen = (int)bitstream.ReadBytes(1); #if !SILVERLIGHT log.Debug(string.Format("String length (cpname): {0}", stringLen)); #endif String compressorName = bitstream.ReadString(31); #if !SILVERLIGHT log.Debug(string.Format("Compressor name: {0}", compressorName.Trim())); #endif int depth = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Depth: {0}", depth)); #endif bitstream.SkipBytes(2); _bytesRead += 78; #if !SILVERLIGHT log.Debug(string.Format("Bytes read: {0}", _bytesRead)); #endif Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; return(_bytesRead); }
/// <summary> /// Loads MP4SyncSampleAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_sync_sample_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Sync sample atom contains keyframe info"); #endif create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); #if !SILVERLIGHT log.Debug(string.Format("Sync entries: {0}", entryCount)); #endif _bytesRead += 4; for (int i = 0; i < entryCount; i++) { int sample = (int)bitstream.ReadBytes(4); //log.trace("Sync entry: {}", sample); syncSamples.Add(sample); _bytesRead += 4; } return(_bytesRead); }
/// <summary> /// Loads Handler atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_handler_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); int qt_componentType = (int)bitstream.ReadBytes(4); handlerType = (int)bitstream.ReadBytes(4); int qt_componentManufacturer = (int)bitstream.ReadBytes(4); int qt_componentFlags = (int)bitstream.ReadBytes(4); int qt_componentFlagsMask = (int)bitstream.ReadBytes(4); _bytesRead += 20; int length = (int)(_size - _bytesRead - 1); String trackName = bitstream.ReadString(length); #if !SILVERLIGHT log.Debug(string.Format("Track name: {0}", trackName)); #endif _bytesRead += length; return(_bytesRead); }
public void CreateDecSpecificInfoDescriptor(Mp4DataStream bitstream) { decSpecificDataOffset = bitstream.Offset; dsid = new byte[_size]; for (int b = 0; b < _size; b++) { dsid[b] = (byte)bitstream.ReadBytes(1); _bytesRead++; } decSpecificDataSize = _size - _bytesRead; }
/// <summary> /// Loads MP4TimeToSampleAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_time_to_sample_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Time to sample atom"); #endif create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); #if !SILVERLIGHT log.Debug(string.Format("Time to sample entries: {0}", entryCount)); #endif _bytesRead += 4; for (int i = 0; i < entryCount; i++) { int sampleCount = (int)bitstream.ReadBytes(4); int sampleDuration = (int)bitstream.ReadBytes(4); //log.trace("Sync entry: {}", sample); timeToSamplesRecords.Add(new TimeSampleRecord(sampleCount, sampleDuration)); _bytesRead += 8; } return(_bytesRead); }
/// <summary> /// Loads MP4VisualSampleEntryAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_visual_sample_entry_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Visual entry atom contains wxh"); #endif bitstream.SkipBytes(24); width = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Width: {0}", width)); #endif height = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Height: {0}", height)); #endif bitstream.SkipBytes(50); _bytesRead += 78; Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; return(_bytesRead); }
/// <summary> /// Loads AVCC atom from the input bitstream. /// <para> /// 8+ bytes ISO/IEC 14496-10 or 3GPP AVC decode config box /// = long unsigned offset + long ASCII text string 'avcC' /// -> 1 byte version = 8-bit hex version (current = 1) /// -> 1 byte H.264 profile = 8-bit unsigned stream profile /// -> 1 byte H.264 compatible profiles = 8-bit hex flags /// -> 1 byte H.264 level = 8-bit unsigned stream level /// -> 1 1/2 nibble reserved = 6-bit unsigned value set to 63 /// -> 1/2 nibble NAL length = 2-bit length byte size type /// - 1 byte = 0 ; 2 bytes = 1 ; 4 bytes = 3 /// -> 1 byte number of SPS = 8-bit unsigned total /// -> 2+ bytes SPS length = short unsigned length /// -> + SPS NAL unit = hexdump /// -> 1 byte number of PPS = 8-bit unsigned total /// -> 2+ bytes PPS length = short unsigned length /// -> + PPS NAL unit = hexdump /// </para> /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_avc_config_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("AVC config"); log.Debug(string.Format("Offset: {0}", bitstream.Offset)); #endif //store the decoder config bytes videoConfigBytes = new byte[(int)_size]; for (int b = 0; b < videoConfigBytes.Length; b++) { videoConfigBytes[b] = (byte)bitstream.ReadBytes(1); switch (b) { //0 / version case 1: //profile avcProfile = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("AVC profile: {0}", avcProfile)); #endif break; case 2: //compatible profile int avcCompatProfile = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("AVC compatible profile: {0}", avcCompatProfile)); #endif break; case 3: //avc level avcLevel = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("AVC level: {0}", avcLevel)); #endif break; case 4: //NAL length break; case 5: //SPS number int numberSPS = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("Number of SPS: {0}", numberSPS)); #endif break; default: break; } _bytesRead++; } return(_bytesRead); }
/// <summary> /// Loads CompactSampleSize atom from the input stream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_compact_sample_size_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); bitstream.SkipBytes(3); sampleSize = 0; fieldSize = (int)bitstream.ReadBytes(1); sampleCount = (int)bitstream.ReadBytes(4); _bytesRead += 8; for (int i = 0; i < sampleCount; i++) { int size = 0; switch (fieldSize) { case 4: size = (int)bitstream.ReadBytes(1); // TODO check the following code samples.Add(size & 0x0f); size = (size >> 4) & 0x0f; i++; _bytesRead += 1; break; case 8: size = (int)bitstream.ReadBytes(1); _bytesRead += 1; break; case 16: size = (int)bitstream.ReadBytes(2); _bytesRead += 2; break; } if (i < sampleCount) { samples.Add(size); } } return(_bytesRead); }
public static Mp4Descriptor CreateDescriptor(Mp4DataStream bitstream) { int tag = (int)bitstream.ReadBytes(1); int bytesRead = 1; int size = 0; int b = 0; do { b = (int)bitstream.ReadBytes(1); size <<= 7; size |= b & 0x7f; bytesRead++; } while ((b & 0x80) == 0x80); Mp4Descriptor descriptor = new Mp4Descriptor(tag, size); switch (tag) { case MP4ES_DescriptorTag: descriptor.CreateESDescriptor(bitstream); break; case MP4DecoderConfigDescriptorTag: descriptor.CreateDecoderConfigDescriptor(bitstream); break; case MP4DecSpecificInfoDescriptorTag: descriptor.CreateDecSpecificInfoDescriptor(bitstream); break; default: break; } bitstream.SkipBytes(descriptor._size - descriptor._bytesRead); descriptor._bytesRead = bytesRead + descriptor._size; return(descriptor); }
/// <summary> /// Loads SampleDescription atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_sample_description_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); #if !SILVERLIGHT log.Debug(string.Format("stsd entry count: {0}", entryCount)); #endif _bytesRead += 4; for (int i = 0; i < entryCount; i++) { Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; } return(_bytesRead); }
/// <summary> /// Loads the MP4DecoderConfigDescriptor from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> public void CreateDecoderConfigDescriptor(Mp4DataStream bitstream) { int objectTypeIndication = (int)bitstream.ReadBytes(1); int value = (int)bitstream.ReadBytes(1); bool upstream = (value & (1 << 1)) > 0; byte streamType = (byte)(value >> 2); value = (int)bitstream.ReadBytes(2); int bufferSizeDB = value << 8; value = (int)bitstream.ReadBytes(1); bufferSizeDB |= value & 0xff; int maxBitRate = (int)bitstream.ReadBytes(4); int minBitRate = (int)bitstream.ReadBytes(4); _bytesRead += 13; if (_bytesRead < _size) { Mp4Descriptor descriptor = CreateDescriptor(bitstream); _children.Add(descriptor); _bytesRead += descriptor.BytesRead; } }
/// <summary> /// Loads MP4SampleToChunkAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_sample_to_chunk_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); _bytesRead += 4; for (int i = 0; i < entryCount; i++) { int firstChunk = (int)bitstream.ReadBytes(4); int samplesPerChunk = (int)bitstream.ReadBytes(4); int sampleDescriptionIndex = (int)bitstream.ReadBytes(4); records.Add(new Record(firstChunk, samplesPerChunk, sampleDescriptionIndex)); _bytesRead += 12; } return _bytesRead; }
/// <summary> /// Loads MP4SyncSampleAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_sync_sample_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Sync sample atom contains keyframe info"); #endif create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); #if !SILVERLIGHT log.Debug(string.Format("Sync entries: {0}", entryCount)); #endif _bytesRead += 4; for (int i = 0; i < entryCount; i++) { int sample = (int)bitstream.ReadBytes(4); //log.trace("Sync entry: {}", sample); syncSamples.Add(sample); _bytesRead += 4; } return _bytesRead; }
/// <summary> /// Loads MP4SampleSizeAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_sample_size_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); sampleSize = (int)bitstream.ReadBytes(4); sampleCount = (int)bitstream.ReadBytes(4); _bytesRead += 8; if (sampleSize == 0) { for (int i = 0; i < sampleCount; i++) { int size = (int)bitstream.ReadBytes(4); samples.Add(size); _bytesRead += 4; } } return _bytesRead; }
/// <summary> /// Loads CompactSampleSize atom from the input stream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_compact_sample_size_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); bitstream.SkipBytes(3); sampleSize = 0; fieldSize = (int)bitstream.ReadBytes(1); sampleCount = (int)bitstream.ReadBytes(4); _bytesRead += 8; for (int i = 0; i < sampleCount; i++) { int size = 0; switch (fieldSize) { case 4: size = (int)bitstream.ReadBytes(1); // TODO check the following code samples.Add(size & 0x0f); size = (size >> 4) & 0x0f; i++; _bytesRead += 1; break; case 8: size = (int)bitstream.ReadBytes(1); _bytesRead += 1; break; case 16: size = (int)bitstream.ReadBytes(2); _bytesRead += 2; break; } if (i < sampleCount) { samples.Add(size); } } return _bytesRead; }
/// <summary> /// Loads MovieHeader atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_movie_header_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); if (version == 1) { creationTime = createDate(bitstream.ReadBytes(8)); modificationTime = createDate(bitstream.ReadBytes(8)); timeScale = (int)bitstream.ReadBytes(4); duration = bitstream.ReadBytes(8); _bytesRead += 28; } else { creationTime = createDate(bitstream.ReadBytes(4)); modificationTime = createDate(bitstream.ReadBytes(4)); timeScale = (int)bitstream.ReadBytes(4); duration = bitstream.ReadBytes(4); _bytesRead += 16; } int qt_preferredRate = (int)bitstream.ReadBytes(4); int qt_preferredVolume = (int)bitstream.ReadBytes(2); bitstream.SkipBytes(10); long qt_matrixA = bitstream.ReadBytes(4); long qt_matrixB = bitstream.ReadBytes(4); long qt_matrixU = bitstream.ReadBytes(4); long qt_matrixC = bitstream.ReadBytes(4); long qt_matrixD = bitstream.ReadBytes(4); long qt_matrixV = bitstream.ReadBytes(4); long qt_matrixX = bitstream.ReadBytes(4); long qt_matrixY = bitstream.ReadBytes(4); long qt_matrixW = bitstream.ReadBytes(4); long qt_previewTime = bitstream.ReadBytes(4); long qt_previewDuration = bitstream.ReadBytes(4); long qt_posterTime = bitstream.ReadBytes(4); long qt_selectionTime = bitstream.ReadBytes(4); long qt_selectionDuration = bitstream.ReadBytes(4); long qt_currentTime = bitstream.ReadBytes(4); long nextTrackID = bitstream.ReadBytes(4); _bytesRead += 80; return _bytesRead; }
/// <summary> /// Loads SampleDescription atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_sample_description_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); #if !SILVERLIGHT log.Debug(string.Format("stsd entry count: {0}", entryCount)); #endif _bytesRead += 4; for (int i = 0; i < entryCount; i++) { Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; } return _bytesRead; }
/// <summary> /// Loads Handler atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_handler_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); int qt_componentType = (int)bitstream.ReadBytes(4); handlerType = (int)bitstream.ReadBytes(4); int qt_componentManufacturer = (int)bitstream.ReadBytes(4); int qt_componentFlags = (int)bitstream.ReadBytes(4); int qt_componentFlagsMask = (int)bitstream.ReadBytes(4); _bytesRead += 20; int length = (int)(_size - _bytesRead - 1); String trackName = bitstream.ReadString(length); #if !SILVERLIGHT log.Debug(string.Format("Track name: {0}", trackName)); #endif _bytesRead += length; return _bytesRead; }
/// <summary> /// Loads MovieHeader atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_movie_header_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); if (version == 1) { creationTime = createDate(bitstream.ReadBytes(8)); modificationTime = createDate(bitstream.ReadBytes(8)); timeScale = (int)bitstream.ReadBytes(4); duration = bitstream.ReadBytes(8); _bytesRead += 28; } else { creationTime = createDate(bitstream.ReadBytes(4)); modificationTime = createDate(bitstream.ReadBytes(4)); timeScale = (int)bitstream.ReadBytes(4); duration = bitstream.ReadBytes(4); _bytesRead += 16; } int qt_preferredRate = (int)bitstream.ReadBytes(4); int qt_preferredVolume = (int)bitstream.ReadBytes(2); bitstream.SkipBytes(10); long qt_matrixA = bitstream.ReadBytes(4); long qt_matrixB = bitstream.ReadBytes(4); long qt_matrixU = bitstream.ReadBytes(4); long qt_matrixC = bitstream.ReadBytes(4); long qt_matrixD = bitstream.ReadBytes(4); long qt_matrixV = bitstream.ReadBytes(4); long qt_matrixX = bitstream.ReadBytes(4); long qt_matrixY = bitstream.ReadBytes(4); long qt_matrixW = bitstream.ReadBytes(4); long qt_previewTime = bitstream.ReadBytes(4); long qt_previewDuration = bitstream.ReadBytes(4); long qt_posterTime = bitstream.ReadBytes(4); long qt_selectionTime = bitstream.ReadBytes(4); long qt_selectionDuration = bitstream.ReadBytes(4); long qt_currentTime = bitstream.ReadBytes(4); long nextTrackID = bitstream.ReadBytes(4); _bytesRead += 80; return(_bytesRead); }
/// <summary> /// Constructs an Atom object from the data in the bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The constructed atom.</returns> public static Mp4Atom CreateAtom(Mp4DataStream bitstream) { String uuid = null; long size = bitstream.ReadBytes(4); if (size == 0) { throw new IOException("Invalid size"); } int type = (int)bitstream.ReadBytes(4); long bytesRead = 8; if (type == MP4ExtendedAtomType) { uuid = bitstream.ReadString(16); bytesRead += 16; } // large size if (size == 1) { size = bitstream.ReadBytes(8); bytesRead += 8; } Mp4Atom atom = new Mp4Atom(size, type, uuid, bytesRead); if ((type == MP4MediaAtomType) || (type == MP4DataInformationAtomType) || (type == MP4MovieAtomType) || (type == MP4MediaInformationAtomType) || (type == MP4SampleTableAtomType) || (type == MP4TrackAtomType)) { bytesRead = atom.create_composite_atom(bitstream); } else if (type == MP4AudioSampleEntryAtomType) { bytesRead = atom.create_audio_sample_entry_atom(bitstream); } else if (type == MP4ChunkLargeOffsetAtomType) { bytesRead = atom.create_chunk_large_offset_atom(bitstream); } else if (type == MP4ChunkOffsetAtomType) { bytesRead = atom.create_chunk_offset_atom(bitstream); } else if (type == MP4HandlerAtomType) { bytesRead = atom.create_handler_atom(bitstream); } else if (type == MP4MediaHeaderAtomType) { bytesRead = atom.create_media_header_atom(bitstream); } else if (type == MP4MovieHeaderAtomType) { bytesRead = atom.create_movie_header_atom(bitstream); } else if (type == MP4SampleDescriptionAtomType) { bytesRead = atom.create_sample_description_atom(bitstream); } else if (type == MP4SampleSizeAtomType) { bytesRead = atom.create_sample_size_atom(bitstream); } else if (type == MP4CompactSampleSizeAtomType) { bytesRead = atom.create_compact_sample_size_atom(bitstream); } else if (type == MP4SampleToChunkAtomType) { bytesRead = atom.create_sample_to_chunk_atom(bitstream); } else if (type == MP4SyncSampleAtomType) { bytesRead = atom.create_sync_sample_atom(bitstream); } else if (type == MP4TimeToSampleAtomType) { bytesRead = atom.create_time_to_sample_atom(bitstream); } else if (type == MP4SoundMediaHeaderAtomType) { bytesRead = atom.create_sound_media_header_atom(bitstream); } else if (type == MP4TrackHeaderAtomType) { bytesRead = atom.create_track_header_atom(bitstream); } else if (type == MP4VideoMediaHeaderAtomType) { bytesRead = atom.create_video_media_header_atom(bitstream); } else if (type == MP4VisualSampleEntryAtomType) { bytesRead = atom.create_visual_sample_entry_atom(bitstream); } else if (type == MP4VideoSampleEntryAtomType) { bytesRead = atom.create_video_sample_entry_atom(bitstream); } else if (type == MP4ESDAtomType) { bytesRead = atom.create_esd_atom(bitstream); } else if (type == MP4AVCAtomType) { bytesRead = atom.create_avc_config_atom(bitstream); } else if (type == MP4PixelAspectAtomType) { bytesRead = atom.create_pasp_atom(bitstream); } #if !SILVERLIGHT log.Debug(string.Format("Atom: type = {0} size = {1}", IntToType(type), size)); #endif bitstream.SkipBytes(size - bytesRead); return(atom); }
/// <summary> /// Loads ChunkOffset atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_chunk_offset_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); _bytesRead += 4; for (int i = 0; i < entryCount; i++) { long chunkOffset = bitstream.ReadBytes(4); chunks.Add(chunkOffset); _bytesRead += 4; } return _bytesRead; }
/// <summary> /// Loads AVCC atom from the input bitstream. /// <para> /// 8+ bytes ISO/IEC 14496-10 or 3GPP AVC decode config box /// = long unsigned offset + long ASCII text string 'avcC' /// -> 1 byte version = 8-bit hex version (current = 1) /// -> 1 byte H.264 profile = 8-bit unsigned stream profile /// -> 1 byte H.264 compatible profiles = 8-bit hex flags /// -> 1 byte H.264 level = 8-bit unsigned stream level /// -> 1 1/2 nibble reserved = 6-bit unsigned value set to 63 /// -> 1/2 nibble NAL length = 2-bit length byte size type /// - 1 byte = 0 ; 2 bytes = 1 ; 4 bytes = 3 /// -> 1 byte number of SPS = 8-bit unsigned total /// -> 2+ bytes SPS length = short unsigned length /// -> + SPS NAL unit = hexdump /// -> 1 byte number of PPS = 8-bit unsigned total /// -> 2+ bytes PPS length = short unsigned length /// -> + PPS NAL unit = hexdump /// </para> /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_avc_config_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("AVC config"); log.Debug(string.Format("Offset: {0}", bitstream.Offset)); #endif //store the decoder config bytes videoConfigBytes = new byte[(int)_size]; for (int b = 0; b < videoConfigBytes.Length; b++) { videoConfigBytes[b] = (byte)bitstream.ReadBytes(1); switch (b) { //0 / version case 1: //profile avcProfile = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("AVC profile: {0}", avcProfile)); #endif break; case 2: //compatible profile int avcCompatProfile = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("AVC compatible profile: {0}", avcCompatProfile)); #endif break; case 3: //avc level avcLevel = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("AVC level: {0}", avcLevel)); #endif break; case 4: //NAL length break; case 5: //SPS number int numberSPS = videoConfigBytes[b]; #if !SILVERLIGHT log.Debug(string.Format("Number of SPS: {0}", numberSPS)); #endif break; default: break; } _bytesRead++; } return _bytesRead; }
/// <summary> /// Loads MP4VisualSampleEntryAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_visual_sample_entry_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Visual entry atom contains wxh"); #endif bitstream.SkipBytes(24); width = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Width: {0}", width)); #endif height = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Height: {0}", height)); #endif bitstream.SkipBytes(50); _bytesRead += 78; Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; return _bytesRead; }
/// <summary> /// Loads MP4TrackHeaderAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_track_header_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); #if !SILVERLIGHT log.Debug(string.Format("Version: {0}", version)); #endif if (version == 1) { creationTime = createDate(bitstream.ReadBytes(8)); modificationTime = createDate(bitstream.ReadBytes(8)); trackId = bitstream.ReadBytes(4); bitstream.SkipBytes(4); duration = bitstream.ReadBytes(8); _bytesRead += 32; } else { creationTime = createDate(bitstream.ReadBytes(4)); modificationTime = createDate(bitstream.ReadBytes(4)); trackId = bitstream.ReadBytes(4); bitstream.SkipBytes(4); duration = bitstream.ReadBytes(4); _bytesRead += 20; } bitstream.SkipBytes(8); //reserved by Apple int qt_layer = (int)bitstream.ReadBytes(2); int qt_alternateGroup = (int)bitstream.ReadBytes(2); int qt_volume = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Volume: {0}", qt_volume)); #endif bitstream.SkipBytes(2); //reserved by Apple long qt_matrixA = bitstream.ReadBytes(4); long qt_matrixB = bitstream.ReadBytes(4); long qt_matrixU = bitstream.ReadBytes(4); long qt_matrixC = bitstream.ReadBytes(4); long qt_matrixD = bitstream.ReadBytes(4); long qt_matrixV = bitstream.ReadBytes(4); long qt_matrixX = bitstream.ReadBytes(4); long qt_matrixY = bitstream.ReadBytes(4); long qt_matrixW = bitstream.ReadBytes(4); qt_trackWidth = (int)bitstream.ReadBytes(4); width = (qt_trackWidth >> 16); qt_trackHeight = (int)bitstream.ReadBytes(4); height = (qt_trackHeight >> 16); _bytesRead += 60; return _bytesRead; }
/// <summary> /// Loads MP4TimeToSampleAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_time_to_sample_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Time to sample atom"); #endif create_full_atom(bitstream); entryCount = (int)bitstream.ReadBytes(4); #if !SILVERLIGHT log.Debug(string.Format("Time to sample entries: {0}", entryCount)); #endif _bytesRead += 4; for (int i = 0; i < entryCount; i++) { int sampleCount = (int)bitstream.ReadBytes(4); int sampleDuration = (int)bitstream.ReadBytes(4); //log.trace("Sync entry: {}", sample); timeToSamplesRecords.Add(new TimeSampleRecord(sampleCount, sampleDuration)); _bytesRead += 8; } return _bytesRead; }
/// <summary> /// Loads MediaHeader atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_media_header_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); if (version == 1) { creationTime = createDate(bitstream.ReadBytes(8)); modificationTime = createDate(bitstream.ReadBytes(8)); timeScale = (int)bitstream.ReadBytes(4); duration = bitstream.ReadBytes(8); _bytesRead += 28; } else { creationTime = createDate(bitstream.ReadBytes(4)); modificationTime = createDate(bitstream.ReadBytes(4)); timeScale = (int)bitstream.ReadBytes(4); duration = bitstream.ReadBytes(4); _bytesRead += 16; } int packedLanguage = (int)bitstream.ReadBytes(2); int qt_quality = (int)bitstream.ReadBytes(2); _bytesRead += 4; return _bytesRead; }
/// <summary> /// Loads MP4SoundMediaHeaderAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_sound_media_header_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); balance = (int)bitstream.ReadBytes(2); bitstream.SkipBytes(2); _bytesRead += 4; return _bytesRead; }
/// <summary> /// Loads MP4TrackHeaderAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_track_header_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); #if !SILVERLIGHT log.Debug(string.Format("Version: {0}", version)); #endif if (version == 1) { creationTime = createDate(bitstream.ReadBytes(8)); modificationTime = createDate(bitstream.ReadBytes(8)); trackId = bitstream.ReadBytes(4); bitstream.SkipBytes(4); duration = bitstream.ReadBytes(8); _bytesRead += 32; } else { creationTime = createDate(bitstream.ReadBytes(4)); modificationTime = createDate(bitstream.ReadBytes(4)); trackId = bitstream.ReadBytes(4); bitstream.SkipBytes(4); duration = bitstream.ReadBytes(4); _bytesRead += 20; } bitstream.SkipBytes(8); //reserved by Apple int qt_layer = (int)bitstream.ReadBytes(2); int qt_alternateGroup = (int)bitstream.ReadBytes(2); int qt_volume = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Volume: {0}", qt_volume)); #endif bitstream.SkipBytes(2); //reserved by Apple long qt_matrixA = bitstream.ReadBytes(4); long qt_matrixB = bitstream.ReadBytes(4); long qt_matrixU = bitstream.ReadBytes(4); long qt_matrixC = bitstream.ReadBytes(4); long qt_matrixD = bitstream.ReadBytes(4); long qt_matrixV = bitstream.ReadBytes(4); long qt_matrixX = bitstream.ReadBytes(4); long qt_matrixY = bitstream.ReadBytes(4); long qt_matrixW = bitstream.ReadBytes(4); qt_trackWidth = (int)bitstream.ReadBytes(4); width = (qt_trackWidth >> 16); qt_trackHeight = (int)bitstream.ReadBytes(4); height = (qt_trackHeight >> 16); _bytesRead += 60; return(_bytesRead); }
/// <summary> /// Loads MP4VideoMediaHeaderAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_video_media_header_atom(Mp4DataStream bitstream) { create_full_atom(bitstream); if ((_size - _bytesRead) == 8) { graphicsMode = (int)bitstream.ReadBytes(2); opColorRed = (int)bitstream.ReadBytes(2); opColorGreen = (int)bitstream.ReadBytes(2); opColorBlue = (int)bitstream.ReadBytes(2); _bytesRead += 8; } return _bytesRead; }
/// <summary> /// Constructs an Atom object from the data in the bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The constructed atom.</returns> public static Mp4Atom CreateAtom(Mp4DataStream bitstream) { String uuid = null; long size = bitstream.ReadBytes(4); if (size == 0) { throw new IOException("Invalid size"); } int type = (int)bitstream.ReadBytes(4); long bytesRead = 8; if (type == MP4ExtendedAtomType) { uuid = bitstream.ReadString(16); bytesRead += 16; } // large size if (size == 1) { size = bitstream.ReadBytes(8); bytesRead += 8; } Mp4Atom atom = new Mp4Atom(size, type, uuid, bytesRead); if ((type == MP4MediaAtomType) || (type == MP4DataInformationAtomType) || (type == MP4MovieAtomType) || (type == MP4MediaInformationAtomType) || (type == MP4SampleTableAtomType) || (type == MP4TrackAtomType)) { bytesRead = atom.create_composite_atom(bitstream); } else if (type == MP4AudioSampleEntryAtomType) { bytesRead = atom.create_audio_sample_entry_atom(bitstream); } else if (type == MP4ChunkLargeOffsetAtomType) { bytesRead = atom.create_chunk_large_offset_atom(bitstream); } else if (type == MP4ChunkOffsetAtomType) { bytesRead = atom.create_chunk_offset_atom(bitstream); } else if (type == MP4HandlerAtomType) { bytesRead = atom.create_handler_atom(bitstream); } else if (type == MP4MediaHeaderAtomType) { bytesRead = atom.create_media_header_atom(bitstream); } else if (type == MP4MovieHeaderAtomType) { bytesRead = atom.create_movie_header_atom(bitstream); } else if (type == MP4SampleDescriptionAtomType) { bytesRead = atom.create_sample_description_atom(bitstream); } else if (type == MP4SampleSizeAtomType) { bytesRead = atom.create_sample_size_atom(bitstream); } else if (type == MP4CompactSampleSizeAtomType) { bytesRead = atom.create_compact_sample_size_atom(bitstream); } else if (type == MP4SampleToChunkAtomType) { bytesRead = atom.create_sample_to_chunk_atom(bitstream); } else if (type == MP4SyncSampleAtomType) { bytesRead = atom.create_sync_sample_atom(bitstream); } else if (type == MP4TimeToSampleAtomType) { bytesRead = atom.create_time_to_sample_atom(bitstream); } else if (type == MP4SoundMediaHeaderAtomType) { bytesRead = atom.create_sound_media_header_atom(bitstream); } else if (type == MP4TrackHeaderAtomType) { bytesRead = atom.create_track_header_atom(bitstream); } else if (type == MP4VideoMediaHeaderAtomType) { bytesRead = atom.create_video_media_header_atom(bitstream); } else if (type == MP4VisualSampleEntryAtomType) { bytesRead = atom.create_visual_sample_entry_atom(bitstream); } else if (type == MP4VideoSampleEntryAtomType) { bytesRead = atom.create_video_sample_entry_atom(bitstream); } else if (type == MP4ESDAtomType) { bytesRead = atom.create_esd_atom(bitstream); } else if (type == MP4AVCAtomType) { bytesRead = atom.create_avc_config_atom(bitstream); } else if (type == MP4PixelAspectAtomType) { bytesRead = atom.create_pasp_atom(bitstream); } #if !SILVERLIGHT log.Debug(string.Format("Atom: type = {0} size = {1}", IntToType(type), size)); #endif bitstream.SkipBytes(size - bytesRead); return atom; }
/// <summary> /// Loads MP4VideoSampleEntryAtom atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_video_sample_entry_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Video entry atom contains wxh"); #endif bitstream.SkipBytes(6); int dataReferenceIndex = (int)bitstream.ReadBytes(2); bitstream.SkipBytes(2); bitstream.SkipBytes(2); bitstream.SkipBytes(12); width = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Width: {0}", width)); #endif height = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Height: {0}", height)); #endif int horizontalRez = (int)bitstream.ReadBytes(4) >> 16; #if !SILVERLIGHT log.Debug(string.Format("H Resolution: {0}", horizontalRez)); #endif int verticalRez = (int)bitstream.ReadBytes(4) >> 16; #if !SILVERLIGHT log.Debug(string.Format("V Resolution: {0}", verticalRez)); #endif bitstream.SkipBytes(4); int frameCount = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Frame to sample count: {0}", frameCount)); #endif int stringLen = (int)bitstream.ReadBytes(1); #if !SILVERLIGHT log.Debug(string.Format("String length (cpname): {0}", stringLen)); #endif String compressorName = bitstream.ReadString(31); #if !SILVERLIGHT log.Debug(string.Format("Compressor name: {0}", compressorName.Trim())); #endif int depth = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Depth: {0}", depth)); #endif bitstream.SkipBytes(2); _bytesRead += 78; #if !SILVERLIGHT log.Debug(string.Format("Bytes read: {0}", _bytesRead)); #endif Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; return _bytesRead; }
/// <summary> /// Loads the version of the full atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_full_atom(Mp4DataStream bitstream) { long value = bitstream.ReadBytes(4); version = (int)value >> 24; flags = (int)value & 0xffffff; _bytesRead += 4; return _bytesRead; }
/// <summary> /// Creates the PASP atom or Pixel Aspect Ratio. It is created by Quicktime /// when exporting an MP4 file. The atom is required for ipod's and acts as /// a container for the avcC atom in these cases. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_pasp_atom(Mp4DataStream bitstream) { #if !SILVERLIGHT log.Debug("Pixel aspect ratio"); #endif int hSpacing = (int)bitstream.ReadBytes(4); int vSpacing = (int)bitstream.ReadBytes(4); #if !SILVERLIGHT log.Debug(string.Format("hSpacing: {0} vSpacing: {1}", hSpacing, vSpacing)); #endif _bytesRead += 8; Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; return _bytesRead; }
/// <summary> /// Loads AudioSampleEntry atom from the input bitstream. /// </summary> /// <param name="bitstream">The input bitstream.</param> /// <returns>The number of bytes loaded.</returns> public long create_audio_sample_entry_atom(Mp4DataStream bitstream) { //qtff page 117 #if !SILVERLIGHT log.Debug("Audio sample entry"); #endif bitstream.SkipBytes(6); int dataReferenceIndex = (int)bitstream.ReadBytes(2); bitstream.SkipBytes(8); channelCount = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Channels: {0}", channelCount)); #endif sampleSize = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Sample size (bits): {0}", sampleSize)); #endif bitstream.SkipBytes(4); timeScale = (int)bitstream.ReadBytes(2); #if !SILVERLIGHT log.Debug(string.Format("Time scale: {0}", timeScale)); #endif bitstream.SkipBytes(2); _bytesRead += 28; Mp4Atom child = Mp4Atom.CreateAtom(bitstream); _children.Add(child); _bytesRead += child.Size; return _bytesRead; }