mirror of
https://github.com/qrtc/ffmpeg-dev-go.git
synced 2025-10-05 15:47:33 +08:00
2023-10-31 09:16:44 CST W44D2
This commit is contained in:
150
examples/remux/main.go
Normal file
150
examples/remux/main.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
ffmpeg "github.com/qrtc/ffmpeg-dev-go"
|
||||
)
|
||||
|
||||
func logPacket(fmtCtx *ffmpeg.AVFormatContext, pkt *ffmpeg.AVPacket, tag string) {
|
||||
timeBase := fmtCtx.GetStreams()[pkt.GetStreamIndex()].GetTimeBaseAddr()
|
||||
fmt.Fprintf(os.Stdout, "%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
|
||||
tag,
|
||||
ffmpeg.AvTs2str(pkt.GetPts()), ffmpeg.AvTs2timestr(pkt.GetPts(), timeBase),
|
||||
ffmpeg.AvTs2str(pkt.GetDts()), ffmpeg.AvTs2timestr(pkt.GetDts(), timeBase),
|
||||
ffmpeg.AvTs2str(pkt.GetDuration()), ffmpeg.AvTs2timestr(pkt.GetDuration(), timeBase),
|
||||
pkt.GetStreamIndex())
|
||||
}
|
||||
|
||||
func main() {
|
||||
var (
|
||||
ofmt *ffmpeg.AVOutputFormat
|
||||
ifmtCtx, ofmtCtx *ffmpeg.AVFormatContext
|
||||
pkt ffmpeg.AVPacket
|
||||
ret int32
|
||||
streamMapping []int32
|
||||
streamIndex int32
|
||||
)
|
||||
|
||||
if len(os.Args) < 3 {
|
||||
fmt.Fprintf(os.Stderr, "usage: %s input output\n"+
|
||||
"API example program to remux a media file with libavformat and libavcodec.\n"+
|
||||
"The output format is guessed according to the file extension.\n"+
|
||||
"\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
inFilename := os.Args[1]
|
||||
outFilename := os.Args[2]
|
||||
|
||||
if ret = ffmpeg.AvFormatOpenInput(&ifmtCtx, inFilename, nil, nil); ret < 0 {
|
||||
fmt.Fprintf(os.Stderr, "Could not open input file '%s'", inFilename)
|
||||
goto end
|
||||
}
|
||||
if ret = ffmpeg.AvFormatFindStreamInfo(ifmtCtx, nil); ret < 0 {
|
||||
fmt.Fprintf(os.Stderr, "Failed to retrieve input stream information")
|
||||
goto end
|
||||
}
|
||||
|
||||
ffmpeg.AvDumpFormat(ifmtCtx, 0, inFilename, 0)
|
||||
|
||||
if ffmpeg.AvFormatAllocOutputContext2(&ofmtCtx, nil, ffmpeg.NIL, outFilename); ofmtCtx == nil {
|
||||
fmt.Fprintf(os.Stderr, "Could not create output context\n")
|
||||
ret = ffmpeg.AVERROR_UNKNOWN
|
||||
goto end
|
||||
}
|
||||
|
||||
streamMapping = make([]int32, ifmtCtx.GetNbStreams())
|
||||
|
||||
ofmt = ofmtCtx.GetOformat()
|
||||
|
||||
for i := 0; i < len(streamMapping); i++ {
|
||||
inStream := ifmtCtx.GetStreams()[i]
|
||||
inCodecPar := inStream.GetCodecpar()
|
||||
|
||||
if inCodecPar.GetCodecType() != ffmpeg.AVMEDIA_TYPE_AUDIO &&
|
||||
inCodecPar.GetCodecType() != ffmpeg.AVMEDIA_TYPE_VIDEO &&
|
||||
inCodecPar.GetCodecType() != ffmpeg.AVMEDIA_TYPE_SUBTITLE {
|
||||
streamMapping[i] = -1
|
||||
continue
|
||||
}
|
||||
|
||||
streamMapping[i] = streamIndex
|
||||
streamIndex++
|
||||
|
||||
outStream := ffmpeg.AvFormatNewStream(ofmtCtx, nil)
|
||||
if outStream == nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed allocating output stream\n")
|
||||
ret = ffmpeg.AVERROR_UNKNOWN
|
||||
goto end
|
||||
}
|
||||
|
||||
if ret = ffmpeg.AvCodecParametersCopy(outStream.GetCodecpar(), inCodecPar); ret < 0 {
|
||||
fmt.Fprintf(os.Stderr, "Failed to copy codec parameters\n")
|
||||
goto end
|
||||
}
|
||||
outStream.GetCodecpar().SetCodecTag(0)
|
||||
}
|
||||
ffmpeg.AvDumpFormat(ofmtCtx, 0, outFilename, 1)
|
||||
|
||||
if (ofmt.GetFlags() & ffmpeg.AVFMT_NOFILE) == 0 {
|
||||
if ret = ffmpeg.AvIOOpen(ofmtCtx.GetPbAddr(), outFilename, ffmpeg.AVIO_FLAG_WRITE); ret < 0 {
|
||||
ffmpeg.AvLog(nil, ffmpeg.AV_LOG_ERROR, "Could not open output file '%s'", outFilename)
|
||||
goto end
|
||||
}
|
||||
}
|
||||
|
||||
if ret = ffmpeg.AvFormatWriteHeader(ofmtCtx, nil); ret < 0 {
|
||||
fmt.Fprintf(os.Stderr, "Error occurred when opening output file\n")
|
||||
goto end
|
||||
}
|
||||
|
||||
for {
|
||||
var inStream, outStream *ffmpeg.AVStream
|
||||
|
||||
if ret = ffmpeg.AvReadFrame(ifmtCtx, &pkt); ret < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
inStream = ifmtCtx.GetStreams()[pkt.GetStreamIndex()]
|
||||
if int(pkt.GetStreamIndex()) >= len(streamMapping) ||
|
||||
streamMapping[pkt.GetStreamIndex()] < 0 {
|
||||
ffmpeg.AvPacketUnref(&pkt)
|
||||
continue
|
||||
}
|
||||
|
||||
pkt.SetStreamIndex(streamMapping[pkt.GetStreamIndex()])
|
||||
outStream = ofmtCtx.GetStreams()[pkt.GetStreamIndex()]
|
||||
logPacket(ifmtCtx, &pkt, "in")
|
||||
|
||||
// copy packet
|
||||
pkt.SetPts(ffmpeg.AvRescaleQRnd(pkt.GetPts(), inStream.GetTimeBase(), outStream.GetTimeBase(),
|
||||
ffmpeg.AV_ROUND_NEAR_INF|ffmpeg.AV_ROUND_PASS_MINMAX))
|
||||
pkt.SetDts(ffmpeg.AvRescaleQRnd(pkt.GetDts(), inStream.GetTimeBase(), outStream.GetTimeBase(),
|
||||
ffmpeg.AV_ROUND_NEAR_INF|ffmpeg.AV_ROUND_PASS_MINMAX))
|
||||
pkt.SetDuration(ffmpeg.AvRescaleQ(pkt.GetDuration(), inStream.GetTimeBase(), outStream.GetTimeBase()))
|
||||
pkt.SetPos(-1)
|
||||
logPacket(ofmtCtx, &pkt, "out")
|
||||
|
||||
if ret = ffmpeg.AvInterleavedWriteFrame(ofmtCtx, &pkt); ret < 0 {
|
||||
fmt.Fprintf(os.Stderr, "Error muxing packet\n")
|
||||
break
|
||||
}
|
||||
ffmpeg.AvPacketUnref(&pkt)
|
||||
}
|
||||
ffmpeg.AvWriteTrailer(ofmtCtx)
|
||||
end:
|
||||
// close output
|
||||
ffmpeg.AvFormatCloseInput(&ifmtCtx)
|
||||
if ofmtCtx != nil && (ofmt.GetFlags()&ffmpeg.AVFMT_NOFILE) == 0 {
|
||||
ffmpeg.AvIOClosep(ofmtCtx.GetPbAddr())
|
||||
}
|
||||
ffmpeg.AvFormatFreeContext(ofmtCtx)
|
||||
|
||||
if ret < 0 && ret != ffmpeg.AVERROR_EOF {
|
||||
fmt.Fprintf(os.Stderr, "Error occurred: %s\n", ffmpeg.AvErr2str(ret))
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
Reference in New Issue
Block a user