I need to process the video stream and the klvdata streams simultaneously in real-time in OpenCV/Python. I'm using FFMPEG to read the file or stream as OpenCV does not retain the klvdata. I pass the data to OpenCV with the subprocess module.
My problem is I cannot figure out how to map both the video and klvdata to the same subprocess pipe simultaneously?
My code:
#!/usr/bin/env python3
import sys, json, klvdata;
from subprocess import PIPE
import subprocess as sp
import cv2
import numpy
command = ['ffmpeg',
'-i', 'DayFlight.mpg',
'-map', '0:0',
'-map', '0:d',
'-pix_fmt', 'bgr24',
'-c:v', 'rawvideo',
'-an','-sn',
'-f', 'image2pipe', '-',
'-c:d', 'copy',
'-f','data',
]
pipe = sp.Popen(command, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, bufsize=10**8)
while True:
raw_image = pipe.stdout.read(1280*720*3)
image = numpy.fromstring(raw_image, dtype='uint8')
image = image.reshape((720,1280,3))
if image is not None:
cv2.imshow('Video', image)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
for packet in klvdata.StreamParser(pipe.stdout):
metadata = packet.MetadataList()
print(metadata)
pipe.stdout.flush()
cv2.destroyAllWindows()
Produces the below error:
Traceback (most recent call last):
File "test_cv.py", line 32, in <module>
metadata = packet.MetadataList()
AttributeError: 'UnknownElement' object has no attribute 'MetadataList'
Any help is greatly appreciated.
For splitting the video and data, we may map the video stream to
stderr
pipe and map the KLV data stream to tostdout
pipe.The same technique is used for separating video and audio in my following answer.
Accurate synchronization between the the video frame and the corresponding data is relatively simple when each video frame has private KLV data (synchronize by sequential order).
The Day Flight.mpg sample file has much fewer data packets than frames, and accurate synchronization is not possible using the suggested solution (I don't think it is possible using the pipes approach).
We may still apply some coarse synchronization - assume the data and the frame are read in time proximity.
Suggested way for splitting the video and the data:
The video and the data are read in two separate threads:
According to Wikipedia, the KLV format is not well defined:
In the sample video, the key length is 16 bytes, but it is not guaranteed...
Reading the KLV data from stdout pipe:
When reading data from a pipe (in real-time like manner), we need to know the expected number of bytes to read.
That forces us to do partial parsing of the KLV data:
After reading the key, length and data, we have one "KLV data packet", we can send to the KLV data parser.
Here is a code sample that woks with
Day Flight.mpg
sample input file:The above code saves the data to
data.bin
(for testing).data.bin
may be used for consistency check.Execute FFmpeg CLI for extracting the data stream:
Verify that
raw.bin
anddata.bin
files are equal.