user5717177
user5717177

Reputation:

Overwriting TS Stream File with FFMPEG in Linux

I'm trying to convert rtmp streams to m3u8 stream. To reach that aim I use FFMPEG. Now, there is no problem with converting and downloading. However, it writes lots of .ts file such as channel0000.ts,channel0001.ts,channel0002.ts. Per every 10 seconds, 1 ts file is created. In this point, I want a single ts file. In other words, I need overwriting because I don't want to store all the stream I need just last 10 seconds. When I try to write on the same file I get this error:

Invalid segment filename template 'channel.ts'
Could not write header for output file #0 (incorrect codec parameters ?):   Invalid argumentStream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #0:1 -> #0:1 (copy)
Last message repeated 1 times

Here is my FFMPEG command.

ffmpeg -loglevel quiet -i rtmp://example -c:v libx264 -profile:v baseline -level 3.1 -c:a aac -strict experimental -f mpegts - | ffmpeg -i - -c copy -map 0 -f segment -segment_list channel.m3u8 -segment_format mpegts -segment_time 10 channel%04d.ts

Any suggestion?

Upvotes: 2

Views: 2068

Answers (2)

Alex SHP
Alex SHP

Reputation: 143

I had a similar issue, my solution was to pipe out the entire result of the hls muxer, except for the header file using the -hls_segment_filename pipe:1 option (I'm therefore just piping out the .ts files and not the .m3u8 ones).

On my pipe out, i stuck a piece of code I wrote that detects the header of a .ts file, which looks something like the bytes [71, 64, 17, 1X, 0, 66, 240, 34, 0, 1, 193, 0, 0, 255, 1, 255, 0, 1, 252, 128, 17, 72] (I recommend GHex to check yoour .ts files if you want more of the header to discriminate). I then made a piece of code that cuts along this line (warning, the fourth byte here can change its value, but it is the only one), and recomposes the file.

The only thing left to do I think for your application is to use a queue for the file's content. If you want ten seconds and your file are about 1s you can use a queue of length 10.

My code was in go (because my whole project was), so here's a bit of code in go that might help :

type tsFile struct {
  contents []byte
  finished bool
  child *tsFile
}

func in(a int, array int[]) bool{
  for _, b := range list {
    if b == a {
      return true
    }
  }
  return false
}

func CutAdd(curFile *tsFile, pipedOut []bytes){
  header := [...]bytes{} // insert here the header you want
  unNeededIndex := [...]int{3} // insert here the bytes indexes that change between files
  cur_header_pointer := 0
  header_cache := make([]byte, 0, len(header))
  for i, b := range(pipedOut){
    if header[cur_header_pointer] == b || in(cur_header_pointer, unNeededIndex){
      header_cache = append(header_cache, b)
      cur_header_pointer ++
      if cur_header_pointer == len(header){
        curFile.finished = true
        curFile.child = &tsFile{contents : header_cache}
        CutAdd(curFile.child, pipedOut[i:])
        return
      }
    } else {
      if cur_header_pointer != 0 {
        for _, cached_b := range(header_cache){
          curFile.contents = append(curFile.contents, cached_b) // we store what we thought was a header
        }
        cur_header_pointer = 0
      }
      curFile.contents = append(curFile.contents, b) // we store the byte
    }
  }
}

It is a bit janky, but it works for me (also there might be mistakes, I didn't put the actual code I made then, but you should have a rough idea of what I mean)

Upvotes: 0

user5717177
user5717177

Reputation:

In FFMPEG documentation, I found "segment_wrap" options. When you add this option, files are written in a loop. In my case I added "-segment_wrap 1" command part and it writes just a single file now.

Upvotes: 1

Related Questions