How to use composite objects using spmd
13 views (last 30 days)
Show older comments
I am trying to implement video-on-demand using the spmd parallel computing function. I have a saved video encoded at 3 different qualities and segmented into 3second segments, and I am trying to save video frames to the video buffer (modelled as a structure) while simultaneously playing from the buffer at a constant rate of 24 frames per second. The quality of each segment must be selected based on the buffer level. However, I am getting the error "Error detected on worker 1. Subscripted assignment between dissimilar structures" from running the following code:
mov = struct; % video buffer
bufsize = length(mov); %buffer level
spmd
switch labindex
case 1
segnum = 0; %segment number
i=1;
c=1;
br = 20; %assumed channel bandwidth in Mbps
%Check last segment number and get segment names from file
res = ["low" "mid" "sample"]; %available resolutions
resnum = 1;
filename = sprintf('%sdash.m3u8',res(resnum));
s = importdata(filename);
lastseg = s{end-1,1};
[lastsegnum,n,err] = sscanf(lastseg,(res(resnum)+'dash%d.ts'));
%Get frame size for highest quality
vidobj = VideoReader("sampledash1.ts");
v = read(vidobj,1);
framesize = size(v);
%Get next segment with appropriate quality
while segnum<=lastsegnum
if bufsize<72 %24fps*3sec = 72 frames in one segment
resnum = 1;
elseif bufsize>=72 && br<216
resnum = 2;
elseif bufsize>=216
resnum = 3;
end
segment = sprintf('%sdash%d.ts',res(resnum),segnum);
vidobj = VideoReader(segment);
f = dir(segment);
fsz = f.bytes; %size of segment
x = rand;
delay = ((fsz*8)/(br*1e6)) + x; %network delay
pause(delay);
while hasFrame(vidobj)
mov(c) = im2frame(readFrame(vidobj));
mov(c).cdata = imresize(mov(c).cdata,[framesize(1) framesize(2)]);
labSend(mov(c).cdata,labindex+1,11);
bufsize = bufsize+1;
c = c+1;
end
labSend(segnum,labindex+1,12);
segnum=segnum+1;
end
case 2
depvid = vision.DeployableVideoPlayer('Size','Full-screen');
i=1;
while ~isempty(mov) %start playing the video only after the first two segments have been downloaded
frame = labReceive(labindex-1,11);
segnum = labReceive(labindex-1,12);
vid(i).cdata = frame;
i=i+1;
if segnum>1
step(depvid,vid(1).cdata)
pause(1/24)
vid(1) = [];
i = i-1;
end
end
end
end
I am a bit confused about why I am getting this error. I think it may be due to the Composite objects created by the function, but I'm not sure how.
0 Comments
Accepted Answer
Raymond Norris
on 17 Oct 2022
It's not related to your parallel code, the issue is the initialization of mov. This can be reproduced by the following
function nagi
mov = struct();
%mov.cdata = [];
%mov.colormap = [];
M.cdata = ones(240,320,3,'uint8');
M.colormap = [];
mov(1) = M;
So it's getting tripped up here
mov(c) = im2frame(readFrame(vidobj));
If you initialize mov as I've commented it out, you'll be fine.
Side note: I'm assuming at some point, labindex 1 won't have anything else to send labindex 2, correct? If so, you're going to run into the issue that labindex 2 is continuing to wait to receive from labindex 1. Keep in mind, for labindex 2, mov is never empty. For all intents and purposes, it only sees
mov = struct;
(Or however you end up initializing it). Therefore, at somepoint, MATLAB will throw
A communication mismatch error was encountered:
The other lab became idle during labReceive.
"The other lab" in this case is labindex 1.
3 Comments
Raymond Norris
on 18 Oct 2022
You mentioned in a comment
%start playing the video ...
but I don't see where that was actually happening, is that the call to step? Keep in mind that technically the graphics can display (and you could even print the figures to a file), but you can't see the graphics in a spmd or parfor block. Case in point, try
parfor idx = 1:2, plot(rand(10)); end
spmd, plot(rand(10)); end
The reason is because the workers are "headless" -- they don't show their graphics. What you can use is a parallel.pool.DataQueue. Here's a simple toy example
Q = parallel.pool.DataQueue;
afterEach(Q,@updatePlot);
spmd
for idx = 1:50
if labindex==2
% Worker 2 is the workhorse, responsible for sending data back
% to the client, which in turn plots the result
% "Calculate" some data
r = round(rand*100)+5;
% Send it to the client
send(Q,r)
end
end
end
function updatePlot(r)
% Plot the results
surfc(1:r,1:r,rand(r))
axis tight, shg
end
More Answers (0)
See Also
Categories
Find more on Parallel and Cloud in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!