mirror of
https://github.com/qrtc/ffmpeg-dev-go.git
synced 2025-10-05 07:37:20 +08:00
151 lines
4.5 KiB
Go
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)
|
|
}
|