Clarified reciprocal framerate / timebase usage
This commit is contained in:
parent
3c10219a47
commit
f37c92e58d
|
@ -71,9 +71,9 @@ func NewDecoder(r io.Reader, settings map[string]any) (d *Decoder, err error) {
|
||||||
PixelAspectRatio: fP.PixelAspectRatio,
|
PixelAspectRatio: fP.PixelAspectRatio,
|
||||||
ColorSpace: fP.ColorSpace,
|
ColorSpace: fP.ColorSpace,
|
||||||
FrameRate: utilities.Ratio{
|
FrameRate: utilities.Ratio{
|
||||||
Numerator: int(d.h.TimebaseDenominator),
|
Numerator: int(d.h.TimebaseNumerator),
|
||||||
Denominator: int(d.h.TimebaseNumerator),
|
Denominator: int(d.h.TimebaseDenominator),
|
||||||
},
|
}.Reciprocal(),
|
||||||
FullColorRange: fP.FullColorRange,
|
FullColorRange: fP.FullColorRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ type Encoder struct {
|
||||||
cfg C.aom_codec_enc_cfg_t
|
cfg C.aom_codec_enc_cfg_t
|
||||||
codec C.aom_codec_ctx_t
|
codec C.aom_codec_ctx_t
|
||||||
raw *C.aom_image_t
|
raw *C.aom_image_t
|
||||||
|
frames uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
var libaomVersion = "libaom-av1 " + C.GoString(C.aom_codec_version_str())
|
var libaomVersion = "libaom-av1 " + C.GoString(C.aom_codec_version_str())
|
||||||
|
@ -116,8 +117,23 @@ func NewEncoder(w io.Writer, properties frame.StreamProperties, settings map[str
|
||||||
|
|
||||||
e.cfg.g_w = C.uint(properties.Width)
|
e.cfg.g_w = C.uint(properties.Width)
|
||||||
e.cfg.g_h = C.uint(properties.Height)
|
e.cfg.g_h = C.uint(properties.Height)
|
||||||
e.cfg.g_timebase.num = C.int(properties.FrameRate.Denominator)
|
|
||||||
e.cfg.g_timebase.den = C.int(properties.FrameRate.Numerator)
|
/*!\brief Stream timebase units
|
||||||
|
*
|
||||||
|
* Indicates the smallest interval of time, in seconds, used by the stream.
|
||||||
|
* For fixed frame rate material, or variable frame rate material where
|
||||||
|
* frames are timed at a multiple of a given clock (ex: video capture),
|
||||||
|
* the \ref RECOMMENDED method is to set the timebase to the reciprocal
|
||||||
|
* of the frame rate (ex: 1001/30000 for 29.970 Hz NTSC). This allows the
|
||||||
|
* pts to correspond to the frame number, which can be handy. For
|
||||||
|
* re-encoding video from containers with absolute time timestamps, the
|
||||||
|
* \ref RECOMMENDED method is to set the timebase to that of the parent
|
||||||
|
* container or multimedia framework (ex: 1/1000 for ms, as in FLV).
|
||||||
|
*/
|
||||||
|
reciprocalFrameRate := properties.FrameRate.Reciprocal()
|
||||||
|
|
||||||
|
e.cfg.g_timebase.num = C.int(reciprocalFrameRate.Numerator)
|
||||||
|
e.cfg.g_timebase.den = C.int(reciprocalFrameRate.Denominator)
|
||||||
|
|
||||||
e.cfg.g_threads = C.uint(getSettingInt(settings, "threads", int(e.cfg.g_threads)))
|
e.cfg.g_threads = C.uint(getSettingInt(settings, "threads", int(e.cfg.g_threads)))
|
||||||
e.cfg.g_lag_in_frames = C.uint(getSettingInt(settings, "lag-in-frames", int(e.cfg.g_lag_in_frames)))
|
e.cfg.g_lag_in_frames = C.uint(getSettingInt(settings, "lag-in-frames", int(e.cfg.g_lag_in_frames)))
|
||||||
|
@ -193,7 +209,7 @@ func NewEncoder(w io.Writer, properties frame.StreamProperties, settings map[str
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if e.w, err = obuwriter.NewWriter(w, properties.Width, properties.Height, 0x31305641, properties.FrameRate); err != nil {
|
if e.w, err = obuwriter.NewWriter(w, properties.Width, properties.Height, 0x31305641, reciprocalFrameRate); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +249,8 @@ func (e *Encoder) Encode(f frame.Frame) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.frames++
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +302,7 @@ func (e *Encoder) Flush() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = e.w.WriteLength()
|
_ = e.w.WriteLength(e.frames)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
frames uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWriter(w io.Writer, width, height int, fourCC uint32, frameRate utilities.Ratio) (*Writer, error) {
|
func NewWriter(w io.Writer, width, height int, fourCC uint32, timeBase utilities.Ratio) (*Writer, error) {
|
||||||
if err := binary.Write(w, binary.LittleEndian, struct {
|
if err := binary.Write(w, binary.LittleEndian, struct {
|
||||||
Magic [4]byte
|
Magic [4]byte
|
||||||
Version uint16
|
Version uint16
|
||||||
|
@ -31,8 +30,8 @@ func NewWriter(w io.Writer, width, height int, fourCC uint32, frameRate utilitie
|
||||||
FourCC: fourCC,
|
FourCC: fourCC,
|
||||||
Width: uint16(width),
|
Width: uint16(width),
|
||||||
Height: uint16(height),
|
Height: uint16(height),
|
||||||
Denominator: uint32(frameRate.Numerator),
|
Denominator: uint32(timeBase.Denominator),
|
||||||
Numerator: uint32(frameRate.Denominator),
|
Numerator: uint32(timeBase.Numerator),
|
||||||
Length: 0,
|
Length: 0,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -52,20 +51,18 @@ func (w *Writer) WriteFrameBytes(pts uint64, data []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.frames++
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteLength writes the Length field for number of frames, if writer was set to io.WriteSeeker
|
// WriteLength writes the Length field for number of frames, if writer was set to io.WriteSeeker
|
||||||
func (w *Writer) WriteLength() error {
|
func (w *Writer) WriteLength(frames uint32) error {
|
||||||
if seeker, ok := w.w.(io.WriteSeeker); ok {
|
if seeker, ok := w.w.(io.WriteSeeker); ok {
|
||||||
if currentIndex, err := seeker.Seek(0, io.SeekCurrent); err != nil {
|
if currentIndex, err := seeker.Seek(0, io.SeekCurrent); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
if _, err = seeker.Seek(4+2+2+4+2+2+4+4, io.SeekStart); err != nil {
|
if _, err = seeker.Seek(4+2+2+4+2+2+4+4, io.SeekStart); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if err = binary.Write(w.w, binary.LittleEndian, w.frames); err != nil {
|
} else if err = binary.Write(w.w, binary.LittleEndian, frames); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if _, err = seeker.Seek(currentIndex, io.SeekStart); err != nil {
|
} else if _, err = seeker.Seek(currentIndex, io.SeekStart); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -14,3 +14,8 @@ func (r Ratio) Float64() float64 {
|
||||||
func (r Ratio) String() string {
|
func (r Ratio) String() string {
|
||||||
return fmt.Sprintf("%d:%d", r.Numerator, r.Denominator)
|
return fmt.Sprintf("%d:%d", r.Numerator, r.Denominator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reciprocal get the reciprocal, for example, to convert frame rate into time base
|
||||||
|
func (r Ratio) Reciprocal() Ratio {
|
||||||
|
return Ratio{Numerator: r.Denominator, Denominator: r.Numerator}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue