Thanks to helpful comments from @MBaz, I managed to come up with a solution:
we can associate multiple audio samples with a single frame using the VideoFileWriter object. This fact and use-case is missing in the documentation.
First, some stats about the audio and video files. The stereo audio samples are in a 2xN array signal. The video frames are in a cell-array of RGB images, frames.
%% Write audio and video to file
% Write both audio and video samples into a single video file.
% Multiple audio samples are matched with one video frame.
% MATLAB problem: Compression is not possible when audio is included.
% Display A/V stats
fprintf('\nVIDEO STATS:');
fprintf('\nNum. of frames: %d', length(frames));
fprintf('\nFrame rate: %.02f fps', annot.video.frame_rate);
fprintf('\n\nAUDIO STATS:');
fprintf('\nNum. of samples: %d', size(signal,1));
fprintf('\nSampling rate: %.02f Hz\n', infoAudio.SampleRate);
Here's the portion that matches multiple audio samples to a single video frame.
Note that there are 697 video frames and 1336321 audio samples. Some basic fiddling to ensure proper matching. The audio subsampling effect is imperceptible in the output AVI files that I tried.
numAudio = size(signal,1);
numRep = floor(numAudio/length(frames));
numDiff = numAudio - numRep*length(frames); % mismatch
if numDiff
% if length(frames) does not evenly divide nAudioSamples, then
% subsample audio to match numRep*length(frames)
selector = round(linspace(1, numAudio, numRep*length(frames)));
subSignal = signal(selector, :);
end
assert(numRep*length(frames) == size(subSignal,1));
Finally, we use the VideoFileWriter object available in the Computer Vision System Toolbox of MATLAB to write audio and video to file.
videoFWriter = vision.VideoFileWriter(fullfile(shotPath, 'avclip', ...
[num2str(shotNum) '_av_clip.avi']), ...
'AudioInputPort', true, ...
'FrameRate', annot.video.frame_rate);
for i = 1:length(frames)
fprintf('Frame: %d/%d\n', i, length(frames));
step(videoFWriter, frames{i}, subSignal(numRep*(i-1)+1:numRep*i,:));
end
release(videoFWriter);