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