How can I merge video files without crashing my memory?
2 views (last 30 days)
Show older comments
Chris Foster
on 31 May 2015
Commented: Walter Roberson
on 3 Jun 2015
I am trying to create a program that randomly chooses two seconds from a variable number of relatively short movie clips (short videos created for the purpose of putting together a '2 seconds a day' type movie). Everything is working fine, but I crash my systems memory after 8 videos or so, and I'm trying to put together around 100. I'm just learning how to program and my main problem revolves around how to free up memory. Below is my code.
if true
% code
files = dir( 'C:/Users/psychuser/Desktop/Pictures and Misc/Phone/*.mov' ); %finds all movies in a certain folder
n = 1;
for i= 1 : size( files , 1 );
originalfilename = sprintf( 'C:/Users/psychuser/Desktop/Pictures and Misc/Phone/%s' , files(i,1).name );%creates variable file name
obj = VideoReader( originalfilename ); %turns video into variable 'obj'
video = obj.read; %read video and properties into matlab file
x = round( obj.FrameRate ); %from that properties file turn framerate of video into variable
y = obj.NumberOfFrames; %from that properties file turn total number of frames into variable
z = ( y - ( x * 2 ) ); %z subtracts the frame rate from the total number of frames so that the new movie doesn't exceed the total number of frames
if ( x * 2 ) <= y %if total number of seconds is greater than 2 seconds choose random two seconds
j = ( n : (n + ( x * 2 ))); %j is a counter that knows where the last video ended and how big the current video is
startframe = randi ( z ); %choose random start point between first frame and last possible frame
choicerng = ( startframe : ( startframe + ( x * 2 ) ) );
video1 ( : , : , : , j ) = video( : , : , : , choicerng ); %merge new video to old 'combined' video
else % else choose the whole video
j = ( n : ( ( y - 1 ) + n ) ); %Y is rounding up for these videos creating a problem with a less than two second clip, to resolve this i subtracted 1 frame, needs a better fix
choicerng = ( 1 : y ); % choose whole video
video1 ( : , : , : , j ) = video( : , : , : , choicerng ); %merge new video to old 'combined' video
end
n = max(j) + 1; % last frame in the combined video
clear x y z originalfilename obj video choicerng startframe %clear variables
end %everything below here writes out the video to a new file called twoseconds
newfilename = 'C:/Users/psychuser/Desktop/Pictures and Misc/ChristiPhone/TwoSecond/twoseconds.avi';
writeobj = VideoWriter( newfilename );
open( writeobj );
writeVideo( writeobj , video1 );
close( writeobj );
clear all
end
0 Comments
Accepted Answer
Image Analyst
on 31 May 2015
Try not reading the whole video into memory. Use read() to read just the frames you want in.
3 Comments
Image Analyst
on 3 Jun 2015
Wow, you're right. It's new but it didn't last long before being deprecated. It looks like they say use readFrame instead of read. That should be a simple fix (just renaming the method) and should resolve the issue, I would think.
It's always a dilemma when to change my demos. If I change read() to readFrame() then people with old versions of MATLAB won't be able to run my demo.
In some ways readFrame() looks worse than read() because with read() you could specify what frame number to extract whereas it doesn't look like readFrame has tha option.
Walter Roberson
on 3 Jun 2015
Yes, you have to set the object properties to indicate which frame you want to read next. A clumsy system.
More Answers (2)
Walter Roberson
on 31 May 2015
See http://www.mathworks.com/help/matlab/import_export/read-video-files.html for how to use the readFrame method of VideoReader; it has an example of setting the current time and reading until a target time. You would not need to calculate the number of frames.
Also instead of storing the frames in memory and writing everything out at the same time, you can use VideoWriter to write individual frames.
You could use a procedure such as
open your output with videowriter
for 1 to number of videos to subset
pick a random video
open a reader onto the video
ask how long it is in seconds
if it is less than 2 seconds set lower time bound to 0 and upper time bound to actual length
otherwise pick a random floating point number between 0 and length minus 2 seconds, set lower time bound to that value and upper time bound to 2 seconds later
set reader start time to lower time bound
loop until the current reader time exceeds upper time bound, reading the next frame from the reader and writing it immediately to the writer
close the reader
end of for loop
close the writer
Chris Foster
on 2 Jun 2015
1 Comment
Walter Roberson
on 2 Jun 2015
I recommend you learn to use fullfile() instead of sprintf()'ing your filenames.
Your line
starttime = randi ( z );
only starts on integer second boundaries. To be more flexible, you could use
starttime = rand() * z;
which will start between 0 and z.
Your reading and writing of frames is not efficient. Change to
video1data = readFrame(obj);
writeVideo( writeobj , video1data );
with no need for "n" at all. You can compress it all down to
writeVideo(writeobj, readFrame(obj));
See Also
Categories
Find more on Audio and Video Data 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!