-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* starting * pcr write * go-astikit replacement until PR is merged * packet header, adaptation field, dts write * dependency cleanup * get rid of panic/recover for writing * make writePCR code more adequate * writePacket and adaptation field length calculation * writePacket and adaptation field length calculation * s/188/MpegTsPacketSize/ * writePATSection * Try* -> BitsWriterBatch * descriptors WIP * go-astikit version bump * descriptors WIP * descriptor parsing tests refactored to allow reuse for descriptor writing * descriptors writing tested * descriptors writing refactoring * descriptors done, PMT WIP * write PMT section fix * writePSIData works * WIP * PES WIP * PES functions pass tests * minor fix * muxer: pat & pmt * muxer: more tests * muxer: payload writing * es-split WIP * es-split seems to work * es-split PCR sync; some style fixes * Data.Kind cleanup * comment update * cleanup * cleanup * go-astikit dep replace removed * comment fix * minor fix * flush on pid change removed as it seems to be unnecessary * added some streamtype info funcs * StreamType and PSITableTypeID are special types now * comment cleanup * use PSITableTypeId more instead of comparing strings * comment cleanup * PSITableTypeId -> PSITableTypeID * PESIsVideoStreamId -> PESIsVideoStreamID * PSITableTypeID.String() -> PSITableTypeID.Type() * review fixes: first pack: constants and stuff * packet_buffer read() renamed to peek() * tools are moved to cmd directory * correct prefixes for muxer and demuxer opts * SetPCRPID instead of isPCRPID of AddElementaryStream * test fix and some comments * muxer WritePacket export * `astits.New` renamed to `NewDemuxer` * astikit version bump; writeBytesN removed in favor of one in BitsWriter * WritePayload -> WriteData with MuxerData Co-authored-by: Ilya Barbashov <[email protected]>
- Loading branch information
Showing
34 changed files
with
4,223 additions
and
704 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"context" | ||
"flag" | ||
"fmt" | ||
"github.com/asticode/go-astikit" | ||
"github.com/asticode/go-astits" | ||
"log" | ||
"os" | ||
"path" | ||
"time" | ||
) | ||
|
||
const ( | ||
ioBufSize = 10 * 1024 * 1024 | ||
) | ||
|
||
type muxerOut struct { | ||
f *os.File | ||
w *bufio.Writer | ||
} | ||
|
||
func main() { | ||
flag.Usage = func() { | ||
fmt.Fprintf(flag.CommandLine.Output(), "Split TS file into multiple files each holding one elementary stream") | ||
fmt.Fprintf(flag.CommandLine.Output(), "%s [FLAGS] INPUT_FILE:\n", os.Args[0]) | ||
flag.PrintDefaults() | ||
} | ||
outDir := flag.String("o", "out", "Output dir, 'out' by default") | ||
inputFile := astikit.FlagCmd() | ||
flag.Parse() | ||
|
||
infile, err := os.Open(inputFile) | ||
if err != nil { | ||
log.Fatalf("%v", err) | ||
} | ||
defer infile.Close() | ||
|
||
_, err = os.Stat(*outDir) | ||
if !os.IsNotExist(err) { | ||
log.Fatalf("can't write to `%s': already exists", *outDir) | ||
} | ||
|
||
if err = os.MkdirAll(*outDir, os.ModePerm); err != nil { | ||
log.Fatalf("%v", err) | ||
} | ||
|
||
demux := astits.NewDemuxer( | ||
context.Background(), | ||
bufio.NewReaderSize(infile, ioBufSize), | ||
) | ||
|
||
var pat *astits.PATData | ||
// key is program number | ||
pmts := map[uint16]*astits.PMTData{} | ||
gotAllPMTs := false | ||
// key is pid | ||
muxers := map[uint16]*astits.Muxer{} | ||
outfiles := map[uint16]muxerOut{} | ||
|
||
pmtsPrinted := false | ||
|
||
timeStarted := time.Now() | ||
bytesWritten := 0 | ||
|
||
for { | ||
d, err := demux.NextData() | ||
if err != nil { | ||
if err == astits.ErrNoMorePackets { | ||
break | ||
} | ||
log.Fatalf("%v", err) | ||
} | ||
|
||
if d.PAT != nil { | ||
pat = d.PAT | ||
gotAllPMTs = false | ||
continue | ||
} | ||
|
||
if d.PMT != nil { | ||
pmts[d.PMT.ProgramNumber] = d.PMT | ||
|
||
gotAllPMTs = true | ||
for _, p := range pat.Programs { | ||
_, ok := pmts[p.ProgramNumber] | ||
if !ok { | ||
gotAllPMTs = false | ||
break | ||
} | ||
} | ||
|
||
if !gotAllPMTs { | ||
continue | ||
} | ||
|
||
if !pmtsPrinted { | ||
log.Printf("Got all PMTs") | ||
} | ||
for _, pmt := range pmts { | ||
if !pmtsPrinted { | ||
log.Printf("\tProgram %d PCR PID %d", pmt.ProgramNumber, pmt.PCRPID) | ||
} | ||
for _, es := range pmt.ElementaryStreams { | ||
_, ok := muxers[es.ElementaryPID] | ||
if ok { | ||
continue | ||
} | ||
|
||
esFilename := path.Join(*outDir, fmt.Sprintf("%d.ts", es.ElementaryPID)) | ||
outfile, err := os.Create(esFilename) | ||
if err != nil { | ||
log.Fatalf("%v", err) | ||
} | ||
|
||
bufWriter := bufio.NewWriterSize(outfile, ioBufSize) | ||
mux := astits.NewMuxer(context.Background(), bufWriter) | ||
err = mux.AddElementaryStream(*es) | ||
if err != nil { | ||
log.Fatalf("%v", err) | ||
} | ||
mux.SetPCRPID(es.ElementaryPID) | ||
|
||
outfiles[es.ElementaryPID] = muxerOut{ | ||
f: outfile, | ||
w: bufWriter, | ||
} | ||
muxers[es.ElementaryPID] = mux | ||
|
||
if !pmtsPrinted { | ||
log.Printf("\t\tES PID %d type %s", | ||
es.ElementaryPID, es.StreamType.String(), | ||
) | ||
} | ||
} | ||
} | ||
|
||
pmtsPrinted = true | ||
continue | ||
} | ||
|
||
if !gotAllPMTs { | ||
continue | ||
} | ||
|
||
if d.PES == nil { | ||
continue | ||
} | ||
|
||
pid := d.FirstPacket.Header.PID | ||
mux, ok := muxers[pid] | ||
if !ok { | ||
log.Printf("Got payload for unknown PID %d", pid) | ||
continue | ||
} | ||
|
||
af := d.FirstPacket.AdaptationField | ||
|
||
if af != nil && af.HasPCR { | ||
af.HasPCR = false | ||
} | ||
|
||
var pcr *astits.ClockReference | ||
if d.PES.Header.OptionalHeader.PTSDTSIndicator == astits.PTSDTSIndicatorBothPresent { | ||
pcr = d.PES.Header.OptionalHeader.DTS | ||
} else if d.PES.Header.OptionalHeader.PTSDTSIndicator == astits.PTSDTSIndicatorOnlyPTS { | ||
pcr = d.PES.Header.OptionalHeader.PTS | ||
} | ||
|
||
if pcr != nil { | ||
if af == nil { | ||
af = &astits.PacketAdaptationField{} | ||
} | ||
af.HasPCR = true | ||
af.PCR = pcr | ||
} | ||
|
||
n, err := mux.WriteData(&astits.MuxerData{ | ||
PID: pid, | ||
AdaptationField: af, | ||
PES: d.PES, | ||
}) | ||
if err != nil { | ||
log.Fatalf("%v", err) | ||
} | ||
|
||
bytesWritten += n | ||
} | ||
|
||
timeDiff := time.Since(timeStarted) | ||
log.Printf("%d bytes written at rate %.02f mb/s", bytesWritten, (float64(bytesWritten)/1024.0/1024.0)/timeDiff.Seconds()) | ||
|
||
for _, f := range outfiles { | ||
if err = f.w.Flush(); err != nil { | ||
log.Printf("Error flushing %s: %v", f.f.Name(), err) | ||
} | ||
if err = f.f.Close(); err != nil { | ||
log.Printf("Error closing %s: %v", f.f.Name(), err) | ||
} | ||
} | ||
|
||
log.Printf("Done") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package astits | ||
|
||
const ( | ||
crc32Polynomial = uint32(0xffffffff) | ||
) | ||
|
||
// computeCRC32 computes a CRC32 | ||
// https://stackoverflow.com/questions/35034042/how-to-calculate-crc32-in-psi-si-packet | ||
func computeCRC32(bs []byte) uint32 { | ||
return updateCRC32(crc32Polynomial, bs) | ||
} | ||
|
||
func updateCRC32(crc32 uint32, bs []byte) uint32 { | ||
for _, b := range bs { | ||
for i := 0; i < 8; i++ { | ||
if (crc32 >= uint32(0x80000000)) != (b >= uint8(0x80)) { | ||
crc32 = (crc32 << 1) ^ 0x04C11DB7 | ||
} else { | ||
crc32 = crc32 << 1 | ||
} | ||
b <<= 1 | ||
} | ||
} | ||
return crc32 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.