From 2ffa926532acdd24cc5d47cab3e6f6443a38a3cb Mon Sep 17 00:00:00 2001 From: nareix Date: Tue, 19 Apr 2016 18:45:32 +0800 Subject: [PATCH] many modifications to change to new api --- atom/genStruct.js | 2 +- atom/otherStruct.go | 347 +------------------------------------------- atom/struct.go | 25 ++-- atom/utils.go | 10 +- demuxer.go | 78 ++++++---- isom/isom.go | 312 +-------------------------------------- muxer.go | 7 +- stream.go | 41 ++++++ 8 files changed, 117 insertions(+), 705 deletions(-) create mode 100644 stream.go diff --git a/atom/genStruct.js b/atom/genStruct.js index 6a2122f..53c8b38 100644 --- a/atom/genStruct.js +++ b/atom/genStruct.js @@ -259,7 +259,7 @@ var atoms = { avc1Conf: { cc4: 'avcC', fields: [ - ['record', 'AVCDecoderConfRecord'], + ['data', '[]byte'], ], }, diff --git a/atom/otherStruct.go b/atom/otherStruct.go index 2c5d154..0652812 100644 --- a/atom/otherStruct.go +++ b/atom/otherStruct.go @@ -1,357 +1,12 @@ package atom import ( - "bytes" + _ "bytes" "fmt" "github.com/nareix/bits" "io" ) -type H264SPSInfo struct { - ProfileIdc uint - LevelIdc uint - - MbWidth uint - MbHeight uint - - CropLeft uint - CropRight uint - CropTop uint - CropBottom uint - - Width uint - Height uint -} - -func ParseH264SPS(data []byte) (res *H264SPSInfo, err error) { - r := &bits.GolombBitReader{ - R: bytes.NewReader(data), - } - - self := &H264SPSInfo{} - - if self.ProfileIdc, err = r.ReadBits(8); err != nil { - return - } - - // constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits - if _, err = r.ReadBits(8); err != nil { - return - } - - // level_idc - if self.LevelIdc, err = r.ReadBits(8); err != nil { - return - } - - // seq_parameter_set_id - if _, err = r.ReadExponentialGolombCode(); err != nil { - return - } - - if self.ProfileIdc == 100 || self.ProfileIdc == 110 || - self.ProfileIdc == 122 || self.ProfileIdc == 244 || - self.ProfileIdc == 44 || self.ProfileIdc == 83 || - self.ProfileIdc == 86 || self.ProfileIdc == 118 { - - var chroma_format_idc uint - if chroma_format_idc, err = r.ReadExponentialGolombCode(); err != nil { - return - } - - if chroma_format_idc == 3 { - // residual_colour_transform_flag - if _, err = r.ReadBit(); err != nil { - return - } - } - - // bit_depth_luma_minus8 - if _, err = r.ReadExponentialGolombCode(); err != nil { - return - } - // bit_depth_chroma_minus8 - if _, err = r.ReadExponentialGolombCode(); err != nil { - return - } - // qpprime_y_zero_transform_bypass_flag - if _, err = r.ReadBit(); err != nil { - return - } - - var seq_scaling_matrix_present_flag uint - if seq_scaling_matrix_present_flag, err = r.ReadBit(); err != nil { - return - } - - if seq_scaling_matrix_present_flag != 0 { - for i := 0; i < 8; i++ { - var seq_scaling_list_present_flag uint - if seq_scaling_list_present_flag, err = r.ReadBit(); err != nil { - return - } - if seq_scaling_list_present_flag != 0 { - var sizeOfScalingList uint - if i < 6 { - sizeOfScalingList = 16 - } else { - sizeOfScalingList = 64 - } - lastScale := uint(8) - nextScale := uint(8) - for j := uint(0); j < sizeOfScalingList; j++ { - if nextScale != 0 { - var delta_scale uint - if delta_scale, err = r.ReadSE(); err != nil { - return - } - nextScale = (lastScale + delta_scale + 256) % 256 - } - if nextScale != 0 { - lastScale = nextScale - } - } - } - } - } - } - - // log2_max_frame_num_minus4 - if _, err = r.ReadExponentialGolombCode(); err != nil { - return - } - - var pic_order_cnt_type uint - if pic_order_cnt_type, err = r.ReadExponentialGolombCode(); err != nil { - return - } - if pic_order_cnt_type == 0 { - // log2_max_pic_order_cnt_lsb_minus4 - if _, err = r.ReadExponentialGolombCode(); err != nil { - return - } - } else if pic_order_cnt_type == 1 { - // delta_pic_order_always_zero_flag - if _, err = r.ReadBit(); err != nil { - return - } - // offset_for_non_ref_pic - if _, err = r.ReadSE(); err != nil { - return - } - // offset_for_top_to_bottom_field - if _, err = r.ReadSE(); err != nil { - return - } - var num_ref_frames_in_pic_order_cnt_cycle uint - if num_ref_frames_in_pic_order_cnt_cycle, err = r.ReadExponentialGolombCode(); err != nil { - return - } - for i := uint(0); i < num_ref_frames_in_pic_order_cnt_cycle; i++ { - if _, err = r.ReadSE(); err != nil { - return - } - } - } - - // max_num_ref_frames - if _, err = r.ReadExponentialGolombCode(); err != nil { - return - } - - // gaps_in_frame_num_value_allowed_flag - if _, err = r.ReadBit(); err != nil { - return - } - - if self.MbWidth, err = r.ReadExponentialGolombCode(); err != nil { - return - } - self.MbWidth++ - - if self.MbHeight, err = r.ReadExponentialGolombCode(); err != nil { - return - } - self.MbHeight++ - - var frame_mbs_only_flag uint - if frame_mbs_only_flag, err = r.ReadBit(); err != nil { - return - } - if frame_mbs_only_flag == 0 { - // mb_adaptive_frame_field_flag - if _, err = r.ReadBit(); err != nil { - return - } - } - - // direct_8x8_inference_flag - if _, err = r.ReadBit(); err != nil { - return - } - - var frame_cropping_flag uint - if frame_cropping_flag, err = r.ReadBit(); err != nil { - return - } - if frame_cropping_flag != 0 { - if self.CropLeft, err = r.ReadExponentialGolombCode(); err != nil { - return - } - if self.CropRight, err = r.ReadExponentialGolombCode(); err != nil { - return - } - if self.CropTop, err = r.ReadExponentialGolombCode(); err != nil { - return - } - if self.CropBottom, err = r.ReadExponentialGolombCode(); err != nil { - return - } - } - - self.Width = (self.MbWidth * 16) - self.CropLeft*2 - self.CropRight*2 - self.Height = ((2 - frame_mbs_only_flag) * self.MbHeight * 16) - self.CropTop*2 - self.CropBottom*2 - - res = self - return -} - -type AVCDecoderConfRecord struct { - AVCProfileIndication int - ProfileCompatibility int - AVCLevelIndication int - LengthSizeMinusOne int - SPS [][]byte - PPS [][]byte -} - -func CreateAVCDecoderConfRecord( - SPS []byte, - PPS []byte, -) (self AVCDecoderConfRecord, err error) { - if len(SPS) < 4 { - err = fmt.Errorf("invalid SPS data") - return - } - self.AVCProfileIndication = int(SPS[1]) - self.ProfileCompatibility = int(SPS[2]) - self.AVCLevelIndication = int(SPS[3]) - self.SPS = [][]byte{SPS} - self.PPS = [][]byte{PPS} - self.LengthSizeMinusOne = 3 - return -} - -func WriteAVCDecoderConfRecord(w io.Writer, self AVCDecoderConfRecord) (err error) { - if err = WriteInt(w, 1, 1); err != nil { - return - } - if err = WriteInt(w, self.AVCProfileIndication, 1); err != nil { - return - } - if err = WriteInt(w, self.ProfileCompatibility, 1); err != nil { - return - } - if err = WriteInt(w, self.AVCLevelIndication, 1); err != nil { - return - } - if err = WriteInt(w, self.LengthSizeMinusOne|0xfc, 1); err != nil { - return - } - - if err = WriteInt(w, len(self.SPS)|0xe0, 1); err != nil { - return - } - for _, data := range self.SPS { - if err = WriteInt(w, len(data), 2); err != nil { - return - } - if err = WriteBytes(w, data, len(data)); err != nil { - return - } - } - - if err = WriteInt(w, len(self.PPS), 1); err != nil { - return - } - for _, data := range self.PPS { - if err = WriteInt(w, len(data), 2); err != nil { - return - } - if err = WriteBytes(w, data, len(data)); err != nil { - return - } - } - - return -} - -func WalkAVCDecoderConfRecord(w Walker, self AVCDecoderConfRecord) { -} - -func ReadAVCDecoderConfRecord(r *io.LimitedReader) (self AVCDecoderConfRecord, err error) { - if _, err = ReadDummy(r, 1); err != nil { - return - } - if self.AVCProfileIndication, err = ReadInt(r, 1); err != nil { - return - } - if self.ProfileCompatibility, err = ReadInt(r, 1); err != nil { - return - } - if self.AVCLevelIndication, err = ReadInt(r, 1); err != nil { - return - } - if self.LengthSizeMinusOne, err = ReadInt(r, 1); err != nil { - return - } - self.LengthSizeMinusOne &= 0x03 - - var n, length int - var data []byte - - if n, err = ReadInt(r, 1); err != nil { - return - } - n &= 0x1f - for i := 0; i < n; i++ { - if length, err = ReadInt(r, 2); err != nil { - return - } - if data, err = ReadBytes(r, length); err != nil { - return - } - self.SPS = append(self.SPS, data) - } - - if n, err = ReadInt(r, 1); err != nil { - return - } - for i := 0; i < n; i++ { - if length, err = ReadInt(r, 2); err != nil { - return - } - if data, err = ReadBytes(r, length); err != nil { - return - } - self.PPS = append(self.PPS, data) - } - - return -} - -func WriteSampleByNALU(w io.Writer, nalu []byte) (size int, err error) { - if err = WriteInt(w, len(nalu), 4); err != nil { - return - } - size += 4 - if _, err = w.Write(nalu); err != nil { - return - } - size += len(nalu) - return -} - const ( TFHD_BASE_DATA_OFFSET = 0x01 TFHD_STSD_ID = 0x02 diff --git a/atom/struct.go b/atom/struct.go index 985840a..bc49400 100644 --- a/atom/struct.go +++ b/atom/struct.go @@ -565,11 +565,11 @@ func WalkTrackHeader(w Walker, self *TrackHeader) { } type HandlerRefer struct { - Version int - Flags int - CodecType string - SubType string - Name string + Version int + Flags int + Type string + SubType string + Name string } func ReadHandlerRefer(r *io.LimitedReader) (res *HandlerRefer, err error) { @@ -581,7 +581,7 @@ func ReadHandlerRefer(r *io.LimitedReader) (res *HandlerRefer, err error) { if self.Flags, err = ReadInt(r, 3); err != nil { return } - if self.CodecType, err = ReadString(r, 4); err != nil { + if self.Type, err = ReadString(r, 4); err != nil { return } if self.SubType, err = ReadString(r, 4); err != nil { @@ -606,7 +606,7 @@ func WriteHandlerRefer(w io.WriteSeeker, self *HandlerRefer) (err error) { if err = WriteInt(w, self.Flags, 3); err != nil { return } - if err = WriteString(w, self.CodecType, 4); err != nil { + if err = WriteString(w, self.Type, 4); err != nil { return } if err = WriteString(w, self.SubType, 4); err != nil { @@ -628,7 +628,7 @@ func WalkHandlerRefer(w Walker, self *HandlerRefer) { w.Name("Flags") w.Int(self.Flags) w.Name("Type") - w.String(self.CodecType) + w.String(self.Type) w.Name("SubType") w.String(self.SubType) w.Name("Name") @@ -1874,13 +1874,13 @@ func WalkAvc1Desc(w Walker, self *Avc1Desc) { } type Avc1Conf struct { - Record AVCDecoderConfRecord + Data []byte } func ReadAvc1Conf(r *io.LimitedReader) (res *Avc1Conf, err error) { self := &Avc1Conf{} - if self.Record, err = ReadAVCDecoderConfRecord(r); err != nil { + if self.Data, err = ReadBytes(r, int(r.N)); err != nil { return } res = self @@ -1893,7 +1893,7 @@ func WriteAvc1Conf(w io.WriteSeeker, self *Avc1Conf) (err error) { return } w = aw - if err = WriteAVCDecoderConfRecord(w, self.Record); err != nil { + if err = WriteBytes(w, self.Data, len(self.Data)); err != nil { return } if err = aw.Close(); err != nil { @@ -1904,7 +1904,8 @@ func WriteAvc1Conf(w io.WriteSeeker, self *Avc1Conf) (err error) { func WalkAvc1Conf(w Walker, self *Avc1Conf) { w.StartStruct("Avc1Conf") - WalkAVCDecoderConfRecord(w, self.Record) + w.Name("Data") + w.Bytes(self.Data) w.EndStruct() return } diff --git a/atom/utils.go b/atom/utils.go index 3f16f8b..5c24473 100644 --- a/atom/utils.go +++ b/atom/utils.go @@ -1,14 +1,12 @@ package atom -func GetAVCDecoderConfRecordByTrack(stream *Track) (record *AVCDecoderConfRecord) { +func GetAvc1ConfByTrack(stream *Track) (avc1 *Avc1Conf) { if media := stream.Media; media != nil { if info := media.Info; info != nil { if sample := info.Sample; sample != nil { if desc := sample.SampleDesc; desc != nil { if avc1 := desc.Avc1Desc; avc1 != nil { - if conf := avc1.Conf; conf != nil { - return &conf.Record - } + return avc1.Conf } } } @@ -22,9 +20,7 @@ func GetMp4aDescByTrack(stream *Track) (mp4a *Mp4aDesc) { if info := media.Info; info != nil { if sample := info.Sample; sample != nil { if desc := sample.SampleDesc; desc != nil { - if mp4a = desc.Mp4aDesc; mp4a != nil { - return - } + return desc.Mp4aDesc } } } diff --git a/demuxer.go b/demuxer.go index 315c798..82f0b48 100644 --- a/demuxer.go +++ b/demuxer.go @@ -16,6 +16,13 @@ type Demuxer struct { movieAtom *atom.Movie } +func (self *Demuxer) Streams() (streams []av.Stream) { + for _, stream := range(self.streams) { + streams = append(streams, stream) + } + return +} + func (self *Demuxer) ReadHeader() (err error) { var N int64 var moov *atom.Movie @@ -54,10 +61,11 @@ func (self *Demuxer) ReadHeader() (err error) { self.movieAtom = moov self.streams = []*Stream{} - for _, atrack := range moov.Tracks { + for i, atrack := range moov.Tracks { stream := &Stream{ trackAtom: atrack, r: self.R, + idx: i, } if atrack.Media != nil && atrack.Media.Info != nil && atrack.Media.Info.Sample != nil { stream.sample = atrack.Media.Info.Sample @@ -66,21 +74,25 @@ func (self *Demuxer) ReadHeader() (err error) { err = fmt.Errorf("sample table not found") return } - if record := atom.GetAVCDecoderConfRecordByTrack(atrack); record != nil { - if len(record.PPS) > 0 { - stream.pps = record.PPS[0] - } - if len(record.SPS) > 0 { - stream.sps = record.SPS[0] - } + + if avc1 := atom.GetAvc1ConfByTrack(atrack); avc1 != nil { stream.SetType(av.H264) - self.streams = append(self.streams, stream) - } else if mp4a := atom.GetMp4aDescByTrack(atrack); mp4a != nil && mp4a.Conf != nil { - if config, err := isom.ReadElemStreamDescAAC(bytes.NewReader(mp4a.Conf.Data)); err == nil { - stream.mpeg4AudioConfig = config.Complete() - stream.SetType(av.AAC) - self.streams = append(self.streams, stream) + if err = stream.SetCodecData(avc1.Data); err != nil { + return } + self.streams = append(self.streams, stream) + + } else if mp4a := atom.GetMp4aDescByTrack(atrack); mp4a != nil && mp4a.Conf != nil { + stream.SetType(av.AAC) + var config []byte + if config, err = isom.ReadElemStreamDesc(bytes.NewReader(mp4a.Conf.Data)); err != nil { + return + } + if err = stream.SetCodecData(config); err != nil { + return + } + self.streams = append(self.streams, stream) + } } @@ -250,7 +262,7 @@ func (self *Stream) incSampleIndex() { self.sampleIndex++ } -func (self *Stream) SampleCount() int { +func (self *Stream) sampleCount() int { if self.sample.SampleSize.SampleSize == 0 { chunkGroupIndex := 0 count := 0 @@ -269,6 +281,23 @@ func (self *Stream) SampleCount() int { } func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) { + var choose *Stream + for _, stream := range(self.streams) { + if choose == nil || stream.dts < choose.dts { + choose = stream + } + } + pkt.StreamIdx = choose.idx + pkt.Pts, pkt.Dts, pkt.IsKeyFrame, pkt.Data, err = choose.readSample() + return +} + +func (self *Demuxer) SeekToTime(time float64) (err error) { + for _, stream := range(self.streams) { + if err = stream.seekToTime(time); err != nil { + return + } + } return } @@ -314,28 +343,20 @@ func (self *Stream) readSample() (pts int64, dts int64, isKeyFrame bool, data [] return } -func (self *Stream) Duration() float64 { +func (self *Stream) duration() float64 { total := int64(0) for _, entry := range self.sample.TimeToSample.Entries { total += int64(entry.Duration * entry.Count) } - return float64(total) / float64(self.trackAtom.Media.Header.TimeScale) + return float64(total) / float64(self.TimeScale()) } -func (self *Stream) CurSampleIndex() int { - return self.sampleIndex -} - -func (self *Stream) SeekToTime(time float64) error { - index := self.TimeToSampleIndex(time) +func (self *Stream) seekToTime(time float64) error { + index := self.timeToSampleIndex(time) return self.setSampleIndex(index) } -func (self *Stream) SeekToSampleIndex(index int) error { - return self.setSampleIndex(index) -} - -func (self *Stream) TimeToSampleIndex(time float64) int { +func (self *Stream) timeToSampleIndex(time float64) int { targetTs := self.TimeToTs(time) targetIndex := 0 @@ -374,3 +395,4 @@ func (self *Stream) TimeToSampleIndex(time float64) int { return targetIndex } + diff --git a/isom/isom.go b/isom/isom.go index f81e3af..c08d808 100644 --- a/isom/isom.go +++ b/isom/isom.go @@ -9,6 +9,7 @@ import ( ) // copied from libavformat/isom.h + const ( MP4ESDescrTag = 3 MP4DecConfigDescrTag = 4 @@ -18,295 +19,6 @@ const ( var debugReader = false var debugWriter = false -// copied from libavcodec/mpeg4audio.h -const ( - AOT_AAC_MAIN = 1 + iota ///< Y Main - AOT_AAC_LC ///< Y Low Complexity - AOT_AAC_SSR ///< N (code in SoC repo) Scalable Sample Rate - AOT_AAC_LTP ///< Y Long Term Prediction - AOT_SBR ///< Y Spectral Band Replication - AOT_AAC_SCALABLE ///< N Scalable - AOT_TWINVQ ///< N Twin Vector Quantizer - AOT_CELP ///< N Code Excited Linear Prediction - AOT_HVXC ///< N Harmonic Vector eXcitation Coding - AOT_TTSI = 12 + iota ///< N Text-To-Speech Interface - AOT_MAINSYNTH ///< N Main Synthesis - AOT_WAVESYNTH ///< N Wavetable Synthesis - AOT_MIDI ///< N General MIDI - AOT_SAFX ///< N Algorithmic Synthesis and Audio Effects - AOT_ER_AAC_LC ///< N Error Resilient Low Complexity - AOT_ER_AAC_LTP = 19 + iota ///< N Error Resilient Long Term Prediction - AOT_ER_AAC_SCALABLE ///< N Error Resilient Scalable - AOT_ER_TWINVQ ///< N Error Resilient Twin Vector Quantizer - AOT_ER_BSAC ///< N Error Resilient Bit-Sliced Arithmetic Coding - AOT_ER_AAC_LD ///< N Error Resilient Low Delay - AOT_ER_CELP ///< N Error Resilient Code Excited Linear Prediction - AOT_ER_HVXC ///< N Error Resilient Harmonic Vector eXcitation Coding - AOT_ER_HILN ///< N Error Resilient Harmonic and Individual Lines plus Noise - AOT_ER_PARAM ///< N Error Resilient Parametric - AOT_SSC ///< N SinuSoidal Coding - AOT_PS ///< N Parametric Stereo - AOT_SURROUND ///< N MPEG Surround - AOT_ESCAPE ///< Y Escape Value - AOT_L1 ///< Y Layer 1 - AOT_L2 ///< Y Layer 2 - AOT_L3 ///< Y Layer 3 - AOT_DST ///< N Direct Stream Transfer - AOT_ALS ///< Y Audio LosslesS - AOT_SLS ///< N Scalable LosslesS - AOT_SLS_NON_CORE ///< N Scalable LosslesS (non core) - AOT_ER_AAC_ELD ///< N Error Resilient Enhanced Low Delay - AOT_SMR_SIMPLE ///< N Symbolic Music Representation Simple - AOT_SMR_MAIN ///< N Symbolic Music Representation Main - AOT_USAC_NOSBR ///< N Unified Speech and Audio Coding (no SBR) - AOT_SAOC ///< N Spatial Audio Object Coding - AOT_LD_SURROUND ///< N Low Delay MPEG Surround - AOT_USAC ///< N Unified Speech and Audio Coding -) - -type MPEG4AudioConfig struct { - SampleRate int - ChannelCount int - ObjectType uint - SampleRateIndex uint - ChannelConfig uint -} - -var sampleRateTable = []int{ - 96000, 88200, 64000, 48000, 44100, 32000, - 24000, 22050, 16000, 12000, 11025, 8000, 7350, -} - -var chanConfigTable = []int{ - 0, 1, 2, 3, 4, 5, 6, 8, -} - -func IsADTSFrame(frames []byte) bool { - return len(frames) > 7 && frames[0] == 0xff && frames[1]&0xf0 == 0xf0 -} - -func ReadADTSFrame(frame []byte) (config MPEG4AudioConfig, payload []byte, samples int, framelen int, err error) { - if !IsADTSFrame(frame) { - err = fmt.Errorf("not adts frame") - return - } - config.ObjectType = uint(frame[2]>>6) + 1 - config.SampleRateIndex = uint(frame[2] >> 2 & 0xf) - config.ChannelConfig = uint(frame[2]<<2&0x4 | frame[3]>>6&0x3) - framelen = int(frame[3]&0x3)<<11 | int(frame[4])<<3 | int(frame[5]>>5) - samples = (int(frame[6]&0x3) + 1) * 1024 - hdrlen := 7 - if frame[1]&0x1 == 0 { - hdrlen = 9 - } - if framelen < hdrlen || len(frame) < framelen { - err = fmt.Errorf("invalid adts header length") - return - } - payload = frame[hdrlen:framelen] - return -} - -func MakeADTSHeader(config MPEG4AudioConfig, samples int, payloadLength int) (header []byte) { - payloadLength += 7 - //AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ) - header = []byte{0xff, 0xf1, 0x50, 0x80, 0x043, 0xff, 0xcd} - //config.ObjectType = uint(frames[2]>>6)+1 - //config.SampleRateIndex = uint(frames[2]>>2&0xf) - //config.ChannelConfig = uint(frames[2]<<2&0x4|frames[3]>>6&0x3) - header[2] = (byte(config.ObjectType-1)&0x3)<<6 | (byte(config.SampleRateIndex)&0xf)<<2 | byte(config.ChannelConfig>>2)&0x1 - header[3] = header[3]&0x3f | byte(config.ChannelConfig&0x3)<<6 - header[3] = header[3]&0xfc | byte(payloadLength>>11)&0x3 - header[4] = byte(payloadLength >> 3) - header[5] = header[5]&0x1f | (byte(payloadLength)&0x7)<<5 - header[6] = header[6]&0xfc | byte(samples/1024-1) - return -} - -func ExtractADTSFrames(frames []byte) (config MPEG4AudioConfig, payload []byte, samples int, err error) { - for len(frames) > 0 { - var n, framelen int - if config, payload, n, framelen, err = ReadADTSFrame(frames); err != nil { - return - } - frames = frames[framelen:] - samples += n - } - return -} - -func ReadADTSHeader(data []byte) (config MPEG4AudioConfig, frameLength int) { - br := &bits.Reader{R: bytes.NewReader(data)} - var i uint - - //Structure - //AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ) - //Header consists of 7 or 9 bytes (without or with CRC). - - // 2 bytes - //A 12 syncword 0xFFF, all bits must be 1 - br.ReadBits(12) - //B 1 MPEG Version: 0 for MPEG-4, 1 for MPEG-2 - br.ReadBits(1) - //C 2 Layer: always 0 - br.ReadBits(2) - //D 1 protection absent, Warning, set to 1 if there is no CRC and 0 if there is CRC - br.ReadBits(1) - - //E 2 profile, the MPEG-4 Audio Object Type minus 1 - config.ObjectType, _ = br.ReadBits(2) - config.ObjectType++ - //F 4 MPEG-4 Sampling Frequency Index (15 is forbidden) - config.SampleRateIndex, _ = br.ReadBits(4) - //G 1 private bit, guaranteed never to be used by MPEG, set to 0 when encoding, ignore when decoding - br.ReadBits(1) - //H 3 MPEG-4 Channel Configuration (in the case of 0, the channel configuration is sent via an inband PCE) - config.ChannelConfig, _ = br.ReadBits(3) - //I 1 originality, set to 0 when encoding, ignore when decoding - br.ReadBits(1) - //J 1 home, set to 0 when encoding, ignore when decoding - br.ReadBits(1) - //K 1 copyrighted id bit, the next bit of a centrally registered copyright identifier, set to 0 when encoding, ignore when decoding - br.ReadBits(1) - //L 1 copyright id start, signals that this frame's copyright id bit is the first bit of the copyright id, set to 0 when encoding, ignore when decoding - br.ReadBits(1) - - //M 13 frame length, this value must include 7 or 9 bytes of header length: FrameLength = (ProtectionAbsent == 1 ? 7 : 9) + size(AACFrame) - i, _ = br.ReadBits(13) - frameLength = int(i) - //O 11 Buffer fullness - br.ReadBits(11) - //P 2 Number of AAC frames (RDBs) in ADTS frame minus 1, for maximum compatibility always use 1 AAC frame per ADTS frame - br.ReadBits(2) - - //Q 16 CRC if protection absent is 0 - return -} - -func readObjectType(r *bits.Reader) (objectType uint, err error) { - if objectType, err = r.ReadBits(5); err != nil { - return - } - if objectType == AOT_ESCAPE { - var i uint - if i, err = r.ReadBits(6); err != nil { - return - } - objectType = 32 + i - } - return -} - -func writeObjectType(w *bits.Writer, objectType uint) (err error) { - if objectType >= 32 { - if err = w.WriteBits(AOT_ESCAPE, 5); err != nil { - return - } - if err = w.WriteBits(objectType-32, 6); err != nil { - return - } - } else { - if err = w.WriteBits(objectType, 5); err != nil { - return - } - } - return -} - -func readSampleRateIndex(r *bits.Reader) (index uint, err error) { - if index, err = r.ReadBits(4); err != nil { - return - } - if index == 0xf { - if index, err = r.ReadBits(24); err != nil { - return - } - } - return -} - -func writeSampleRateIndex(w *bits.Writer, index uint) (err error) { - if index >= 0xf { - if err = w.WriteBits(0xf, 4); err != nil { - return - } - if err = w.WriteBits(index, 24); err != nil { - return - } - } else { - if err = w.WriteBits(index, 4); err != nil { - return - } - } - return -} - -func (self MPEG4AudioConfig) IsValid() bool { - return self.ObjectType > 0 -} - -func (self MPEG4AudioConfig) Complete() (config MPEG4AudioConfig) { - config = self - if int(config.SampleRateIndex) < len(sampleRateTable) { - config.SampleRate = sampleRateTable[config.SampleRateIndex] - } - if int(config.ChannelConfig) < len(chanConfigTable) { - config.ChannelCount = chanConfigTable[config.ChannelConfig] - } - return -} - -// copied from libavcodec/mpeg4audio.c avpriv_mpeg4audio_get_config() -func ReadMPEG4AudioConfig(r io.Reader) (config MPEG4AudioConfig, err error) { - br := &bits.Reader{R: r} - - if config.ObjectType, err = readObjectType(br); err != nil { - return - } - if config.SampleRateIndex, err = readSampleRateIndex(br); err != nil { - return - } - if config.ChannelConfig, err = br.ReadBits(4); err != nil { - return - } - return -} - -func WriteMPEG4AudioConfig(w io.Writer, config MPEG4AudioConfig) (err error) { - bw := &bits.Writer{W: w} - - if err = writeObjectType(bw, config.ObjectType); err != nil { - return - } - - if config.SampleRateIndex == 0 { - for i, rate := range sampleRateTable { - if rate == config.SampleRate { - config.SampleRateIndex = uint(i) - } - } - } - if err = writeSampleRateIndex(bw, config.SampleRateIndex); err != nil { - return - } - - if config.ChannelConfig == 0 { - for i, count := range chanConfigTable { - if count == config.ChannelCount { - config.ChannelConfig = uint(i) - } - } - } - if err = bw.WriteBits(config.ChannelConfig, 4); err != nil { - return - } - - if err = bw.FlushBits(); err != nil { - return - } - return -} - func readDesc(r io.Reader) (tag uint, data []byte, err error) { if tag, err = bits.ReadUIntBE(r, 8); err != nil { return @@ -518,28 +230,12 @@ func ReadElemStreamDesc(r io.Reader) (decConfig []byte, err error) { return } -func ReadElemStreamDescAAC(r io.Reader) (config MPEG4AudioConfig, err error) { - var data []byte - if data, err = ReadElemStreamDesc(r); err != nil { - return - } - if debugReader { - println("decConfig: ", len(data)) - } - if config, err = ReadMPEG4AudioConfig(bytes.NewReader(data)); err != nil { - return - } - return -} - -func WriteElemStreamDescAAC(w io.Writer, config MPEG4AudioConfig, trackId uint) (err error) { +func WriteElemStreamDesc(w io.Writer, decConfig []byte, trackId uint) (err error) { // MP4ESDescrTag(ESDesc MP4DecConfigDescrTag(objectId streamType bufSize avgBitrate MP4DecSpecificDescrTag(decConfig))) - buf := &bytes.Buffer{} - WriteMPEG4AudioConfig(buf, config) - data := buf.Bytes() + data := decConfig - buf = &bytes.Buffer{} + buf := &bytes.Buffer{} // 0x40 = ObjectType AAC // 0x15 = Audiostream writeDecConfDesc(buf, 0x40, 0x15, data) diff --git a/muxer.go b/muxer.go index 2d9e2e5..6c5ad64 100644 --- a/muxer.go +++ b/muxer.go @@ -7,6 +7,7 @@ import ( "github.com/nareix/mp4/atom" "github.com/nareix/mp4/isom" "github.com/nareix/codec/h264parser" + "github.com/nareix/codec/aacparser" "io" ) @@ -148,12 +149,12 @@ func (self *Muxer) WriteSample(pkt av.Packet) (err error) { pts, dts, isKeyFrame, frame := pkt.Pts, pkt.Dts, pkt.IsKeyFrame, pkt.Data stream := self.streams[pkt.StreamIdx] - if stream.Type() == av.AAC && isom.IsADTSFrame(frame) { + if stream.Type() == av.AAC && aacparser.IsADTSFrame(frame) { for len(frame) > 0 { var payload []byte var samples int var framelen int - if _, payload, samples, framelen, err = isom.ReadADTSFrame(frame); err != nil { + if _, payload, samples, framelen, err = aacparser.ReadADTSFrame(frame); err != nil { return } delta := int64(samples) * stream.TimeScale() / int64(stream.SampleRate()) @@ -247,7 +248,7 @@ func (self *Muxer) WriteTrailer() (err error) { if err = stream.fillTrackAtom(); err != nil { return } - dur := stream.Duration() + dur := stream.duration() stream.trackAtom.Header.Duration = int(float64(timeScale) * dur) if dur > maxDur { maxDur = dur diff --git a/stream.go b/stream.go new file mode 100644 index 0000000..b1126b2 --- /dev/null +++ b/stream.go @@ -0,0 +1,41 @@ +package mp4 + +import ( + "github.com/nareix/av" + "github.com/nareix/mp4/atom" + "io" +) + +type Stream struct { + av.StreamCommon + + trackAtom *atom.Track + r io.ReadSeeker + idx int + + muxer *Muxer + + sample *atom.SampleTable + sampleIndex int + + sampleOffsetInChunk int64 + syncSampleIndex int + + dts int64 + sttsEntryIndex int + sampleIndexInSttsEntry int + + cttsEntryIndex int + sampleIndexInCttsEntry int + + chunkGroupIndex int + chunkIndex int + sampleIndexInChunk int + + sttsEntry *atom.TimeToSampleEntry + cttsEntry *atom.CompositionOffsetEntry + writeMdat func([]byte) (int64, error) + lastDts int64 +} + +