mirror of
https://github.com/3d0c/gmf
synced 2025-12-24 10:40:59 +08:00
fixes, frames interator, transcoder
This commit is contained in:
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 alex.s.contact@yandex.ru
|
||||
Copyright (c) 2013 Alex Parker(3d0c)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
5
codec.go
5
codec.go
@@ -17,8 +17,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
CODEC_TYPE_AUDIO int = C.AVMEDIA_TYPE_AUDIO
|
||||
CODEC_TYPE_VIDEO int = C.AVMEDIA_TYPE_VIDEO
|
||||
AVMEDIA_TYPE_AUDIO int32 = C.AVMEDIA_TYPE_AUDIO
|
||||
AVMEDIA_TYPE_VIDEO int32 = C.AVMEDIA_TYPE_VIDEO
|
||||
|
||||
AV_PIX_FMT_YUV420P int32 = C.AV_PIX_FMT_YUV420P
|
||||
FF_PROFILE_MPEG4_SIMPLE int = C.FF_PROFILE_MPEG4_SIMPLE
|
||||
AV_NOPTS_VALUE int = C.AV_NOPTS_VALUE
|
||||
|
||||
46
codecCtx.go
46
codecCtx.go
@@ -22,14 +22,15 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
AV_CODEC_ID_MPEG1VIDEO int = C.AV_CODEC_ID_MPEG1VIDEO
|
||||
AV_CODEC_ID_MPEG2VIDEO int = C.AV_CODEC_ID_MPEG2VIDEO
|
||||
AV_CODEC_ID_H264 int = C.AV_CODEC_ID_H264
|
||||
AV_CODEC_ID_MPEG4 int = C.AV_CODEC_ID_MPEG4
|
||||
CODEC_FLAG_GLOBAL_HEADER int = C.CODEC_FLAG_GLOBAL_HEADER
|
||||
FF_MB_DECISION_SIMPLE int = C.FF_MB_DECISION_SIMPLE
|
||||
FF_MB_DECISION_BITS int = C.FF_MB_DECISION_BITS
|
||||
FF_MB_DECISION_RD int = C.FF_MB_DECISION_RD
|
||||
AV_CODEC_ID_MPEG1VIDEO int = C.AV_CODEC_ID_MPEG1VIDEO
|
||||
AV_CODEC_ID_MPEG2VIDEO int = C.AV_CODEC_ID_MPEG2VIDEO
|
||||
AV_CODEC_ID_H264 int = C.AV_CODEC_ID_H264
|
||||
AV_CODEC_ID_MPEG4 int = C.AV_CODEC_ID_MPEG4
|
||||
CODEC_FLAG_GLOBAL_HEADER int = C.CODEC_FLAG_GLOBAL_HEADER
|
||||
FF_MB_DECISION_SIMPLE int = C.FF_MB_DECISION_SIMPLE
|
||||
FF_MB_DECISION_BITS int = C.FF_MB_DECISION_BITS
|
||||
FF_MB_DECISION_RD int = C.FF_MB_DECISION_RD
|
||||
AV_SAMPLE_FMT_S16 int32 = C.AV_SAMPLE_FMT_S16
|
||||
)
|
||||
|
||||
type CodecCtx struct {
|
||||
@@ -107,6 +108,8 @@ func (this *CodecCtx) CopyRequired(ist *Stream) *CodecCtx {
|
||||
codec.sample_rate = icodec.sample_rate
|
||||
codec.channels = icodec.channels
|
||||
|
||||
codec.channel_layout = icodec.channel_layout
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -128,9 +131,8 @@ func (this *CodecCtx) Id() int {
|
||||
return int(this.avCodecCtx.codec_id)
|
||||
}
|
||||
|
||||
// @todo change it to int32
|
||||
func (this *CodecCtx) Type() int {
|
||||
return int(this.avCodecCtx.codec_type)
|
||||
func (this *CodecCtx) Type() int32 {
|
||||
return int32(this.avCodecCtx.codec_type)
|
||||
}
|
||||
|
||||
func (this *CodecCtx) Width() int {
|
||||
@@ -145,6 +147,14 @@ func (this *CodecCtx) PixFmt() int32 {
|
||||
return int32(this.avCodecCtx.pix_fmt)
|
||||
}
|
||||
|
||||
func (this *CodecCtx) FrameSize() int {
|
||||
return int(this.avCodecCtx.frame_size)
|
||||
}
|
||||
|
||||
func (this *CodecCtx) SampleFmt() int32 {
|
||||
return this.avCodecCtx.sample_fmt
|
||||
}
|
||||
|
||||
func (this *CodecCtx) GetProfile() int {
|
||||
return int(this.avCodecCtx.profile)
|
||||
}
|
||||
@@ -158,6 +168,10 @@ func (this *CodecCtx) TimeBase() AVRational {
|
||||
return AVRational(this.avCodecCtx.time_base)
|
||||
}
|
||||
|
||||
func (this *CodecCtx) ChannelLayout() int {
|
||||
return int(this.avCodecCtx.channel_layout)
|
||||
}
|
||||
|
||||
func (this *CodecCtx) SetBitRate(val int) *CodecCtx {
|
||||
this.avCodecCtx.bit_rate = C.int(val)
|
||||
return this
|
||||
@@ -203,3 +217,13 @@ func (this *CodecCtx) SetMbDecision(val int) *CodecCtx {
|
||||
this.avCodecCtx.mb_decision = C.int(val)
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *CodecCtx) SetSampleFmt(val int32) *CodecCtx {
|
||||
this.avCodecCtx.sample_fmt = val
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *CodecCtx) SetSampleRate(val int) *CodecCtx {
|
||||
this.avCodecCtx.sample_rate = C.int(val)
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@ import (
|
||||
. "github.com/3d0c/gmf"
|
||||
"log"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
func fatal(err error) {
|
||||
debug.PrintStack()
|
||||
log.Fatal(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
@@ -39,10 +41,14 @@ func addStream(codecName string, oc *FmtCtx, ist *Stream) (int, int) {
|
||||
|
||||
cc.CopyRequired(ist)
|
||||
|
||||
if cc.Type() == int(AVMEDIA_TYPE_VIDEO) && oc.IsGlobalHeader() {
|
||||
if oc.IsGlobalHeader() {
|
||||
cc.SetFlag(CODEC_FLAG_GLOBAL_HEADER)
|
||||
}
|
||||
|
||||
if cc.Type() == AVMEDIA_TYPE_AUDIO {
|
||||
cc.SetSampleFmt(AV_SAMPLE_FMT_S16).SetBitRate(64000)
|
||||
}
|
||||
|
||||
if err := cc.Open(nil); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
@@ -56,6 +62,8 @@ func main() {
|
||||
var srcFileName, dstFileName string
|
||||
var stMap map[int]int = make(map[int]int, 0)
|
||||
|
||||
log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime)
|
||||
|
||||
if len(os.Args) != 3 {
|
||||
fmt.Println("Simple transcoder, it guesses source format and codecs and tries to convert it to v:mpeg4/a:mp2.")
|
||||
fmt.Println("usage: [input filename] [output.mp4]")
|
||||
@@ -91,46 +99,38 @@ func main() {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
i := 0
|
||||
|
||||
for packet := range inputCtx.Packets() {
|
||||
ist := assert(inputCtx.GetStream(packet.StreamIndex())).(*Stream)
|
||||
|
||||
if ist.CodecCtx().Type() == int(AVMEDIA_TYPE_AUDIO) {
|
||||
log.Println("skipping audio packet")
|
||||
continue
|
||||
}
|
||||
ost := assert(outputCtx.GetStream(stMap[ist.Index()])).(*Stream)
|
||||
|
||||
frame, got, err := packet.Decode(ist.CodecCtx())
|
||||
if got != 0 {
|
||||
if ist.CodecCtx().Type() == int(AVMEDIA_TYPE_VIDEO) {
|
||||
frame.SetPts(i)
|
||||
for frame := range packet.Frames(ist.CodecCtx()) {
|
||||
frame.SetPts(ost.Pts)
|
||||
|
||||
if ost.IsAudio() {
|
||||
frame.
|
||||
SetNbSamples(ost.CodecCtx().FrameSize()).
|
||||
SetFormat(ost.CodecCtx().SampleFmt()).
|
||||
SetChannelLayout(ost.CodecCtx().ChannelLayout())
|
||||
}
|
||||
|
||||
ost := assert(outputCtx.GetStream(stMap[ist.Index()])).(*Stream)
|
||||
|
||||
if p, ready, _ := frame.Encode(ost.CodecCtx()); ready {
|
||||
if ost.CodecCtx().Type() == int(AVMEDIA_TYPE_VIDEO) {
|
||||
if p.Pts() != AV_NOPTS_VALUE {
|
||||
p.SetPts(RescaleQ(p.Pts(), ost.CodecCtx().TimeBase(), ist.TimeBase()))
|
||||
}
|
||||
|
||||
if p.Dts() != AV_NOPTS_VALUE {
|
||||
p.SetDts(RescaleQ(p.Dts(), ost.CodecCtx().TimeBase(), ist.TimeBase()))
|
||||
}
|
||||
if p.Pts() != AV_NOPTS_VALUE {
|
||||
p.SetPts(RescaleQ(p.Pts(), ost.CodecCtx().TimeBase(), ist.TimeBase()))
|
||||
}
|
||||
|
||||
if p.Dts() != AV_NOPTS_VALUE {
|
||||
p.SetDts(RescaleQ(p.Dts(), ost.CodecCtx().TimeBase(), ist.TimeBase()))
|
||||
}
|
||||
|
||||
p.SetStreamIndex(ost.Index())
|
||||
|
||||
if err := outputCtx.WritePacket(p); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
ost.Pts++
|
||||
}
|
||||
|
||||
if got == 0 || err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
frame.Unref()
|
||||
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,7 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
AVMEDIA_TYPE_VIDEO int32 = C.AVMEDIA_TYPE_VIDEO
|
||||
AVMEDIA_TYPE_AUDIO int32 = C.AVMEDIA_TYPE_AUDIO
|
||||
)
|
||||
var ()
|
||||
|
||||
type FmtCtx struct {
|
||||
avCtx *_Ctype_AVFormatContext
|
||||
@@ -161,7 +158,6 @@ func (this *FmtCtx) WriteHeader() error {
|
||||
|
||||
func (this *FmtCtx) WritePacket(p *Packet) error {
|
||||
if averr := C.av_interleaved_write_frame(this.avCtx, &p.avPacket); averr < 0 {
|
||||
// if averr := C.av_write_frame(this.avCtx, &p.avPacket); averr < 0 {
|
||||
return errors.New(fmt.Sprintf("Unable to write packet to '%s': %s", this.ofmt.Filename, AvError(int(averr))))
|
||||
}
|
||||
|
||||
@@ -242,7 +238,7 @@ func (this *FmtCtx) NewStream(c *Codec) *Stream {
|
||||
if st := C.avformat_new_stream(this.avCtx, avCodec); st == nil {
|
||||
return nil
|
||||
} else {
|
||||
return &Stream{avStream: st}
|
||||
return &Stream{avStream: st, Pts: 0}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ func _TestPacketsIterator(t *testing.T) {
|
||||
t.Fatal("Unexpected error:", err)
|
||||
}
|
||||
|
||||
if stream.GetCodecCtx().Type() == CODEC_TYPE_AUDIO {
|
||||
if stream.GetCodecCtx().Type() == AVMEDIA_TYPE_AUDIO {
|
||||
// skip for tests
|
||||
continue
|
||||
}
|
||||
@@ -286,7 +286,7 @@ func _TestEncode(t *testing.T) {
|
||||
t.Fatal("Unexpected error:", err)
|
||||
}
|
||||
|
||||
if stream.GetCodecCtx().Type() == CODEC_TYPE_AUDIO {
|
||||
if stream.GetCodecCtx().Type() == AVMEDIA_TYPE_AUDIO {
|
||||
// skip for tests
|
||||
continue
|
||||
}
|
||||
|
||||
25
frame.go
25
frame.go
@@ -31,7 +31,7 @@ import (
|
||||
|
||||
type Frame struct {
|
||||
avFrame *_Ctype_AVFrame
|
||||
mediaType int
|
||||
mediaType int32
|
||||
}
|
||||
|
||||
func NewFrame() *Frame {
|
||||
@@ -45,13 +45,13 @@ func (this *Frame) Encode(cc *CodecCtx) (*Packet, bool, error) {
|
||||
p := NewPacket()
|
||||
|
||||
switch this.mediaType {
|
||||
case CODEC_TYPE_AUDIO:
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
ret = int(C.avcodec_encode_audio2(cc.avCodecCtx, &p.avPacket, this.avFrame, (*C.int)(unsafe.Pointer(&gotOutput))))
|
||||
if ret < 0 {
|
||||
return nil, false, errors.New(fmt.Sprintf("Unable to encode video packet, averror: %s", AvError(int(ret))))
|
||||
}
|
||||
|
||||
case CODEC_TYPE_VIDEO:
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
cc.avCodecCtx.field_order = C.AV_FIELD_PROGRESSIVE
|
||||
|
||||
ret = int(C.avcodec_encode_video2(cc.avCodecCtx, &p.avPacket, this.avFrame, (*C.int)(unsafe.Pointer(&gotOutput))))
|
||||
@@ -68,10 +68,7 @@ func (this *Frame) Encode(cc *CodecCtx) (*Packet, bool, error) {
|
||||
return p, ready, nil
|
||||
}
|
||||
|
||||
func (this *Frame) Scale(width int, height int) *Frame {
|
||||
return nil
|
||||
}
|
||||
|
||||
// @remove
|
||||
func (this *Frame) AvPtr() unsafe.Pointer {
|
||||
return unsafe.Pointer(this.avFrame)
|
||||
}
|
||||
@@ -84,6 +81,7 @@ func (this *Frame) Unref() {
|
||||
C.av_frame_unref(this.avFrame)
|
||||
}
|
||||
|
||||
// @remove
|
||||
func (this *Frame) SetPts(val int) {
|
||||
this.avFrame.pts = (_Ctype_int64_t)(val)
|
||||
}
|
||||
@@ -137,7 +135,7 @@ func (this *Frame) KeyFrame() int {
|
||||
}
|
||||
|
||||
func (this *Frame) SetFormat(val int32) *Frame {
|
||||
this.avFrame.format = C.int(val) //C.int(val)
|
||||
this.avFrame.format = C.int(val)
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -151,6 +149,7 @@ func (this *Frame) SetHeight(val int) *Frame {
|
||||
return this
|
||||
}
|
||||
|
||||
// @todo PIX_FMT
|
||||
func (this *Frame) ImgAlloc() error {
|
||||
if ret := int(C.av_image_alloc(
|
||||
(**C.uint8_t)(unsafe.Pointer(&this.avFrame.data)),
|
||||
@@ -179,3 +178,13 @@ func (this *Frame) Clone() *Frame {
|
||||
func (this *Frame) Free() {
|
||||
C.av_frame_free(&this.avFrame)
|
||||
}
|
||||
|
||||
func (this *Frame) SetNbSamples(val int) *Frame {
|
||||
this.avFrame.nb_samples = C.int(val)
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *Frame) SetChannelLayout(val int) *Frame {
|
||||
this.avFrame.channel_layout = (_Ctype_uint64_t)(val)
|
||||
return this
|
||||
}
|
||||
|
||||
86
packet.go
86
packet.go
@@ -28,7 +28,7 @@ import (
|
||||
// > decoder).
|
||||
// this stuff with map of singletons is used.
|
||||
//
|
||||
var frames map[int]*Frame = make(map[int]*Frame, 0)
|
||||
var frames map[int32]*Frame = make(map[int32]*Frame, 0)
|
||||
|
||||
type Packet struct {
|
||||
avPacket _Ctype_AVPacket
|
||||
@@ -45,91 +45,49 @@ func NewPacket() *Packet {
|
||||
return p
|
||||
}
|
||||
|
||||
func (this *Packet) Decode(cc *CodecCtx) (*Frame, int, error) {
|
||||
// @todo should be private
|
||||
func (this *Packet) Decode(cc *CodecCtx) (*Frame, bool, int, error) {
|
||||
var gotOutput int
|
||||
var ret int = 0
|
||||
|
||||
if frames[cc.Type()] == nil {
|
||||
frames[cc.Type()] = &Frame{avFrame: C.av_frame_alloc(), mediaType: cc.Type()}
|
||||
}
|
||||
|
||||
switch cc.Type() {
|
||||
case CODEC_TYPE_AUDIO:
|
||||
ret := C.avcodec_decode_audio4(cc.avCodecCtx, frames[CODEC_TYPE_AUDIO].avFrame, (*C.int)(unsafe.Pointer(&gotOutput)), &this.avPacket)
|
||||
case AVMEDIA_TYPE_AUDIO:
|
||||
ret = int(C.avcodec_decode_audio4(cc.avCodecCtx, frames[AVMEDIA_TYPE_AUDIO].avFrame, (*C.int)(unsafe.Pointer(&gotOutput)), &this.avPacket))
|
||||
if ret < 0 {
|
||||
return nil, 0, errors.New(fmt.Sprintf("Unable to decode audio packet, averror: %s", AvError(int(ret))))
|
||||
return nil, false, int(ret), errors.New(fmt.Sprintf("Unable to decode audio packet, averror: %s", AvError(int(ret))))
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case CODEC_TYPE_VIDEO:
|
||||
// pkt->dts = av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base);
|
||||
// this.avPacket.dts = C.av_rescale_q(ist->dts, AV_TIME_BASE_Q, ist->st->time_base)
|
||||
fmt.Println(cc.avCodecCtx)
|
||||
ret := C.avcodec_decode_video2(cc.avCodecCtx, frames[CODEC_TYPE_VIDEO].avFrame, (*C.int)(unsafe.Pointer(&gotOutput)), &this.avPacket)
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
ret = int(C.avcodec_decode_video2(cc.avCodecCtx, frames[AVMEDIA_TYPE_VIDEO].avFrame, (*C.int)(unsafe.Pointer(&gotOutput)), &this.avPacket))
|
||||
if ret < 0 {
|
||||
return nil, 0, errors.New(fmt.Sprintf("Unable to decode video packet, averror: %s", AvError(int(ret))))
|
||||
return nil, false, int(ret), errors.New(fmt.Sprintf("Unable to decode video packet, averror: %s", AvError(int(ret))))
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
default:
|
||||
return nil, 0, errors.New(fmt.Sprintf("Unknown codec type: %v", cc.Type()))
|
||||
return nil, false, int(ret), errors.New(fmt.Sprintf("Unknown codec type: %v", cc.Type()))
|
||||
}
|
||||
|
||||
return frames[cc.Type()], gotOutput, nil
|
||||
return frames[cc.Type()], (gotOutput > 0), int(ret), nil
|
||||
}
|
||||
|
||||
func (this *Packet) DecodeV2(cc *CodecCtx) *Frame {
|
||||
var gotOutput int
|
||||
|
||||
if frames[cc.Type()] == nil {
|
||||
frames[cc.Type()] = &Frame{avFrame: C.av_frame_alloc(), mediaType: cc.Type()}
|
||||
}
|
||||
|
||||
ret := C.avcodec_decode_video2(cc.avCodecCtx, frames[CODEC_TYPE_VIDEO].avFrame, (*C.int)(unsafe.Pointer(&gotOutput)), &this.avPacket)
|
||||
if ret < 0 {
|
||||
return nil
|
||||
fmt.Printf("Unable to decode video packet, averror: %s", AvError(int(ret)))
|
||||
}
|
||||
|
||||
if gotOutput != 0 {
|
||||
frames[cc.Type()].avFrame.pts = C.av_frame_get_best_effort_timestamp(frames[cc.Type()].avFrame)
|
||||
|
||||
return frames[cc.Type()]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *Packet) DecodeV(cc *CodecCtx) chan *Frame {
|
||||
var gotOutput int
|
||||
|
||||
if frames[cc.Type()] == nil {
|
||||
frames[cc.Type()] = &Frame{avFrame: C.av_frame_alloc(), mediaType: cc.Type()}
|
||||
}
|
||||
|
||||
func (this *Packet) Frames(cc *CodecCtx) chan *Frame {
|
||||
yield := make(chan *Frame)
|
||||
|
||||
go func() {
|
||||
defer close(yield)
|
||||
|
||||
for {
|
||||
ret := C.avcodec_decode_video2(cc.avCodecCtx, frames[CODEC_TYPE_VIDEO].avFrame, (*C.int)(unsafe.Pointer(&gotOutput)), &this.avPacket)
|
||||
if ret < 0 {
|
||||
break
|
||||
fmt.Printf("Unable to decode video packet, averror: %s", AvError(int(ret)))
|
||||
}
|
||||
|
||||
if ret == 0 && gotOutput == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if gotOutput != 0 {
|
||||
// frame->pts = av_frame_get_best_effort_timestamp(frame);
|
||||
frames[cc.Type()].avFrame.pts = C.av_frame_get_best_effort_timestamp(frames[cc.Type()].avFrame)
|
||||
yield <- frames[cc.Type()]
|
||||
frame, ready, ret, _ := this.Decode(cc)
|
||||
if ready {
|
||||
yield <- frame
|
||||
}
|
||||
|
||||
C.shift_data(&this.avPacket, C.int(ret))
|
||||
@@ -138,8 +96,6 @@ func (this *Packet) DecodeV(cc *CodecCtx) chan *Frame {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
close(yield)
|
||||
}()
|
||||
|
||||
return yield
|
||||
@@ -182,5 +138,11 @@ func (this *Packet) Data() []byte {
|
||||
}
|
||||
|
||||
func (this *Packet) Dump() {
|
||||
fmt.Println(this.avPacket)
|
||||
fmt.Println("pkt:{\n", "pts:", this.avPacket.pts, "\ndts:", this.avPacket.dts, "\ndata:", string(C.GoBytes(unsafe.Pointer(this.avPacket.data), 128)), "size:", this.avPacket.size, "\n}")
|
||||
}
|
||||
|
||||
func (this *Packet) SetStreamIndex(val int) *Packet {
|
||||
this.avPacket.stream_index = C.int(val)
|
||||
return this
|
||||
}
|
||||
|
||||
17
stream.go
17
stream.go
@@ -16,6 +16,7 @@ import (
|
||||
type Stream struct {
|
||||
avStream *_Ctype_AVStream
|
||||
cc *CodecCtx
|
||||
Pts int
|
||||
}
|
||||
|
||||
func (this *Stream) CodecCtx() *CodecCtx {
|
||||
@@ -33,6 +34,10 @@ func (this *Stream) CodecCtx() *CodecCtx {
|
||||
avCodecCtx: this.avStream.codec,
|
||||
}
|
||||
|
||||
if err := this.cc.Open(nil); err != nil {
|
||||
panic(fmt.Sprintf("Can't open code for stream '%d', error: %v", this.Index(), err))
|
||||
}
|
||||
|
||||
return this.cc
|
||||
}
|
||||
|
||||
@@ -69,3 +74,15 @@ func (this *Stream) NbFrames() int {
|
||||
func (this *Stream) TimeBase() AVRational {
|
||||
return AVRational(this.avStream.time_base)
|
||||
}
|
||||
|
||||
func (this *Stream) Type() int32 {
|
||||
return this.CodecCtx().Type()
|
||||
}
|
||||
|
||||
func (this *Stream) IsAudio() bool {
|
||||
return (this.Type() == AVMEDIA_TYPE_AUDIO)
|
||||
}
|
||||
|
||||
func (this *Stream) IsVideo() bool {
|
||||
return (this.Type() == AVMEDIA_TYPE_VIDEO)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user