Add RTSP preview capture — working with both cameras
Major breakthrough: RTSP preview fully operational on DWARF Mini.
Key discovery: RTSP (port 554) only works AFTER opening the camera via
WebSocket. Without CMD_CAMERA_OPEN (10000/12000), the RTSP server accepts
connections but never sends frames. This was the missing piece.
RTSP details:
- Tele: rtsp://<ip>:554/ch0/stream0
- Wide: rtsp://<ip>:554/ch1/stream0
- Codec: MJPEG over RTSP (not H.264)
- Transport: TCP (confirmed from RtspPlayerView.java ijkplayer options)
- Resolution: 1920x1080 both cameras
Port 8092 (MJPEG HTTP /mainstream, /secondstream) is inactive on the Mini.
The DWARF Mini uses RTSP exclusively, not the HTTP MJPEG fallback.
Added `dwarfctl preview grab [--cam tele|wide] [output.jpg]` that:
1. Opens the camera via WebSocket
2. Waits 2s for RTSP to become available
3. Captures one frame via ffmpeg
Updated API_REFERENCE.md with the corrected RTSP details and the camera-open
prerequisite.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -44,6 +45,7 @@ func main() {
|
||||
cmdMonitor(),
|
||||
cmdInteractive(),
|
||||
cmdPano(),
|
||||
cmdPreview(),
|
||||
)
|
||||
|
||||
rootCmd.MarkPersistentFlagRequired("ip")
|
||||
@ -316,9 +318,12 @@ func cmdCamera() *cobra.Command {
|
||||
},
|
||||
},
|
||||
)
|
||||
// Add --cam to all subcommands
|
||||
// Add --cam to all subcommands, --raw to photo only
|
||||
for _, sub := range c.Commands() {
|
||||
sub.Flags().String("cam", "tele", "camera: tele|wide")
|
||||
if sub.Name() == "photo" {
|
||||
sub.Flags().Bool("raw", false, "capture RAW instead of JPEG")
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
@ -662,6 +667,45 @@ func cmdPower() *cobra.Command {
|
||||
return c
|
||||
}
|
||||
|
||||
// --- preview ---
|
||||
|
||||
func cmdPreview() *cobra.Command {
|
||||
c := &cobra.Command{Use: "preview", Short: "RTSP preview frame capture"}
|
||||
c.AddCommand(
|
||||
&cobra.Command{
|
||||
Use: "grab [--cam tele|wide] [output.jpg]",
|
||||
Short: "Capture one frame from RTSP (opens camera automatically)",
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cam := mustCam(flagCam(cmd))
|
||||
ch := "ch0"
|
||||
if cam == api.CameraWide {
|
||||
ch = "ch1"
|
||||
}
|
||||
out := "/tmp/preview.jpg"
|
||||
if len(args) > 0 {
|
||||
out = args[0]
|
||||
}
|
||||
scope, cleanup := dial()
|
||||
must(scope.OpenCamera(cam))
|
||||
cleanup()
|
||||
time.Sleep(2 * time.Second)
|
||||
url := fmt.Sprintf("rtsp://%s:554/%s/stream0", flagIP, ch)
|
||||
ffmpegCmd := exec.Command("ffmpeg", "-rtsp_transport", "tcp",
|
||||
"-i", url, "-frames:v", "1", "-q:v", "2", "-y", out)
|
||||
if err := ffmpegCmd.Run(); err != nil {
|
||||
die("ffmpeg: %v (is ffmpeg installed?)", err)
|
||||
}
|
||||
fmt.Printf("frame saved to %s\n", out)
|
||||
},
|
||||
},
|
||||
)
|
||||
for _, sub := range c.Commands() {
|
||||
sub.Flags().String("cam", "tele", "camera: tele|wide")
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// --- panorama ---
|
||||
|
||||
func cmdPano() *cobra.Command {
|
||||
|
||||
Reference in New Issue
Block a user