175 lines
3.8 KiB
Go
175 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"git.kingecg.top/kingecg/goffmpeg/pkg/ffmpeg"
|
|
)
|
|
|
|
// Simple remuxing example using goffmpeg library
|
|
func main() {
|
|
if len(os.Args) < 3 {
|
|
fmt.Println("Usage: simple-transcode <input> <output>")
|
|
fmt.Println("Example: simple-transcode input.mp4 output.flv")
|
|
os.Exit(1)
|
|
}
|
|
|
|
inputURL := os.Args[1]
|
|
outputURL := os.Args[2]
|
|
|
|
// Open input file
|
|
ic := ffmpeg.AllocFormatContext()
|
|
defer ic.Free()
|
|
|
|
if err := ic.OpenInput(inputURL); err != nil {
|
|
log.Fatalf("Failed to open input %s: %v", inputURL, err)
|
|
}
|
|
|
|
// Find stream info
|
|
if err := ic.FindStreamInfo(); err != nil {
|
|
log.Fatalf("Failed to find stream info: %v", err)
|
|
}
|
|
|
|
fmt.Printf("Input: %s\n", inputURL)
|
|
ic.DumpFormat(0, inputURL, false)
|
|
|
|
// Guess output format
|
|
of := ffmpeg.GuessFormat("", outputURL)
|
|
if of == nil {
|
|
log.Fatalf("Failed to guess output format")
|
|
}
|
|
|
|
// Create output context
|
|
ofc, err := ffmpeg.AllocOutputContext(outputURL, of)
|
|
if err != nil {
|
|
log.Fatalf("Failed to allocate output context: %v", err)
|
|
}
|
|
defer ofc.Free()
|
|
|
|
// Get input streams
|
|
inputStreams := ic.Streams()
|
|
|
|
// Process streams - select first video and audio only
|
|
var videoIdx, audioIdx int = -1, -1
|
|
streamCount := 0
|
|
|
|
for i, is := range inputStreams {
|
|
cp := is.CodecParameters()
|
|
if cp == nil {
|
|
continue
|
|
}
|
|
|
|
streamType := cp.CodecType()
|
|
|
|
// Skip non-video/audio
|
|
if streamType != ffmpeg.CodecTypeVideo && streamType != ffmpeg.CodecTypeAudio {
|
|
continue
|
|
}
|
|
|
|
// Skip duplicate audio
|
|
if streamType == ffmpeg.CodecTypeAudio && audioIdx >= 0 {
|
|
fmt.Printf("\nStream %d: audio (skipped - duplicate)\n", i)
|
|
continue
|
|
}
|
|
|
|
// Add stream with same codec (stream copy mode)
|
|
os, err := ofc.AddStream(nil)
|
|
if err != nil {
|
|
fmt.Printf("\nStream %d: failed to add stream: %v\n", i, err)
|
|
continue
|
|
}
|
|
|
|
// Copy codec parameters from input to output
|
|
if err := os.SetCodecParameters(cp); err != nil {
|
|
fmt.Printf("\nStream %d: failed to set codec parameters: %v\n", i, err)
|
|
continue
|
|
}
|
|
|
|
// Copy time base
|
|
tb := is.TimeBase()
|
|
os.SetTimeBase(tb)
|
|
|
|
if streamType == ffmpeg.CodecTypeVideo {
|
|
videoIdx = streamCount
|
|
fmt.Printf("\nStream %d: video (stream copy)\n", i)
|
|
} else {
|
|
audioIdx = streamCount
|
|
fmt.Printf("\nStream %d: audio (stream copy)\n", i)
|
|
}
|
|
streamCount++
|
|
}
|
|
|
|
if videoIdx < 0 && audioIdx < 0 {
|
|
log.Fatal("No supported streams found")
|
|
}
|
|
|
|
fmt.Printf("\nOutput: %s\n", outputURL)
|
|
fmt.Printf("Output has %d streams\n", streamCount)
|
|
ofc.DumpFormat(0, outputURL, true)
|
|
|
|
// Open output file
|
|
if err := ofc.OpenOutput(outputURL); err != nil {
|
|
log.Fatalf("Failed to open output: %v", err)
|
|
}
|
|
|
|
// Write header
|
|
if err := ofc.WriteHeader(); err != nil {
|
|
log.Fatalf("Failed to write header: %v", err)
|
|
}
|
|
|
|
fmt.Println("\nRemuxing...")
|
|
pkt := ffmpeg.AllocPacket()
|
|
defer pkt.Free()
|
|
|
|
packetCount := 0
|
|
for {
|
|
err := ic.ReadPacket(pkt)
|
|
if err != nil {
|
|
break
|
|
}
|
|
|
|
pktStreamIdx := pkt.StreamIndex()
|
|
|
|
// Map input stream index to output stream index
|
|
var outStreamIdx int
|
|
if videoIdx >= 0 && audioIdx >= 0 {
|
|
// Both video and audio present
|
|
if pktStreamIdx == 0 {
|
|
outStreamIdx = videoIdx
|
|
} else if pktStreamIdx == 1 {
|
|
outStreamIdx = audioIdx
|
|
} else {
|
|
pkt.Unref()
|
|
continue
|
|
}
|
|
} else if videoIdx >= 0 {
|
|
outStreamIdx = videoIdx
|
|
} else {
|
|
outStreamIdx = audioIdx
|
|
}
|
|
|
|
pkt.SetStreamIndex(outStreamIdx)
|
|
|
|
if err := ofc.WritePacket(pkt); err != nil {
|
|
log.Printf("Warning: failed to write packet: %v", err)
|
|
}
|
|
|
|
pkt.Unref()
|
|
packetCount++
|
|
|
|
if packetCount%100 == 0 {
|
|
fmt.Printf("Processed %d packets...\n", packetCount)
|
|
}
|
|
}
|
|
|
|
// Write trailer
|
|
if err := ofc.WriteTrailer(); err != nil {
|
|
log.Fatalf("Failed to write trailer: %v", err)
|
|
}
|
|
|
|
fmt.Printf("\nRemuxing complete! Processed %d packets.\n", packetCount)
|
|
fmt.Printf("Output saved to: %s\n", outputURL)
|
|
}
|