mirror of
https://github.com/bluenviron/mediamtx
synced 2025-02-26 00:20:36 +00:00
277 lines
6.0 KiB
Go
277 lines
6.0 KiB
Go
package playback
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/bluenviron/mediacommon/pkg/formats/fmp4"
|
|
"github.com/bluenviron/mediacommon/pkg/formats/fmp4/seekablebuffer"
|
|
"github.com/bluenviron/mediamtx/internal/conf"
|
|
"github.com/bluenviron/mediamtx/internal/test"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func writeSegment1(t *testing.T, fpath string) {
|
|
init := fmp4.Init{
|
|
Tracks: []*fmp4.InitTrack{{
|
|
ID: 1,
|
|
TimeScale: 90000,
|
|
Codec: &fmp4.CodecH264{
|
|
SPS: test.FormatH264.SPS,
|
|
PPS: test.FormatH264.PPS,
|
|
},
|
|
}},
|
|
}
|
|
|
|
var buf1 seekablebuffer.Buffer
|
|
err := init.Marshal(&buf1)
|
|
require.NoError(t, err)
|
|
|
|
var buf2 seekablebuffer.Buffer
|
|
parts := fmp4.Parts{
|
|
{
|
|
SequenceNumber: 1,
|
|
Tracks: []*fmp4.PartTrack{{
|
|
ID: 1,
|
|
BaseTime: 0,
|
|
Samples: []*fmp4.PartSample{},
|
|
}},
|
|
},
|
|
{
|
|
SequenceNumber: 1,
|
|
Tracks: []*fmp4.PartTrack{{
|
|
ID: 1,
|
|
BaseTime: 30 * 90000,
|
|
Samples: []*fmp4.PartSample{
|
|
{
|
|
Duration: 30 * 90000,
|
|
IsNonSyncSample: false,
|
|
Payload: []byte{1, 2},
|
|
},
|
|
{
|
|
Duration: 1 * 90000,
|
|
IsNonSyncSample: false,
|
|
Payload: []byte{3, 4},
|
|
},
|
|
{
|
|
Duration: 1 * 90000,
|
|
IsNonSyncSample: true,
|
|
Payload: []byte{5, 6},
|
|
},
|
|
},
|
|
}},
|
|
},
|
|
}
|
|
err = parts.Marshal(&buf2)
|
|
require.NoError(t, err)
|
|
|
|
err = os.WriteFile(fpath, append(buf1.Bytes(), buf2.Bytes()...), 0o644)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func writeSegment2(t *testing.T, fpath string) {
|
|
init := fmp4.Init{
|
|
Tracks: []*fmp4.InitTrack{{
|
|
ID: 1,
|
|
TimeScale: 90000,
|
|
Codec: &fmp4.CodecH264{
|
|
SPS: test.FormatH264.SPS,
|
|
PPS: test.FormatH264.PPS,
|
|
},
|
|
}},
|
|
}
|
|
|
|
var buf1 seekablebuffer.Buffer
|
|
err := init.Marshal(&buf1)
|
|
require.NoError(t, err)
|
|
|
|
var buf2 seekablebuffer.Buffer
|
|
parts := fmp4.Parts{
|
|
{
|
|
SequenceNumber: 1,
|
|
Tracks: []*fmp4.PartTrack{{
|
|
ID: 1,
|
|
BaseTime: 0,
|
|
Samples: []*fmp4.PartSample{
|
|
{
|
|
Duration: 1 * 90000,
|
|
IsNonSyncSample: false,
|
|
Payload: []byte{7, 8},
|
|
},
|
|
{
|
|
Duration: 1 * 90000,
|
|
IsNonSyncSample: false,
|
|
Payload: []byte{9, 10},
|
|
},
|
|
},
|
|
}},
|
|
},
|
|
}
|
|
err = parts.Marshal(&buf2)
|
|
require.NoError(t, err)
|
|
|
|
err = os.WriteFile(fpath, append(buf1.Bytes(), buf2.Bytes()...), 0o644)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestServerGet(t *testing.T) {
|
|
dir, err := os.MkdirTemp("", "mediamtx-playback")
|
|
require.NoError(t, err)
|
|
defer os.RemoveAll(dir)
|
|
|
|
err = os.Mkdir(filepath.Join(dir, "mypath"), 0o755)
|
|
require.NoError(t, err)
|
|
|
|
writeSegment1(t, filepath.Join(dir, "mypath", "2008-11-07_11-22-00-500000.mp4"))
|
|
writeSegment2(t, filepath.Join(dir, "mypath", "2008-11-07_11-23-02-500000.mp4"))
|
|
|
|
s := &Server{
|
|
Address: "127.0.0.1:9996",
|
|
ReadTimeout: conf.StringDuration(10 * time.Second),
|
|
PathConfs: map[string]*conf.Path{
|
|
"mypath": {
|
|
Playback: true,
|
|
RecordPath: filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f"),
|
|
},
|
|
},
|
|
Parent: &test.NilLogger{},
|
|
}
|
|
err = s.Initialize()
|
|
require.NoError(t, err)
|
|
defer s.Close()
|
|
|
|
v := url.Values{}
|
|
v.Set("path", "mypath")
|
|
v.Set("start", time.Date(2008, 11, 0o7, 11, 23, 1, 500000000, time.Local).Format(time.RFC3339Nano))
|
|
v.Set("duration", "2")
|
|
v.Set("format", "fmp4")
|
|
|
|
u := &url.URL{
|
|
Scheme: "http",
|
|
Host: "localhost:9996",
|
|
Path: "/get",
|
|
RawQuery: v.Encode(),
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
|
require.NoError(t, err)
|
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer res.Body.Close()
|
|
|
|
require.Equal(t, http.StatusOK, res.StatusCode)
|
|
|
|
buf, err := io.ReadAll(res.Body)
|
|
require.NoError(t, err)
|
|
|
|
var parts fmp4.Parts
|
|
err = parts.Unmarshal(buf)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, fmp4.Parts{
|
|
{
|
|
SequenceNumber: 0,
|
|
Tracks: []*fmp4.PartTrack{
|
|
{
|
|
ID: 1,
|
|
Samples: []*fmp4.PartSample{
|
|
{
|
|
Duration: 0,
|
|
Payload: []byte{3, 4},
|
|
},
|
|
{
|
|
Duration: 90000,
|
|
IsNonSyncSample: true,
|
|
Payload: []byte{5, 6},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
SequenceNumber: 0,
|
|
Tracks: []*fmp4.PartTrack{
|
|
{
|
|
ID: 1,
|
|
BaseTime: 90000,
|
|
Samples: []*fmp4.PartSample{
|
|
{
|
|
Duration: 90000,
|
|
Payload: []byte{7, 8},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}, parts)
|
|
}
|
|
|
|
func TestServerList(t *testing.T) {
|
|
dir, err := os.MkdirTemp("", "mediamtx-playback")
|
|
require.NoError(t, err)
|
|
defer os.RemoveAll(dir)
|
|
|
|
err = os.Mkdir(filepath.Join(dir, "mypath"), 0o755)
|
|
require.NoError(t, err)
|
|
|
|
writeSegment1(t, filepath.Join(dir, "mypath", "2008-11-07_11-22-00-500000.mp4"))
|
|
writeSegment2(t, filepath.Join(dir, "mypath", "2008-11-07_11-23-02-500000.mp4"))
|
|
writeSegment2(t, filepath.Join(dir, "mypath", "2009-11-07_11-23-02-500000.mp4"))
|
|
|
|
s := &Server{
|
|
Address: "127.0.0.1:9996",
|
|
ReadTimeout: conf.StringDuration(10 * time.Second),
|
|
PathConfs: map[string]*conf.Path{
|
|
"mypath": {
|
|
Playback: true,
|
|
RecordPath: filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f"),
|
|
},
|
|
},
|
|
Parent: &test.NilLogger{},
|
|
}
|
|
err = s.Initialize()
|
|
require.NoError(t, err)
|
|
defer s.Close()
|
|
|
|
v := url.Values{}
|
|
v.Set("path", "mypath")
|
|
|
|
u := &url.URL{
|
|
Scheme: "http",
|
|
Host: "localhost:9996",
|
|
Path: "/list",
|
|
RawQuery: v.Encode(),
|
|
}
|
|
|
|
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
|
|
require.NoError(t, err)
|
|
|
|
res, err := http.DefaultClient.Do(req)
|
|
require.NoError(t, err)
|
|
defer res.Body.Close()
|
|
|
|
require.Equal(t, http.StatusOK, res.StatusCode)
|
|
|
|
var out interface{}
|
|
err = json.NewDecoder(res.Body).Decode(&out)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []interface{}{
|
|
map[string]interface{}{
|
|
"duration": float64(64),
|
|
"start": time.Date(2008, 11, 0o7, 11, 22, 0, 500000000, time.Local).Format(time.RFC3339Nano),
|
|
},
|
|
map[string]interface{}{
|
|
"duration": float64(2),
|
|
"start": time.Date(2009, 11, 0o7, 11, 23, 2, 500000000, time.Local).Format(time.RFC3339Nano),
|
|
},
|
|
}, out)
|
|
}
|