Files
ffmpeg-dev-go/examples/remux/main.go
2023-11-05 08:43:33 +08:00

151 lines
4.5 KiB
Go

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)
}