mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Fix #1641, HLS/RTC picture corrupt for SPS/PPS lost. v4.0.175
This commit is contained in:
parent
71ed6e5dc5
commit
29cf13afa0
5 changed files with 164 additions and 17 deletions
123
trunk/3rdparty/srs-bench/srs/rtmp_test.go
vendored
123
trunk/3rdparty/srs-bench/srs/rtmp_test.go
vendored
|
@ -21,19 +21,20 @@
|
||||||
package srs
|
package srs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ossrs/go-oryx-lib/avc"
|
|
||||||
"github.com/ossrs/go-oryx-lib/flv"
|
|
||||||
"github.com/pion/interceptor"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ossrs/go-oryx-lib/avc"
|
||||||
|
"github.com/ossrs/go-oryx-lib/flv"
|
||||||
"github.com/ossrs/go-oryx-lib/logger"
|
"github.com/ossrs/go-oryx-lib/logger"
|
||||||
"github.com/ossrs/go-oryx-lib/rtmp"
|
"github.com/ossrs/go-oryx-lib/rtmp"
|
||||||
|
"github.com/pion/interceptor"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRtmpPublishPlay(t *testing.T) {
|
func TestRtmpPublishPlay(t *testing.T) {
|
||||||
|
@ -126,12 +127,14 @@ func TestRtmpPublish_RtcPlay(t *testing.T) {
|
||||||
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
|
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
|
||||||
i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
|
i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
|
||||||
nn, attr, err := i.nextRTPReader.Read(payload, attributes)
|
nn, attr, err := i.nextRTPReader.Read(payload, attributes)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
|
return nn, attr, err
|
||||||
|
}
|
||||||
|
|
||||||
if nnPlayReadRTP++; nnPlayReadRTP >= uint64(*srsPlayOKPackets) {
|
if nnPlayReadRTP++; nnPlayReadRTP >= uint64(*srsPlayOKPackets) {
|
||||||
cancel() // Completed.
|
cancel() // Completed.
|
||||||
}
|
}
|
||||||
logger.Tf(ctx, "Play RECV RTP #%v %vB", nnPlayReadRTP, nn)
|
logger.Tf(ctx, "Play RECV RTP #%v %vB", nnPlayReadRTP, nn)
|
||||||
}
|
|
||||||
return nn, attr, err
|
return nn, attr, err
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
@ -280,3 +283,113 @@ func TestRtmpPublish_MultipleSequences(t *testing.T) {
|
||||||
t.Errorf("err %+v", err)
|
t.Errorf("err %+v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRtmpPublish_MultipleSequences_RtcPlay(t *testing.T) {
|
||||||
|
ctx := logger.WithContext(context.Background())
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
|
||||||
|
|
||||||
|
var r0, r1, r2 error
|
||||||
|
err := func() (err error) {
|
||||||
|
streamSuffix := fmt.Sprintf("rtmp-regression-%v-%v", os.Getpid(), rand.Int())
|
||||||
|
rtmpUrl := fmt.Sprintf("%v://%v%v-%v", srsSchema, *srsServer, *srsStream, streamSuffix)
|
||||||
|
|
||||||
|
// Publisher connect to a RTMP stream.
|
||||||
|
publisher := NewRTMPPublisher()
|
||||||
|
defer publisher.Close()
|
||||||
|
|
||||||
|
if err := publisher.Publish(ctx, rtmpUrl); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the RTC player.
|
||||||
|
var thePlayer *testPlayer
|
||||||
|
if thePlayer, err = newTestPlayer(registerMiniCodecs, func(play *testPlayer) error {
|
||||||
|
play.streamSuffix = streamSuffix
|
||||||
|
var nnSpsPps uint64
|
||||||
|
var previousSpsPps []byte
|
||||||
|
return play.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
|
||||||
|
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
|
||||||
|
i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
|
||||||
|
nn, attr, err := i.nextRTPReader.Read(payload, attributes)
|
||||||
|
if err != nil {
|
||||||
|
return nn, attr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
annexb, nalus, err := DemuxRtpSpsPps(payload[:nn])
|
||||||
|
if err != nil || len(nalus) == 0 ||
|
||||||
|
(nalus[0].NALUType != avc.NALUTypeSPS && nalus[0].NALUType != avc.NALUTypePPS) ||
|
||||||
|
bytes.Equal(annexb, previousSpsPps) {
|
||||||
|
return nn, attr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
previousSpsPps = annexb
|
||||||
|
if nnSpsPps++; nnSpsPps >= 2 {
|
||||||
|
cancel() // Completed.
|
||||||
|
}
|
||||||
|
logger.Tf(ctx, "Play RECV SPS/PPS #%v %vB %v", nnSpsPps, nn, nalus[0].NALUType)
|
||||||
|
return nn, attr, err
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer thePlayer.Close()
|
||||||
|
|
||||||
|
// Run publisher and players.
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
defer wg.Wait()
|
||||||
|
|
||||||
|
var playerIceReady context.Context
|
||||||
|
playerIceReady, thePlayer.iceReadyCancel = context.WithCancel(ctx)
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if r1 = thePlayer.Run(logger.WithContext(ctx), cancel); r1 != nil {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
logger.Tf(ctx, "player done")
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
// Wait for player ready.
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-playerIceReady.Done():
|
||||||
|
}
|
||||||
|
|
||||||
|
var nnPackets int
|
||||||
|
ctxAvatar, cancelAvatar := context.WithCancel(ctx)
|
||||||
|
publisher.onSendPacket = func(m *rtmp.Message) error {
|
||||||
|
if m.MessageType == rtmp.MessageTypeVideo {
|
||||||
|
nnPackets++
|
||||||
|
}
|
||||||
|
if nnPackets > 10 {
|
||||||
|
cancelAvatar()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
publisher.closeTransportWhenIngestDone = false
|
||||||
|
if r0 = publisher.Ingest(ctxAvatar, *srsPublishBBB); r0 != nil {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
publisher.closeTransportWhenIngestDone = true
|
||||||
|
if r2 = publisher.Ingest(ctx, *srsPublishAvatar); r2 != nil {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
logger.Tf(ctx, "publisher done")
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
if err := filterTestError(ctx.Err(), err, r0, r1, r2); err != nil {
|
||||||
|
t.Errorf("err %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
41
trunk/3rdparty/srs-bench/srs/util.go
vendored
41
trunk/3rdparty/srs-bench/srs/util.go
vendored
|
@ -29,6 +29,8 @@ import (
|
||||||
"github.com/ossrs/go-oryx-lib/avc"
|
"github.com/ossrs/go-oryx-lib/avc"
|
||||||
"github.com/ossrs/go-oryx-lib/flv"
|
"github.com/ossrs/go-oryx-lib/flv"
|
||||||
"github.com/ossrs/go-oryx-lib/rtmp"
|
"github.com/ossrs/go-oryx-lib/rtmp"
|
||||||
|
"github.com/pion/rtp"
|
||||||
|
"github.com/pion/rtp/codecs"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
@ -1657,3 +1659,42 @@ func IsNALUEquals(a, b *avc.NALU) bool {
|
||||||
|
|
||||||
return bytes.Equal(a.Data, b.Data)
|
return bytes.Equal(a.Data, b.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DemuxRtpSpsPps(payload []byte) ([]byte, []*avc.NALU, error) {
|
||||||
|
// Parse RTP packet.
|
||||||
|
pkt := rtp.Packet{}
|
||||||
|
if err := pkt.Unmarshal(payload); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode H264 packet.
|
||||||
|
h264Packet := codecs.H264Packet{}
|
||||||
|
annexb, err := h264Packet.Unmarshal(pkt.Payload)
|
||||||
|
if err != nil {
|
||||||
|
return annexb, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if not STAP-A
|
||||||
|
if !bytes.HasPrefix(annexb, []byte{0x00, 0x00, 0x00, 0x01}) {
|
||||||
|
return annexb, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse to NALUs
|
||||||
|
rawNalus := bytes.Split(annexb, []byte{0x00, 0x00, 0x00, 0x01})
|
||||||
|
|
||||||
|
nalus := []*avc.NALU{}
|
||||||
|
for _, rawNalu := range rawNalus {
|
||||||
|
if len(rawNalu) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
nalu := avc.NewNALU()
|
||||||
|
if err := nalu.UnmarshalBinary(rawNalu); err != nil {
|
||||||
|
return annexb, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nalus = append(nalus, nalu)
|
||||||
|
}
|
||||||
|
|
||||||
|
return annexb, nalus, nil
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ The changelog for SRS.
|
||||||
|
|
||||||
## SRS 4.0 Changelog
|
## SRS 4.0 Changelog
|
||||||
|
|
||||||
|
* v4.0, 2021-10-11, Fix [#1641](https://github.com/ossrs/srs/issues/1641), HLS/RTC picture corrupt for SPS/PPS lost. v4.0.175
|
||||||
* v4.0, 2021-10-11, RTC: Refine config, aac to rtmp_to_rtc, bframe to keep_bframe. v4.0.174
|
* v4.0, 2021-10-11, RTC: Refine config, aac to rtmp_to_rtc, bframe to keep_bframe. v4.0.174
|
||||||
* v4.0, 2021-10-10, For [#1641](https://github.com/ossrs/srs/issues/1641), Support RTMP publish and play regression test. v4.0.173
|
* v4.0, 2021-10-10, For [#1641](https://github.com/ossrs/srs/issues/1641), Support RTMP publish and play regression test. v4.0.173
|
||||||
* v4.0, 2021-10-10, RTC: Change rtc.aac to discard by default. v4.0.172
|
* v4.0, 2021-10-10, RTC: Change rtc.aac to discard by default. v4.0.172
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
|
|
||||||
#define VERSION_MAJOR 4
|
#define VERSION_MAJOR 4
|
||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_REVISION 174
|
#define VERSION_REVISION 175
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -818,10 +818,6 @@ srs_error_t SrsFormat::avc_demux_sps_pps(SrsBuffer* stream)
|
||||||
if (!stream->require(sequenceParameterSetLength)) {
|
if (!stream->require(sequenceParameterSetLength)) {
|
||||||
return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode SPS data");
|
return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode SPS data");
|
||||||
}
|
}
|
||||||
if (vcodec->sequenceParameterSetNALUnit.size() > 0) {
|
|
||||||
stream->skip(sequenceParameterSetLength);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (sequenceParameterSetLength > 0) {
|
if (sequenceParameterSetLength > 0) {
|
||||||
vcodec->sequenceParameterSetNALUnit.resize(sequenceParameterSetLength);
|
vcodec->sequenceParameterSetNALUnit.resize(sequenceParameterSetLength);
|
||||||
stream->read_bytes(&vcodec->sequenceParameterSetNALUnit[0], sequenceParameterSetLength);
|
stream->read_bytes(&vcodec->sequenceParameterSetNALUnit[0], sequenceParameterSetLength);
|
||||||
|
@ -846,10 +842,6 @@ srs_error_t SrsFormat::avc_demux_sps_pps(SrsBuffer* stream)
|
||||||
if (!stream->require(pictureParameterSetLength)) {
|
if (!stream->require(pictureParameterSetLength)) {
|
||||||
return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode PPS data");
|
return srs_error_new(ERROR_HLS_DECODE_ERROR, "decode PPS data");
|
||||||
}
|
}
|
||||||
if (vcodec->pictureParameterSetNALUnit.size() > 0) {
|
|
||||||
stream->skip(pictureParameterSetLength);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pictureParameterSetLength > 0) {
|
if (pictureParameterSetLength > 0) {
|
||||||
vcodec->pictureParameterSetNALUnit.resize(pictureParameterSetLength);
|
vcodec->pictureParameterSetNALUnit.resize(pictureParameterSetLength);
|
||||||
stream->read_bytes(&vcodec->pictureParameterSetNALUnit[0], pictureParameterSetLength);
|
stream->read_bytes(&vcodec->pictureParameterSetNALUnit[0], pictureParameterSetLength);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue