move ParseAVCDecoderConfRecord() from mp4 package to here
This commit is contained in:
parent
b58d9c03fc
commit
cb4f07abc0
@ -3,6 +3,8 @@ package h264parser
|
||||
|
||||
import (
|
||||
"github.com/nareix/bits"
|
||||
"fmt"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -280,3 +282,359 @@ func SplitNALUs(b []byte) (nalus [][]byte, ok bool) {
|
||||
return [][]byte{b}, false
|
||||
}
|
||||
|
||||
type SPSInfo struct {
|
||||
ProfileIdc uint
|
||||
LevelIdc uint
|
||||
|
||||
MbWidth uint
|
||||
MbHeight uint
|
||||
|
||||
CropLeft uint
|
||||
CropRight uint
|
||||
CropTop uint
|
||||
CropBottom uint
|
||||
|
||||
Width uint
|
||||
Height uint
|
||||
}
|
||||
|
||||
func ParseSPS(data []byte) (self SPSInfo, err error) {
|
||||
r := &bits.GolombBitReader{
|
||||
R: bytes.NewReader(data),
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
func MakeAVCDecoderConfRecord(
|
||||
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
|
||||
}
|
||||
*/
|
||||
|
||||
type CodecInfo struct {
|
||||
Record AVCDecoderConfRecord
|
||||
SPSInfo SPSInfo
|
||||
}
|
||||
|
||||
// CodecData is AVCDecoderConfRecord
|
||||
func ParseCodecData(config []byte) (info CodecInfo, err error) {
|
||||
if info.Record, err = ParseAVCDecoderConfRecord(config); err != nil {
|
||||
return
|
||||
}
|
||||
if len(info.Record.SPS) < 1 {
|
||||
err = fmt.Errorf("CodecData invalid: no SPS found in AVCDecoderConfRecord")
|
||||
return
|
||||
}
|
||||
if info.SPSInfo, err = ParseSPS(info.Record.SPS[0]); err != nil {
|
||||
err = fmt.Errorf("CodecData invalid: parse SPS failed(%s)", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type AVCDecoderConfRecord struct {
|
||||
AVCProfileIndication uint
|
||||
ProfileCompatibility uint
|
||||
AVCLevelIndication uint
|
||||
LengthSizeMinusOne uint
|
||||
SPS [][]byte
|
||||
PPS [][]byte
|
||||
}
|
||||
|
||||
func ParseAVCDecoderConfRecord(config []byte) (self AVCDecoderConfRecord, err error) {
|
||||
r := bytes.NewReader(config)
|
||||
|
||||
if _, err = bits.ReadUIntBE(r, 8); err != nil {
|
||||
return
|
||||
}
|
||||
if self.AVCProfileIndication, err = bits.ReadUIntBE(r, 8); err != nil {
|
||||
return
|
||||
}
|
||||
if self.ProfileCompatibility, err = bits.ReadUIntBE(r, 8); err != nil {
|
||||
return
|
||||
}
|
||||
if self.AVCLevelIndication, err = bits.ReadUIntBE(r, 8); err != nil {
|
||||
return
|
||||
}
|
||||
if self.LengthSizeMinusOne, err = bits.ReadUIntBE(r, 8); err != nil {
|
||||
return
|
||||
}
|
||||
self.LengthSizeMinusOne &= 0x03
|
||||
|
||||
var u uint
|
||||
var n, length int
|
||||
var data []byte
|
||||
|
||||
if u, err = bits.ReadUIntBE(r, 8); err != nil {
|
||||
return
|
||||
}
|
||||
n = int(u&0x1f)
|
||||
for i := 0; i < n; i++ {
|
||||
if u, err = bits.ReadUIntBE(r, 16); err != nil {
|
||||
return
|
||||
}
|
||||
length = int(u)
|
||||
if data, err = bits.ReadBytes(r, length); err != nil {
|
||||
return
|
||||
}
|
||||
self.SPS = append(self.SPS, data)
|
||||
}
|
||||
|
||||
if u, err = bits.ReadUIntBE(r, 8); err != nil {
|
||||
return
|
||||
}
|
||||
n = int(u)
|
||||
for i := 0; i < n; i++ {
|
||||
if u, err = bits.ReadUIntBE(r, 16); err != nil {
|
||||
return
|
||||
}
|
||||
length = int(u)
|
||||
if data, err = bits.ReadBytes(r, length); err != nil {
|
||||
return
|
||||
}
|
||||
self.PPS = append(self.PPS, data)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user