Skip to content

[Camera] Start the video stream using the parameters from the allocated stream #40658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,45 +60,51 @@ struct SnapshotStream
class CameraAVStreamManager : public CameraAVStreamMgmtDelegate
{
public:
Protocols::InteractionModel::Status VideoStreamAllocate(const VideoStreamStruct & allocateArgs, uint16_t & outStreamID);
Protocols::InteractionModel::Status VideoStreamAllocate(const VideoStreamStruct & allocateArgs,
uint16_t & outStreamID) override;

Protocols::InteractionModel::Status VideoStreamModify(const uint16_t streamID, const chip::Optional<bool> waterMarkEnabled,
const chip::Optional<bool> osdEnabled);
const chip::Optional<bool> osdEnabled) override;

Protocols::InteractionModel::Status VideoStreamDeallocate(const uint16_t streamID);
Protocols::InteractionModel::Status VideoStreamDeallocate(const uint16_t streamID) override;

Protocols::InteractionModel::Status AudioStreamAllocate(const AudioStreamStruct & allocateArgs, uint16_t & outStreamID);
Protocols::InteractionModel::Status AudioStreamAllocate(const AudioStreamStruct & allocateArgs,
uint16_t & outStreamID) override;

Protocols::InteractionModel::Status AudioStreamDeallocate(const uint16_t streamID);
Protocols::InteractionModel::Status AudioStreamDeallocate(const uint16_t streamID) override;

Protocols::InteractionModel::Status SnapshotStreamAllocate(const SnapshotStreamStruct & allocateArgs, uint16_t & outStreamID);
Protocols::InteractionModel::Status SnapshotStreamAllocate(const SnapshotStreamStruct & allocateArgs,
uint16_t & outStreamID) override;

Protocols::InteractionModel::Status SnapshotStreamModify(const uint16_t streamID, const chip::Optional<bool> waterMarkEnabled,
const chip::Optional<bool> osdEnabled);
const chip::Optional<bool> osdEnabled) override;

Protocols::InteractionModel::Status SnapshotStreamDeallocate(const uint16_t streamID);
Protocols::InteractionModel::Status SnapshotStreamDeallocate(const uint16_t streamID) override;

void OnStreamUsagePrioritiesChanged();
void OnVideoStreamAllocated(const VideoStreamStruct & allocatedStream, StreamAllocationAction action) override;

void OnAttributeChanged(AttributeId attributeId);
void OnStreamUsagePrioritiesChanged() override;

void OnAttributeChanged(AttributeId attributeId) override;

Protocols::InteractionModel::Status CaptureSnapshot(const DataModel::Nullable<uint16_t> streamID,
const VideoResolutionStruct & resolution, ImageSnapshot & outImageSnapshot);
const VideoResolutionStruct & resolution,
ImageSnapshot & outImageSnapshot) override;

CHIP_ERROR
LoadAllocatedVideoStreams(std::vector<VideoStreamStruct> & allocatedVideoStreams);
LoadAllocatedVideoStreams(std::vector<VideoStreamStruct> & allocatedVideoStreams) override;

CHIP_ERROR
LoadAllocatedAudioStreams(std::vector<AudioStreamStruct> & allocatedAudioStreams);
LoadAllocatedAudioStreams(std::vector<AudioStreamStruct> & allocatedAudioStreams) override;

CHIP_ERROR
LoadAllocatedSnapshotStreams(std::vector<SnapshotStreamStruct> & allocatedSnapshotStreams);
LoadAllocatedSnapshotStreams(std::vector<SnapshotStreamStruct> & allocatedSnapshotStreams) override;

CHIP_ERROR PersistentAttributesLoadedCallback();
CHIP_ERROR PersistentAttributesLoadedCallback() override;

CHIP_ERROR OnTransportAcquireAudioVideoStreams(uint16_t audioStreamID, uint16_t videoStreamID);
CHIP_ERROR OnTransportAcquireAudioVideoStreams(uint16_t audioStreamID, uint16_t videoStreamID) override;

CHIP_ERROR OnTransportReleaseAudioVideoStreams(uint16_t audioStreamID, uint16_t videoStreamID);
CHIP_ERROR OnTransportReleaseAudioVideoStreams(uint16_t audioStreamID, uint16_t videoStreamID) override;

void Init();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ Protocols::InteractionModel::Status CameraAVStreamManager::SnapshotStreamDealloc
return Status::Success;
}

void CameraAVStreamManager::OnVideoStreamAllocated(const VideoStreamStruct & allocatedStream, StreamAllocationAction action)
{
ChipLogProgress(Zcl, "Video stream has been allocated");
}

void CameraAVStreamManager::OnStreamUsagePrioritiesChanged()
{
ChipLogProgress(Zcl, "Stream usage priorities changed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class CameraDeviceInterface
virtual CameraError CaptureSnapshot(const chip::app::DataModel::Nullable<uint16_t> streamID,
const VideoResolutionStruct & resolution, ImageSnapshot & outImageSnapshot) = 0;
// Start video stream
virtual CameraError StartVideoStream(uint16_t streamID) = 0;
virtual CameraError StartVideoStream(const VideoStreamStruct & allocatedStream) = 0;

// Stop video stream
virtual CameraError StopVideoStream(uint16_t streamID) = 0;
Expand Down
2 changes: 1 addition & 1 deletion examples/camera-app/linux/include/camera-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class CameraDevice : public CameraDeviceInterface, public CameraDeviceInterface:
CameraError CaptureSnapshot(const chip::app::DataModel::Nullable<uint16_t> streamID, const VideoResolutionStruct & resolution,
ImageSnapshot & outImageSnapshot) override;

CameraError StartVideoStream(uint16_t streamID) override;
CameraError StartVideoStream(const VideoStreamStruct & allocatedStream) override;

// Stop video stream
CameraError StopVideoStream(uint16_t streamID) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "camera-avstream-controller.h"
#include "camera-device-interface.h"
#include <app/clusters/camera-av-stream-management-server/camera-av-stream-management-server.h>
#include <app/util/config.h>
#include <vector>

Expand Down Expand Up @@ -55,6 +56,8 @@ class CameraAVStreamManager : public CameraAVStreamMgmtDelegate, public CameraAV

Protocols::InteractionModel::Status SnapshotStreamDeallocate(const uint16_t streamID) override;

void OnVideoStreamAllocated(const VideoStreamStruct & allocatedStream, StreamAllocationAction action) override;

void OnStreamUsagePrioritiesChanged() override;

void OnAttributeChanged(AttributeId attributeId) override;
Expand Down
20 changes: 10 additions & 10 deletions examples/camera-app/linux/src/camera-device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,21 +624,21 @@ CameraError CameraDevice::CaptureSnapshot(const chip::app::DataModel::Nullable<u
return CameraError::SUCCESS;
}

CameraError CameraDevice::StartVideoStream(uint16_t streamID)
CameraError CameraDevice::StartVideoStream(const VideoStreamStruct & allocatedStream)
{
auto it = std::find_if(mVideoStreams.begin(), mVideoStreams.end(),
[streamID](const VideoStream & s) { return s.videoStreamParams.videoStreamID == streamID; });
uint16_t streamID = allocatedStream.videoStreamID;
auto it = std::find_if(mVideoStreams.begin(), mVideoStreams.end(),
[streamID](const VideoStream & s) { return s.videoStreamParams.videoStreamID == streamID; });

if (it == mVideoStreams.end())
{
return CameraError::ERROR_VIDEO_STREAM_START_FAILED;
}

// Create Gstreamer video pipeline
CameraError error = CameraError::SUCCESS;
GstElement * videoPipeline =
CreateVideoPipeline(mVideoDevicePath, it->videoStreamParams.minResolution.width, it->videoStreamParams.minResolution.height,
it->videoStreamParams.minFrameRate, error);
// Create Gstreamer video pipeline using the final allocated stream parameters
CameraError error = CameraError::SUCCESS;
GstElement * videoPipeline = CreateVideoPipeline(mVideoDevicePath, allocatedStream.minResolution.width,
allocatedStream.minResolution.height, allocatedStream.minFrameRate, error);
if (videoPipeline == nullptr)
{
ChipLogError(Camera, "Failed to create video pipeline.");
Expand All @@ -656,8 +656,8 @@ CameraError CameraDevice::StartVideoStream(uint16_t streamID)
gst_object_unref(appsink);
}

ChipLogProgress(Camera, "Starting video stream (id=%u): %u×%u @ %ufps", streamID, it->videoStreamParams.minResolution.width,
it->videoStreamParams.minResolution.height, it->videoStreamParams.minFrameRate);
ChipLogProgress(Camera, "Starting video stream (id=%u): %u×%u @ %ufps", streamID, allocatedStream.minResolution.width,
allocatedStream.minResolution.height, allocatedStream.minFrameRate);

// Start the pipeline
ChipLogProgress(Camera, "Requesting PLAYING …");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,14 @@ Protocols::InteractionModel::Status CameraAVStreamManager::VideoStreamAllocate(c
if (!stream.isAllocated)
{
stream.isAllocated = true;

// Start the video stream from HAL for serving.
mCameraDeviceHAL->GetCameraHALInterface().StartVideoStream(outStreamID);

// Set the default viewport on the newly allocated stream
mCameraDeviceHAL->GetCameraHALInterface().SetViewport(stream,
mCameraDeviceHAL->GetCameraHALInterface().GetViewport());

// Inform DPTZ that there's an allocated stream
mCameraDeviceHAL->GetCameraAVSettingsUserLevelMgmtDelegate().VideoStreamAllocated(outStreamID);

// Set the current frame rate attribute from HAL once stream has started
// Set the current frame rate attribute from HAL
GetCameraAVStreamMgmtServer()->SetCurrentFrameRate(mCameraDeviceHAL->GetCameraHALInterface().GetCurrentFrameRate());

return Status::Success;
Expand All @@ -155,6 +151,39 @@ Protocols::InteractionModel::Status CameraAVStreamManager::VideoStreamAllocate(c
return Status::DynamicConstraintError;
}

void CameraAVStreamManager::OnVideoStreamAllocated(const VideoStreamStruct & allocatedStream, StreamAllocationAction action)
{
switch (action)
{
case StreamAllocationAction::kNewAllocation:
ChipLogProgress(Camera, "Starting new video stream with ID: %u", allocatedStream.videoStreamID);
mCameraDeviceHAL->GetCameraHALInterface().StartVideoStream(allocatedStream);

// Set the current frame rate attribute from HAL once stream has started
GetCameraAVStreamMgmtServer()->SetCurrentFrameRate(mCameraDeviceHAL->GetCameraHALInterface().GetCurrentFrameRate());
break;

case StreamAllocationAction::kModification:
// Find the stream and restart it with new parameters
for (VideoStream & stream : mCameraDeviceHAL->GetCameraHALInterface().GetAvailableVideoStreams())
{
if (stream.videoStreamParams.videoStreamID == allocatedStream.videoStreamID && stream.isAllocated)
{
// For modifications, we always stop and restart the stream to ensure new parameters are applied
ChipLogProgress(Camera, "Restarting video stream with ID: %u due to modifications", allocatedStream.videoStreamID);
mCameraDeviceHAL->GetCameraHALInterface().StopVideoStream(allocatedStream.videoStreamID);
mCameraDeviceHAL->GetCameraHALInterface().StartVideoStream(allocatedStream);
break;
}
}
break;

case StreamAllocationAction::kReuse:
ChipLogProgress(Camera, "Reusing existing video stream with ID: %u without changes", allocatedStream.videoStreamID);
break;
}
}

Protocols::InteractionModel::Status CameraAVStreamManager::VideoStreamModify(const uint16_t streamID,
const chip::Optional<bool> waterMarkEnabled,
const chip::Optional<bool> osdEnabled)
Expand Down
21 changes: 17 additions & 4 deletions examples/camera-controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,25 @@ pairing onnetwork 1 20202021

Wait for the command to complete and confirm that commissioning was successful.

3. Start the Live Stream Still in the controller shell, use the Live View
command with the nodeID you assigned during pairing to request a video
stream.
3. To start a live video stream from your camera, use the `liveview start`
command followed by the nodeID you set during pairing. For example, if your
nodeID is 1, you can request a stream with a minimum resolution of 800x600
pixels and a minimum frame rate of 30 frames per second using the command
below.

```
liveview start 1
liveview start 1 --min-res-width 800 --min-res-height 600 --min-framerate 30
```

To see what video formats and resolutions your camera supports, first list the
available video devices, then check the formats for your specific device:

```
# List all available video devices
v4l2-ctl --list-devices

# Check formats for a specific device (replace /dev/video0 with your device)
v4l2-ctl -d /dev/video0 --list-formats-ext
```

Wave your hand in front of the camera to trigger live view; a video window will
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,18 @@ CHIP_ERROR CameraAVStreamMgmtServer::AddVideoStream(const VideoStreamStruct & vi
}

CHIP_ERROR CameraAVStreamMgmtServer::UpdateVideoStreamRangeParams(VideoStreamStruct & videoStreamToUpdate,
const VideoStreamStruct & videoStream)
{
const VideoStreamStruct & videoStream, bool & wasModified)
{
// Store original values to detect changes
uint16_t origMinFrameRate = videoStreamToUpdate.minFrameRate;
uint16_t origMaxFrameRate = videoStreamToUpdate.maxFrameRate;
uint16_t origMinResWidth = videoStreamToUpdate.minResolution.width;
uint16_t origMinResHeight = videoStreamToUpdate.minResolution.height;
uint16_t origMaxResWidth = videoStreamToUpdate.maxResolution.width;
uint16_t origMaxResHeight = videoStreamToUpdate.maxResolution.height;
uint32_t origMinBitRate = videoStreamToUpdate.minBitRate;
uint32_t origMaxBitRate = videoStreamToUpdate.maxBitRate;

// Adjust the range parameters for the allocated video stream to be the
// intersection of the existing and the new one.
videoStreamToUpdate.minFrameRate = std::max(videoStreamToUpdate.minFrameRate, videoStream.minFrameRate);
Expand All @@ -292,6 +302,14 @@ CHIP_ERROR CameraAVStreamMgmtServer::UpdateVideoStreamRangeParams(VideoStreamStr
videoStreamToUpdate.minBitRate = std::max(videoStreamToUpdate.minBitRate, videoStream.minBitRate);
videoStreamToUpdate.maxBitRate = std::min(videoStreamToUpdate.maxBitRate, videoStream.maxBitRate);

// Check if any parameter was actually modified
wasModified = (origMinFrameRate != videoStreamToUpdate.minFrameRate) ||
(origMaxFrameRate != videoStreamToUpdate.maxFrameRate) || (origMinResWidth != videoStreamToUpdate.minResolution.width) ||
(origMinResHeight != videoStreamToUpdate.minResolution.height) ||
(origMaxResWidth != videoStreamToUpdate.maxResolution.width) ||
(origMaxResHeight != videoStreamToUpdate.maxResolution.height) || (origMinBitRate != videoStreamToUpdate.minBitRate) ||
(origMaxBitRate != videoStreamToUpdate.maxBitRate);

auto path = ConcreteAttributePath(mEndpointId, CameraAvStreamManagement::Id, Attributes::AllocatedVideoStreams::Id);
mDelegate.OnAttributeChanged(Attributes::AllocatedVideoStreams::Id);
MatterReportingAttributeChangeCallback(path);
Expand Down Expand Up @@ -1782,7 +1800,6 @@ void CameraAVStreamMgmtServer::HandleVideoStreamAllocate(HandlerContext & ctx,

if (status == Status::Success)
{

// Check if the streamID matches an existing one in the
// mAllocatedVideoStreams.
auto it =
Expand All @@ -1794,12 +1811,21 @@ void CameraAVStreamMgmtServer::HandleVideoStreamAllocate(HandlerContext & ctx,
// Add the allocated videostream object in the AllocatedVideoStreams list.
videoStreamArgs.videoStreamID = videoStreamID;
AddVideoStream(videoStreamArgs);

// Call delegate with the allocated stream parameters and new allocation action
mDelegate.OnVideoStreamAllocated(videoStreamArgs, StreamAllocationAction::kNewAllocation);
}
else
{
bool wasModified = false;

VideoStreamStruct & videoStreamToUpdate = *it;
// Reusing the existing stream. Update range parameters
UpdateVideoStreamRangeParams(videoStreamToUpdate, videoStreamArgs);
// Reusing the existing stream. Update range parameters and check if they were modified
UpdateVideoStreamRangeParams(videoStreamToUpdate, videoStreamArgs, wasModified);

// Call delegate with the final updated stream parameters and appropriate action
mDelegate.OnVideoStreamAllocated(videoStreamToUpdate,
wasModified ? StreamAllocationAction::kModification : StreamAllocationAction::kReuse);
}

response.videoStreamID = videoStreamID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ constexpr size_t kArrayTlvOverhead = 2;

constexpr size_t kStreamUsagePrioritiesTlvSize = kArrayTlvOverhead + kStreamUsageTlvSize * kNumOfStreamUsageTypes;

enum class StreamAllocationAction
{
kNewAllocation, // Fresh stream allocation - always start
kModification, // Existing stream with parameter changes - restart if active
kReuse // Reusing existing stream without changes - no action needed
};

class CameraAVStreamMgmtServer;

// ImageSnapshot response data for a CaptureSnapshot command.
Expand Down Expand Up @@ -107,6 +114,15 @@ class CameraAVStreamMgmtDelegate
virtual Protocols::InteractionModel::Status VideoStreamAllocate(const VideoStreamStruct & allocateArgs,
uint16_t & outStreamID) = 0;

/**
* @brief Called after the server has finalized video stream allocation and narrowed parameters.
* This is where the actual video stream should be started using the final allocated parameters.
*
* @param allocatedStream The finalized video stream with narrowed parameters from the server.
* @param action Action indicating how to handle the stream: new allocation, modification, or reuse.
*/
virtual void OnVideoStreamAllocated(const VideoStreamStruct & allocatedStream, StreamAllocationAction action) = 0;

/**
* @brief Handle Command Delegate for Video stream modification.
*
Expand Down Expand Up @@ -507,7 +523,8 @@ class CameraAVStreamMgmtServer : public CommandHandlerInterface, public Attribut

CHIP_ERROR AddVideoStream(const VideoStreamStruct & videoStream);

CHIP_ERROR UpdateVideoStreamRangeParams(VideoStreamStruct & videoStreamToUpdate, const VideoStreamStruct & videoStream);
CHIP_ERROR UpdateVideoStreamRangeParams(VideoStreamStruct & videoStreamToUpdate, const VideoStreamStruct & videoStream,
bool & wasModified);

CHIP_ERROR RemoveVideoStream(uint16_t videoStreamId);

Expand Down
Loading