I am running the following ffmpeg
command in console in order to pipe the resulting frame data to another program
ffmpeg -loglevel quiet -skip_frame nokey -i "input.mkv" -vsync vfr -frame_pts true -filter_complex "extractplanes=y[Y];[Y]scale=8:8" -pix_fmt gray -f rawvideo - | test.exe
But attempting to read the piped data from stdin
seems to arbitrarily hang after a certain amount of frames, the frame number it stops reading at appears to be consistent for any given video file, but differs if you try loading another video.
Trying the above cmd with 5 different input files produces the following results:
input1.mkv
stops reading after55
framesinput2.mkv
stops reading after8
framesinput3.mkv
stops reading after18
framesinput4.mkv
stops reading after74
framesinput5.mkv
stops reading after50
frames
I know each of the video files is supposed to return around 300-400
frames, which is also what happens when you use ffmpeg
to instead save the data to disk as images (rather than piping it) using the similar command given below
ffmpeg -skip_frame nokey -i "input.mkv" -vsync vfr -frame_pts true -filter_complex "extractplanes=y[Y];[Y]scale=8:8" -pix_fmt gray "keyframes/%%06d.bmp"
test.exe
is very simplistic and literally only attempts to read the known amount of frames from stdin
into an array
int main(int argc, char* argv[])
{
unsigned char buffer[272*64] = {0};
int count = fread(buffer, sizeof(char)*64, 272, stdin);
// *** TEST PRINT CONTENT ***
for (unsigned int i=0; i<((count+1)*64); i++)
{
if (i % 8 == 0)
{
std::cout << std::endl;
}
if (i % 64 == 0)
{
std::cout << std::endl;
std::cout << "--- Frame: " << ((i >> 6)+1) << " ---" << std::endl;
std::cout << "--- NEXT FRAME ---" << std::endl;
std::cout << std::endl;
}
std::cout << +buffer[i] << " ";
}
std::cout << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << count+1 << " frames processed" << std::endl;
return 0;
}
and later just prints out the contents of the array so I can check if it actually got all the data, the provided example uses fread
, but I get similar results with other methods like manually redirecting required amount of bytes from std::cin
.
My best guess is that the program tries reading the frames faster than ffmpeg
can generate them, leading to it reaching EOF
early and exiting, but attempting to read 1
frame at a time and printing the result in a loop while trying to slow it down by sleeping for 500ms
each iteration does not seem to work either.
Why does this happen and how do I make it pipe all of the frame data i know that ffmpeg
is generating?
The code for attempting to parse one frame at at time, which also stops reading at the same point as the code above:
int main(int argc, char* argv[])
{
for (int f=0; f<(272); f++)
{
Sleep(500);
unsigned char buffer[64] = {0};
fread(buffer, sizeof(char)*64, 1, stdin);
for (int i=0; i<(64); i++)
{
if (i % 8 == 0)
{
std::cout << std::endl;
}
if (i % 64 == 0)
{
std::cout << std::endl;
std::cout << "--- Frame: " << (f+1) << " ---" << std::endl;
std::cout << "--- NEXT FRAME ---" << std::endl;
std::cout << std::endl;
}
std::cout << +buffer[i] << " ";
}
}
return 0;
}
The code using std::cin
, which produces similar results to code above, but also loads partial data from the next frame:
int main(int argc, char* argv[])
{
unsigned int j = 0;
unsigned char buffer[272*64] = {0};
while (j<(272*64))
{
std::cin >> buffer[j++];
}
// *** TEST PRINT CONTENT ***
for (unsigned int i=0; i<(272*64); i++)
{
if (i % 8 == 0)
{
std::cout << std::endl;
}
if (i % 64 == 0)
{
std::cout << std::endl;
std::cout << "--- Frame: " << ((i >> 6)+1) << " ---" << std::endl;
std::cout << "--- NEXT FRAME ---" << std::endl;
std::cout << std::endl;
}
std::cout << +buffer[i] << " ";
}
std::cout << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << count+1 << " frames processed" << std::endl;
return 0;
}