Skip to content

Commit

Permalink
fix(concat): dont use syscall for windows
Browse files Browse the repository at this point in the history
  • Loading branch information
Darkness4 committed Jun 9, 2024
1 parent abad495 commit 77d5afc
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 95 deletions.
117 changes: 23 additions & 94 deletions video/concat/concat.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,14 @@ import "C"
import (
"context"
"errors"
"io"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"syscall"
"unsafe"

"github.com/Darkness4/fc2-live-dl-go/utils"
"github.com/rs/zerolog/log"
)

Expand Down Expand Up @@ -100,11 +98,30 @@ func Do(output string, inputs []string, opts ...Option) error {
}

// If mixed formats (adts vs asc), we should remux the others first using intermediates or FIFO
inputs, err := remuxMixedTS(ctx, inputs, opts...)
if err != nil {
return err
if areFormatMixed(inputs) {
i, useFIFO, err := remuxMixedTS(ctx, inputs, opts...)
if err != nil {
return err
}
inputs = i

if !useFIFO {
// Delete intermediates
defer func() {
for _, input := range i {
if err := os.Remove(input); err != nil {
log.Error().
Err(err).
Str("file", input).
Msg("failed to remove intermediate file")
}
}
}()
}
}

fmt.Println("output", output)

inputsC := C.malloc(C.size_t(len(inputs)) * C.size_t(unsafe.Sizeof(uintptr(0))))
defer C.free(inputsC)
// convert the C array to a Go Array so we can index it
Expand Down Expand Up @@ -229,94 +246,6 @@ func areFormatMixed(files []string) bool {
return ts > 0 && ts < len(files)
}

// remuxMixedTS remuxes mixed TS/AAC files into intermediate format.
func remuxMixedTS(ctx context.Context, files []string, opts ...Option) ([]string, error) {
intermediates := make([]string, 0, len(files))

// Check if there are mixed formats
if areFormatMixed(files) {
log.Warn().Msg("mixed formats detected, intermediate files/fifos will be created")

// Remux all the files into intermediate format
for _, file := range files {
randName := utils.GenerateRandomString(8)
intermediateName := "." + file + "." + randName + ".ts"
intermediates = append(intermediates, intermediateName)

// Make fifo
if err := syscall.Mkfifo(intermediateName, 0600); err != nil {
// If fails to create the FIFO, ignore it and use an intermediate file
log.Error().Err(err).Msg("failed to create FIFO")
}

doneCh := make(chan struct{}, 1)

// Make mpegts intermediates
go func() {
defer func() {
doneCh <- struct{}{}
}()
// Will IO block due to the FIFO
if err := Do(intermediateName, []string{file}, opts...); err != nil {
log.Error().
Err(err).
Str("file", file).
Msg("failed to remux to intermediate file")
}

// Remove the FIFO
_ = os.Remove(intermediateName)
}()

go func() {
select {
case <-doneCh:
return
case <-ctx.Done():
// Remove the FIFO
}

// Flush fifo
if err := flushFIFO(intermediateName); err != nil {
log.Err(err).Msg("failed to flush FIFO")
}

_ = os.Remove(intermediateName)
}()
}
} else {
intermediates = files
}

return intermediates, nil
}

func flushFIFO(file string) error {
// Open the FIFO for reading
fifo, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer fifo.Close()

// Read all data from the FIFO
buffer := make([]byte, 1024)
for {
n, err := fifo.Read(buffer)
if err != nil {
if err == io.EOF {
break
}
return err
}
if n == 0 {
break
}
}

return nil
}

func extractOrderPart(prefix string, filename string) string {
// Extracts the numeric suffix from the filename, if present
ext := filepath.Ext(filename)
Expand Down
2 changes: 1 addition & 1 deletion video/concat/concat_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func TestDo(t *testing.T) {
err := concat.Do("output.mp4", []string{"input.ts", "input.1.mp4"})
err := concat.Do("output.mp4", []string{"input.ts", "input.mp4"})
require.NoError(t, err)
}

Expand Down
128 changes: 128 additions & 0 deletions video/concat/remux_intermediate_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//go:build !windows

package concat

import (
"context"
"io"
"os"
"sync"
"syscall"

"github.com/Darkness4/fc2-live-dl-go/utils"
"github.com/rs/zerolog/log"
)

// remuxMixedTS remuxes mixed TS/AAC files into intermediate format.
func remuxMixedTS(
ctx context.Context,
files []string,
opts ...Option,
) (intermediates []string, useFIFO bool, err error) {
intermediates = make([]string, 0, len(files))

useFIFO = false

var wg sync.WaitGroup

// Check if we can use FIFO
for _, file := range files {
randName := utils.GenerateRandomString(8)
intermediateName := "." + file + "." + randName + ".ts"
intermediates = append(intermediates, intermediateName)

if useFIFO {
if err := syscall.Mkfifo(intermediateName, 0600); err != nil {
// If fails to create the FIFO, ignore it and use an intermediate file
log.Error().Err(err).Msg("failed to create FIFO")
useFIFO = false
}
}
}

if !useFIFO {
// Delete eventual FIFOs
for _, intermediateName := range intermediates {
_ = os.Remove(intermediateName)
}
}

// Remux all the files into intermediate format
for i, intermediateName := range intermediates {
wg.Add(1)

doneCh := make(chan struct{}, 1)

// Make mpegts intermediates
go func(intermediateName string) {
defer func() {
doneCh <- struct{}{}
}()
// Will IO block due to the FIFO
if err := Do(intermediateName, []string{files[i]}, opts...); err != nil {
log.Error().
Err(err).
Str("file", files[i]).
Str("intermediate", intermediateName).
Msg("failed to remux to intermediate file")
}

// Remove the FIFO
if useFIFO {
_ = os.Remove(intermediateName)
}
}(intermediateName)

go func(intermediateName string) {
defer wg.Done()
select {
case <-doneCh:
return
case <-ctx.Done():
// Remove the FIFO
}

// Flush fifo
if useFIFO {
if err := flushFIFO(intermediateName); err != nil {
log.Err(err).Msg("failed to flush FIFO")
}

_ = os.Remove(intermediateName)
}
}(intermediateName)
}

if !useFIFO {
// Wait for all the remuxing to finish
wg.Wait()
}

return intermediates, useFIFO, nil
}

func flushFIFO(file string) error {
// Open the FIFO for reading
fifo, err := os.OpenFile(file, os.O_RDONLY, 0600)
if err != nil {
return err
}
defer fifo.Close()

// Read all data from the FIFO
buffer := make([]byte, 1024)
for {
n, err := fifo.Read(buffer)
if err != nil {
if err == io.EOF {
break
}
return err
}
if n == 0 {
break
}
}

return nil
}
50 changes: 50 additions & 0 deletions video/concat/remux_intermediate_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//go:build windows

package concat

import (
"context"
"sync"

"github.com/Darkness4/fc2-live-dl-go/utils"
"github.com/rs/zerolog/log"
)

// remuxMixedTS remuxes mixed TS/AAC files into intermediate format.
func remuxMixedTS(
_ context.Context, // ctx is not used as operations are IO bound and has finality.
files []string,
opts ...Option,
) (intermediates []string, useFIFO bool, err error) {
intermediates = make([]string, 0, len(files))

var wg sync.WaitGroup

// Check if there are mixed formats
log.Warn().Msg("mixed formats detected, intermediate files will be created")

// Remux all the files into intermediate format
for _, file := range files {
wg.Add(1)
randName := utils.GenerateRandomString(8)
intermediateName := "." + file + "." + randName + ".ts"
intermediates = append(intermediates, intermediateName)

// Make mpegts intermediates
go func() {
defer wg.Done()
// Will IO block due to the FIFO
if err := Do(intermediateName, []string{file}, opts...); err != nil {
log.Error().
Err(err).
Str("file", file).
Msg("failed to remux to intermediate file")
}
}()
}

// Wait for all the remuxing to finish
wg.Wait()

return intermediates, useFIFO, nil
}

0 comments on commit 77d5afc

Please sign in to comment.