C++ Video streaming and transimisson - c++

I am new to video decoding/encoding. Currently I have a task to test the video transmission for a network coding. The network coding programme was already done.
Firstly I tried to divide the video into frames in opencv, and transmit the frames, but after division, I found a 3MB video are converted to 80MB total size frames!! which is not efficient for transmission. Is there any better way to do the video transmission? Can any pros provide me a sample code in C++? I be told that cannot directly put video into buff due to the transmission bandwidth limitation. I am wondering using the inter frame difference to reduce the transmission file size but I do not know ht to do this in C++.
Here is my code for video divide into frames.
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
VideoCapture cap("/home/yonghao/Documents/50MbitMJPEG1080p.mp4"); // open the video file for reading
double fps = cap.get(CV_CAP_PROP_FPS); //get the frames per seconds of the video
int numFrames = cap.get(CV_CAP_PROP_FRAME_COUNT); // get the total number of frames
cout << "Frame per seconds : " << fps << endl;
cout << "Total Frame Numbers : " << numFrames << endl;
namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
int frame_number = 1;
while(frame_number<=numFrames)
{
Mat frame;
bool bSuccess = cap.read(frame); // read a new frame from video
if (!bSuccess) //if not success, break loop
{
cout << "Cannot read the frame from video file" << endl;
break;
}
imshow("MyVideo", frame); //show the frame in "MyVideo" window
//save frame
stringstream ss;
string name = "/home/yonghao/Documents/Frames/frame_";
string type = ".jpg";
ss<<name<<(frame_number)<<type;
string filename = ss.str();
ss.str("");
imwrite(filename, frame);
cout << "Frame " << frame_number << " has been generated." << endl;
frame_number++;
//user exit by press ESC button
if(waitKey(30) == 27) //wait for 'esc' key press for 30 ms. If 'esc' key is pressed, break loop
{
cout << "esc key is pressed by user" << endl;
break;
}
}
return 0;
}

If the bitrate of your video is too high for your bandwidth, you need to recompress it, using a standard video codec, for example h264.
You can do that with the ffmpeg program, using something like :
ffmpeg -i <your_input_file> -c:v libx264 -crf 22 video.avi
This will encode with default options and a constant quality (crf parameter, the lower the higher quality), see here for the options of h264 encoder, in your case you may prefer to use constant bitrate instead of constant quality.
Reading the video at correct speed and streaming it on the network would be possible in c with libavformat library (part of ffmpeg libraries), but probably complex for a beginner.
One simpler solution would be to pipe the output of a ffmpeg command to your program that does the network coding.
For example:
ffmpeg -re -i input.avi -f rawvideo -c:v copy pipe:1 | ./network_encode
This will read the encoded video file and send the raw video stream to your network encoding program (here network_encode read data from standard input, apply your network coding and send it)
On the receiver, you can do something similar to visualize your video (here network_decode receive the data from the network, decode it, and write result to standard output):
./network_decode | ffplay -i -

Related

OpenCV VideoCapture working properly only after breakpoint

I'm currently using OpenCV 2.3.1 with Visual Studio 2008. I'm trying to read the frames from a Hauppauge Usb Live-2 using VideoCapture, but I'm ran into a strange issue. Below is the relevant part of my code:
VideoCapture vc(0);
if (!vc.isOpened()) return -1;
Mat frame;
namedWindow("Camera");
bool success;
while (true)
{
success = vc.read(frame);
if (!success) continue;
imshow("Camera", frame);
if (waitkey(30) == 27) break;
}
Initially, when running my code in debug mode, the window displaying the captured frames shows only a solid gray image. Attempting to debug my program, I placed breakpoint a breakpoint at the start of my code and stepped through each line. At imshow, however, the window started displaying the grabbed frames properly, showing what was captured by my camera. Subsequently, I realized that so long as I enter a breakpoint between opening my device and displaying it on the window, the frames will start showing up properly.
Does anyone have any idea how entering a breakpoint may affect the execution of a program in debug mode (in this case allowing the VideoCapture object to start reading the frames properly)?
Note: Running the executable gave no problems either, so I'm posting this question out of curiosity.
I believe your code is trying to display the image (which is empty) before your camera gets ready. Try to slow down for one or two seconds, by first include files like:
#include <chrono>
#include <thread>
Then before your while statement, add this line:
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
If you are using C++ with lower version than 11, then the sleep_for method might be different. Take a reference here.
The camera has an initialisation period so you need to check for empty frames.
Now there are two options, you could do what #Derman has said and put in a wait but how do you know how long you need to wait for?
Or you can check for empty frames and only show the window if they are not empty
VideoCapture vc(0);
if ( !vc.isOpened() ) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
Mat frame;
namedWindow("Camera");
bool success;
while (true)
{
vc.read(frame);
if(frame.empty()){
std::cerr<<"frame is empty"<<std::endl;
break;
}
imshow("Camera", frame);
if (waitkey(30) == 27) break;
}
I don't see any reason why this code shouldn't start showing the frames once they are avaliable from the camera

Retrieving every 3rd frame from video file in opencv c++

I'm writing a logic to retrieve every 3rd frame from a video in opencv c++, while executing I am facing a problem in first 'for' loop when I try print(cout) 'i' value ouput is only upto 687, after which "Error: Insufficient memory (Failed to allocate 2764804 bytes) out of memory" error occurs.
int main(){
string path = "C:/vid_frames/Highway_Hamilton.avi";
VideoCapture capture(path);
Mat matImage[1000];
cout<<"initalization done";
//obtaining frames from the video into matimage variable
for(int i=0;i<1000;i++) {
char filename[30]="Existing frame";
capture >> matImage[i];
cout<<"i:"<<i;
if ( matImage[i].empty())
{
cout << "Cannot load image!,runnig application might abort exit,press any key:" << endl;
getchar();
}
char frame_id[30];
itoa(i, frame_id, 15);
strcat(filename, frame_id);
}
int num=0;
for(int i=0;num<1000;i++) {
char filename[30]="Required frame";
char frame_id[30];
itoa(num, frame_id, 10);
strcat(filename, frame_id);
num=num+3;
}
}
suggest me how I can access a array of Mat variable beyond 687,and kindly let me know if any other logic exists for retrieving every 3rd frame from a video, so that I can move out of this prob,solving this prob is surely appreciable. thanks in advance.
You can use CV_CAP_PROP_POS_FRAMES macro to set frame position to be decoded/captured next.
Like,
VideoCapture::set(CV_CAP_PROP_POS_FRAMES ,framePosition);
See OpenCV Doc for more details

OpenCV/C++ - frames read from video file restart after end of the video

I'm trying to get each frame from an mp4 video with OpenCV. I followed the standard examples but for some reason, when the last frame is read, the loop does not terminate but in fact starts again.
Here is the code:
while (1) {
inputVideo.read(inputFrame);
nFrames = inputVideo.get(CV_CAP_PROP_POS_FRAMES);
cout << "Frame: " << nFrames << endl;
n++;
}
Why doesn't it stop after all the frames have been processed?
You can use inputVideo.get() to detect the position of the frame in the file and use this to break out at the end

OpenCV videoWriter codec issue

I am trying to write a video in OpenCV in Windows and am meeting various issues when choosing codecs. I'm not sure if it is something in my code or I do not have the codecs necessary. The code is:
int main(int argc, char ** argv){
VideoCapture inputVideo("LFW.mp4");
Mat inputFrame, outputFrame;
VideoWriter outputVideo;
if (!inputVideo.isOpened()){
std::cout << "!!! Input video could not be opened" << std::endl;
return 1;
}
int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC));
const string name = "Output.mp4";
Size size = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), (int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
outputVideo.open(name, CV_FOURCC('M','P','4','2'), inputVideo.get(CV_CAP_PROP_FPS), size, true);
if (!outputVideo.isOpened()){
std::cout << "!!! Output video could not be opened" << std::endl;
return 2;
}
return 0;
}
The code keeps exiting with code 2, therefore the videoWriter object is not happy with its configuration.
I have a problem with many codecs on windows. I have installed ffmpeg correctly, but still there is a problem with many video format.
Try this one CV_FOURCC('W', 'M', 'V', '2')
VideoWriter video("Result.wmv", CV_FOURCC('W', 'M', 'V', '2'), 30, SizeOfFrame, true);
WMV is awful format but works perfect for me. I am working with Visual Studio 2015 and my own build of Opencv 3.0.0.
In Opencv 3.0.0, I can strongly recommend include also
#include "opencv2/imgcodecs/imgcodecs.hpp"
#include "opencv2/videoio/videoio.hpp"
There is anoter recommandation. Check size of input video and size of VideoWriter. CV_CAP_PROP_FRAME_WIDTH and CV_CAP_PROP_FRAME_HEIGHT in some cases return wrong values. Check both sizes before video.write(Mat)
You can check your video writer by this loop.
Set your writer sizes as dummy constant.
Size SizeOfFrame = cv::Size( 800, 600);
VideoWriter video("Result.wmv", CV_FOURCC('W', 'M', 'V', '2'), 30, SizeOfFrame, true);
In video loop resize retrieved video to same size as writer. If this fail your installation is probably wrong.
for (;;)
{
bool Is = cap.grab();
if (Is == false) {
cout << "cannot grab video frame" << endl;
}
else {
cap.retrieve(LoadedImage, CV_CAP_OPENNI_BGR_IMAGE);
resize(LoadedImage, LoadedImage, Size(800, 600));
video.write(LoadedImage);
}
}
My Tutorial here
It is not uncommon that people have codec issues when working with VideoCapture and VideoWriter. (Another less common issue is that OpenCV has been compiled without an encoder (like using WITH_FFMPEG=NO or WITH_VFW=NO when compiling OpenCV) )
I would try the following things dissect the problem (ordered by the level of hassle involved :) ):
Try running the same program but passing -1instead of CV_FOURCC('M','P','4','2') as the second argument to outputVideo.open(). You will then get a pop-up asking you to select codec and can then see which ones OpenCV finds.
If that doesn't help you - use a debugger to step into outputVideo.open(). You might turn out to arrive at an empty function (#ifdefed away due to some preprocessor macro). Unfortunately you will have to have a debug-compiled OpenCV with pdb-files to do this properly.

video is not being written to file

I am using opencv to capture a video directly from webcam and saving it to a avi file. I have used the following code:
#include "StdAfx.h"
using namespace std;
using namespace cv;
int _tmain()
{
VideoCapture src;
src.open(1);
if(!src.isOpened())
{
cout<<"could not open camera\n";
return -1;
}
else
{
cout<<"camera opened\n";
}
int ex=static_cast<int>(src.get(CV_CAP_PROP_FOURCC));
Size s(Size((int)src.get(CV_CAP_PROP_FRAME_WIDTH),(int)src.get((CV_CAP_PROP_FRAME_HEIGHT))));
VideoWriter out;
out.open("out.avi",ex,20,s);
while(1)
{
Mat im;
src>>im;
imshow("vid",im);
out<<im;
char c;
c=cvWaitKey(50);
if(c==27)
break;
}
system("pause");
}
all the headers are included in stdafx.h.
But actually I am getting a avi file of size 0bite. How to fix this thing? I need to record the webcam video without displaying.
Note: I'm new in openCV and I am using Visual Studio 2010
to run the application without display the webcam just delete
imshow("vid",im);
and out.avi size is 0 because you open it when the application is running (when you open the video stream and write on it ) , to open the video which you recorded , just close the application to end the write on the video and then open it .
Actually there is no logical error in your program. The only problem is the FOUR_CC Codec you are using to write the video.
When I ran your code, I faced the exact problem as yours. When I added the error checking to the out.open() function, I found the problem.
Most probably, the FOUR_CC codec of the camera is not supported by the avi container.
As you are using Windows, a good option is to use CV_FOURCC_PROMPT in the 2nd argument of out.open.
This will open a pop up list box containing different FOUR_CC codecs available. If you don't know which one to choose, just select Full Frames (Uncompressed). It is the most compatible option but will increase the size of the output video file.
The final code should look like this:
if(!out.open("out.avi",CV_FOURCC_PROMPT,20,s))
{
cout<<"Writer Not Opened"<<endl;
return -1;
}