Задать вопрос

Почему видео по RTSP пишет только первых два кадра?

Нашел скриптик на GoLangна просторах гитхаба, и допилил его. Видео пишет в файл, все работает без запинок. Но, на этом все заканчивается, во время исполнения видео-файл в формате H264 увеличивается в размере. Открываю записанный файл через VLC, вижу длительность видео 00:00, во время проигрыша видео, показывает только первых два кадра и усё. Растолкуйте, в чем может быть проблема? С Go имею дело недавно. Так что прошу сильно не пинать, а если пинать, то по сути.

Вот собсно, код:
package main

import "fmt"
import "net"
import "bufio"
import "strings"
import "strconv"
import "encoding/base64"
import "os"
import "bytes"
import "time"
import "flag"

var fuaBuffer *bytes.Buffer
var f *os.File

var  server = flag.String("s", "122.12.528.71:554", "server address host")
var  login = flag.String("l", "admin", "login")
var  pass = flag.String("p", "somepass", "password")
var  link = flag.String("link", "/Stream/Cha/101","link")
var  recordMinutes = flag.Int("t", 1, "record time length in minutes")
var  outputFile = flag.String("o", "", "output file")


func readHeader(reader *bufio.Reader) map[string]string {
	result := make(map[string]string)

	for{
		line, _, err := reader.ReadLine();
		if err != nil{
			panic(err)
		}
		if string(line)=="" {
			break
		}

		fmt.Println(string(line))

		keyvalue := strings.SplitN(string(line),":", 2)
		if len(keyvalue) > 1{
			result[strings.ToUpper(keyvalue[0])] = strings.TrimSpace(keyvalue[1])
		}
	}

	fmt.Println()

	return result

}

func readBody(reader *bufio.Reader, contentLength int) (result string){
	if(contentLength < 0){

		buf := make([]byte, 512)
		for{
			read, _ := reader.Read(buf)
			if read == 0 {
				return
			}else{
				result += string(buf)
			}

		}
	}else{
		buf := make([]byte, contentLength)
		start := 0

		for ;start < contentLength; {
			readed, _ := reader.Read(buf[start:])
			result += string(buf)

			start += readed
		}


	}

	return result
}

func request(conn net.Conn, reader *bufio.Reader, action, url string, hs map[string]string, seq int) (map[string]string, string){

	req := action + " " + url + " RTSP/1.0\r\n"
	for k, v := range hs{
		req += k + ": " + v + "\r\n"
	}
	req += fmt.Sprintf("CSeq: %d\r\n", seq)
	req += "\r\n"

	fmt.Print(req)

	conn.Write([]byte(req))

	headers := readHeader(reader)

	contentLength := 0
	value, ok := headers["CONTENT-LENGTH"]
	if ok {
		contentLength, _ = strconv.Atoi(value)
	}


	if contentLength != 0{
		return headers, readBody(reader, contentLength)
	}

	return headers, ""
}

func main(){

	flag.Parse()

	conn, err := net.Dial("tcp", *server);

	if err != nil {
		fmt.Printf("connect server fail...%v\n", err);
		return
	}

	url := "rtsp://" + *server
	
        seq := 1
	fmt.Println(url)

	reader := bufio.NewReader(conn)

	//dobavlennui header
            headers, bod := request(conn, reader, "OPTIONS", url, (map[string]string{
        	"User-Agent" : "GLOBALNET cam service (LIVE555 Streaming Media v2018.07.24)",
            }), seq)
	fmt.Println(bod)
    seq++



	headers, body := request(conn, reader, "DESCRIBE", url, nil, seq)
	seq++

	fmt.Println(body)

	var ppsSps [][]byte

	startPos := strings.Index(body, "sprop-parameter-sets")

	fmt.Println(startPos)
	
	if startPos > 0{

		startPos += strings.Index(body[startPos:], "=")
		endPos := startPos + strings.Index(body[startPos:], "\r\n")
		ppsSpsBase64 := strings.Split(body[startPos + 1:endPos], ",")
		ppsSps = make([][]byte, len(ppsSpsBase64))
		for i, item := range ppsSpsBase64{
			ppsSps[i], _ = base64.StdEncoding.DecodeString(item)
		}
	}


	var controlUrl string
	startPos = strings.Index(body, "video")
	startPos += strings.Index(body[startPos:], "control")
	if startPos > 0{
		startPos += strings.Index(body[startPos:], ":")
		endPos := startPos + strings.Index(body[startPos:], "\r\n")
		controlUrl = body[startPos+1:endPos]
	}

	playUrl := controlUrl
	headers, _ = request(conn, reader, "SETUP", playUrl, (map[string]string{
		"Transport" : "RTP/AVP/TCP;unicast;interleaved=0-1",
		}), seq)
	seq++


	session, _ := headers["SESSION"]
	headers, _ = request(conn, reader, "PLAY", playUrl, (map[string]string{
		"Session" : session,
		}), seq)
	seq++


	f, err = os.Create(*outputFile)
	defer func(){
		f.Close()
	}()

	if err != nil{
		fmt.Println(err)
		return
	}

	for _, pps := range ppsSps{
		onNalu(pps)
	}

	go func(){
		for{
			conn, _ := net.Dial("tcp", *server);
			reader := bufio.NewReader(conn)
			_, body := request(conn, reader, "GET_PARAMETER", playUrl, (map[string]string{
				"Session" : session,
				}), seq)
			seq++

			fmt.Println(body)

			conn.Close()
			conn = nil

			time.Sleep(30*time.Second)
		}
	}()

	go func(){
		readAVPData(reader)
	}()

	<- time.After(time.Duration(*recordMinutes)*time.Minute)

}

func readAVPData(reader *bufio.Reader){


	for {

	magicNum, err := reader.ReadByte()
	channel, _ := reader.ReadByte()
	dataLengthHi, _ := reader.ReadByte()
	dataLengthLow, _ := reader.ReadByte()
	dataLength := (int)(dataLengthHi)*int(256) + (int)(dataLengthLow)
	data := make([]byte, dataLength)
	offset := 0
	readed := 0
	for ;offset < dataLength; offset += readed{
		readed, err = reader.Read(data[offset:])
		if err != nil{
			break
		}
	}
	
	if err != nil{
		fmt.Println(err)
		break
	}

	fmt.Printf("magicNum %d channel %d dataLength %d\n", magicNum, channel, dataLength)

	if magicNum != 36{
		fmt.Println("magicNum wrong!")
		break
	}

	if channel != 0{
		continue
	}



	decodeRtp(data)
	

	
	}//end for

}

func decodeRtp(data []byte){

	payload :=data[12:]

	naluType := payload[0] & 0x1f; // 0x1f смотрим тип NAL
	if(naluType > 0 && naluType < 23){
		onNalu(payload)
	}else if(naluType == 28){  // если NAL = 28, значит фрейм влазит в один пакет	
		onFuA(payload) 
	}else{
		fmt.Println("unknown type"); // иначе не известный тип
	}
	
}



func onNalu(data []byte){
	f.Write([]byte{0,0,0,1})
	f.Write(data)
}

func onFuA(data []byte){
	naluType := data[0] & 0xe0
	naluType  |= data[1] &  0x1f
	
	
	start := data[1] >> 7
	end := (data[1] >> 6) & 0x01

	if start > 0{
		fuaBuffer = bytes.NewBuffer(nil)
		fuaBuffer.WriteByte(naluType)
	}

	fuaBuffer.Write(data[2:])
	
	if end > 0{
		onNalu(fuaBuffer.Bytes())
	}
}


Скрипт отрабатывает через команду
go run camrecord.go -o file1.h264 -t 1
где -o это файл который писать, -t - время работы скрипта в минутах, потом завершить запись с потока.
  • Вопрос задан
  • 134 просмотра
Подписаться 3 Средний 3 комментария
Пригласить эксперта
Ответы на вопрос 1
customtema
@customtema
arint.ru
Видеокодек лагает. Пишет ключевик, а потом никак.

Пакет кодеков (например ubuntu-restricted-extras ubuntu-restricted-plugins и т.п.) вообще стоит?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы