diff --git a/codecParam.go b/codecParam.go index e05df5f..d6910d1 100644 --- a/codecParam.go +++ b/codecParam.go @@ -23,23 +23,30 @@ func (cp *CodecParameters) Free() { C.avcodec_parameters_free(&cp.avCodecParameters) } -func (cp *CodecParameters) GetCodecType() int { +func (cp *CodecParameters) CodecType() int { return int(cp.avCodecParameters.codec_type) } -func (cp *CodecParameters) GetCodecId() int { +func (cp *CodecParameters) CodecId() int { return int(cp.avCodecParameters.codec_id) } -func (cp *CodecParameters) GetBitRate() int64 { +func (cp *CodecParameters) BitRate() int64 { return int64(cp.avCodecParameters.bit_rate) } -func (cp *CodecParameters) GetWidth() int { +func (cp *CodecParameters) Width() int { return int(cp.avCodecParameters.width) } -func (cp *CodecParameters) GetHeight() int { +// Format +// video: the pixel format, the value corresponds to enum AVPixelFormat. +// audio: the sample format, the value corresponds to enum AVSampleFormat. +func (cp *CodecParameters) Format() int32 { + return int32(cp.avCodecParameters.format) +} + +func (cp *CodecParameters) Height() int { return int(cp.avCodecParameters.height) } diff --git a/example_encoding_test.go b/example_encoding_test.go new file mode 100644 index 0000000..82c2a22 --- /dev/null +++ b/example_encoding_test.go @@ -0,0 +1,96 @@ +package gmf_test + +import ( + "errors" + "fmt" + "log" + + "github.com/3d0c/gmf" +) + +func Example() { + outputfilename := "examples/sample-encoding1.mpg" + dstWidth, dstHeight := 640, 480 + + codec, err := gmf.FindEncoder(gmf.AV_CODEC_ID_MPEG1VIDEO) + if err != nil { + log.Fatal(err) + } + + videoEncCtx := gmf.NewCodecCtx(codec) + if videoEncCtx == nil { + log.Fatal(errors.New("failed to create a new codec context")) + } + defer videoEncCtx.Free() + + outputCtx, err := gmf.NewOutputCtx(outputfilename) + if err != nil { + log.Fatal(errors.New("failed to create a new output context")) + } + defer outputCtx.Free() + + videoEncCtx. + SetBitRate(400000). + SetWidth(dstWidth). + SetHeight(dstHeight). + SetTimeBase(gmf.AVR{Num: 1, Den: 25}). + SetPixFmt(gmf.AV_PIX_FMT_YUV420P). + SetProfile(gmf.FF_PROFILE_MPEG4_SIMPLE). + SetMbDecision(gmf.FF_MB_DECISION_RD) + + if outputCtx.IsGlobalHeader() { + videoEncCtx.SetFlag(gmf.CODEC_FLAG_GLOBAL_HEADER) + } + + videoStream := outputCtx.NewStream(codec) + if videoStream == nil { + log.Fatal(errors.New(fmt.Sprintf("Unable to create stream for videoEnc [%s]\n", codec.LongName()))) + } + defer videoStream.Free() + + if err = videoEncCtx.Open(nil); err != nil { + log.Fatal(err) + } + videoStream.DumpContexCodec(videoEncCtx) + // videoStream.SetCodecCtx(videoEncCtx) + + outputCtx.SetStartTime(0) + + if err = outputCtx.WriteHeader(); err != nil { + log.Fatal(err) + } + outputCtx.Dump() + i := int64(0) + n := 0 + + for frame := range gmf.GenSyntVideoNewFrame(videoEncCtx.Width(), videoEncCtx.Height(), videoEncCtx.PixFmt()) { + frame.SetPts(i) + + if p, err := frame.Encode(videoEncCtx); p != nil { + if p.Pts() != gmf.AV_NOPTS_VALUE { + p.SetPts(gmf.RescaleQ(p.Pts(), videoEncCtx.TimeBase(), videoStream.TimeBase())) + } + + if p.Dts() != gmf.AV_NOPTS_VALUE { + p.SetDts(gmf.RescaleQ(p.Dts(), videoEncCtx.TimeBase(), videoStream.TimeBase())) + } + + if err := outputCtx.WritePacket(p); err != nil { + log.Fatal(err) + } + + n++ + + log.Printf("Write frame=%d size=%v pts=%v dts=%v\n", frame.Pts(), p.Size(), p.Pts(), p.Dts()) + + p.Free() + } else if err != nil { + log.Fatal(err) + } + + frame.Free() + i++ + } + fmt.Println("frames written to examples/sample-encoding1.mpg") + // Output: frames written to examples/sample-encoding1.mpg +} diff --git a/packet_go112.go b/packet_go112.go index 96c38d4..7a0f52c 100644 --- a/packet_go112.go +++ b/packet_go112.go @@ -23,7 +23,7 @@ import ( ) const ( - AV_PKT_FLAG_KEY = C.AV_PKT_FLAG_KEY + AV_PKT_FLAG_KEY = C.AV_PKT_FLAG_KEY // The packet contains a keyframe ) type Packet struct { diff --git a/packet_test.go b/packet_test.go index bdda880..3909aed 100644 --- a/packet_test.go +++ b/packet_test.go @@ -1,8 +1,9 @@ package gmf_test import ( - "github.com/3d0c/gmf" "testing" + + "github.com/3d0c/gmf" ) func TestFramesIterator(t *testing.T) { @@ -14,9 +15,8 @@ func TestFramesIterator(t *testing.T) { cnt := 0 ist := assert(inputCtx.GetStream(0)).(*gmf.Stream) - t.Log("NbFrames", ist.NbFrames()) - ctx := ist.CodecCtx() - for frame := range gmf.GenSyntVideoNewFrame(ctx.Width(), ctx.Height(), ctx.PixFmt()) { + par := ist.CodecPar() + for frame := range gmf.GenSyntVideoNewFrame(par.Width(), par.Height(), par.Format()) { cnt++ frame.Free() } @@ -25,3 +25,16 @@ func TestFramesIterator(t *testing.T) { t.Fatalf("Expected %d frames, obtained %d\n", 25, cnt) } } + +func ExamplePacket_SetData() { + p := gmf.NewPacket() + defer p.Free() + p.SetData([]byte{0x00, 0x00, 0x00, 0x01, 0x67}) + defer p.FreeData() +} + +func ExamplePacket_SetFlags() { + p := gmf.NewPacket() + p.SetFlags(p.Flags() | gmf.AV_PKT_FLAG_KEY) + defer p.Free() +} diff --git a/stream.go b/stream.go index 2ac4a26..9492a40 100644 --- a/stream.go +++ b/stream.go @@ -19,8 +19,9 @@ type Stream struct { SwsCtx *SwsCtx SwrCtx *SwrCtx AvFifo *AVAudioFifo - cc *CodecCtx - Pts int64 + // Deprecated: Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead. + cc *CodecCtx + Pts int64 CgoMemoryManage } @@ -47,6 +48,8 @@ func (s *Stream) SetCodecFlags() { s.avStream.codec.flags |= C.AV_CODEC_FLAG_GLOBAL_HEADER } +// CodecCtx +// Deprecated: Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead. func (s *Stream) CodecCtx() *CodecCtx { // Supposed that output context is set and opened by user if s.IsCodecCtxSet() { @@ -83,7 +86,16 @@ func (s *Stream) SetCodecCtx(cc *CodecCtx) { s.cc = cc } -func (s *Stream) SetCodecParameters(cp *CodecParameters) error { +func (s *Stream) CodecPar() *CodecParameters { + if s.avStream == nil || s.avStream.codecpar == nil { + return nil + } + return &CodecParameters{ + avCodecParameters: s.avStream.codecpar, + } +} + +func (s *Stream) SetCodecPar(cp *CodecParameters) error { if cp == nil || cp.avCodecParameters == nil { return fmt.Errorf("codec parameters are not initialized") } @@ -92,6 +104,8 @@ func (s *Stream) SetCodecParameters(cp *CodecParameters) error { return nil } +// IsCodecCtxSet +// Deprecated: Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead. func (s *Stream) IsCodecCtxSet() bool { return s.cc != nil } @@ -117,7 +131,7 @@ func (s *Stream) TimeBase() AVRational { } func (s *Stream) Type() int32 { - return s.CodecCtx().Type() + return int32(s.CodecPar().CodecType()) } func (s *Stream) IsAudio() bool { diff --git a/stream_test.go b/stream_test.go index d853dcb..b6e30fd 100644 --- a/stream_test.go +++ b/stream_test.go @@ -1,9 +1,10 @@ package gmf_test import ( - "github.com/3d0c/gmf" "log" "testing" + + "github.com/3d0c/gmf" ) func TestStream(t *testing.T) { @@ -34,9 +35,9 @@ func TestStream(t *testing.T) { st := assert(ctx.GetStream(0)).(*gmf.Stream) - st.SetCodecCtx(cc) + st.DumpContexCodec(cc) - if st.CodecCtx().Height() != td.height || st.CodecCtx().Width() != td.width { + if cc.Height() != td.height || cc.Width() != td.width { t.Fatalf("Expected dimension = %dx%d, %dx%d got\n", td.width, td.height, st.CodecCtx().Width(), st.CodecCtx().Height()) } @@ -53,7 +54,7 @@ func TestStreamInputCtx(t *testing.T) { ist := assert(inputCtx.GetStream(0)).(*gmf.Stream) - if ist.CodecCtx().Width() != inputSampleWidth || ist.CodecCtx().Height() != inputSampleHeight { + if ist.CodecPar().Width() != inputSampleWidth || ist.CodecPar().Height() != inputSampleHeight { t.Fatalf("Expected dimension = %dx%d, %dx%d got\n", inputSampleWidth, inputSampleHeight, ist.CodecCtx().Width(), ist.CodecCtx().Height()) } diff --git a/sws_test.go b/sws_test.go index 18a7774..5ef6360 100644 --- a/sws_test.go +++ b/sws_test.go @@ -1,9 +1,10 @@ package gmf_test import ( - "github.com/3d0c/gmf" "log" "testing" + + "github.com/3d0c/gmf" ) // @todo export rescaled frame as jpeg and compare dimension. @@ -45,7 +46,7 @@ func TestScale(t *testing.T) { t.Fatal(err) } - videoStream.SetCodecCtx(dstCodecCtx) + videoStream.DumpContexCodec(dstCodecCtx) swsCtx, err := gmf.NewSwsCtx(srcEncCtx.Width(), srcEncCtx.Height(), srcEncCtx.PixFmt(), dstCodecCtx.Width(), dstCodecCtx.Height(), dstCodecCtx.PixFmt(), gmf.SWS_BICUBIC) if err != nil { t.Fatal(err)