Я новичок в декодировании / кодировании видео. В настоящее время у меня есть задача проверить передачу видео на сетевое кодирование. Программа сетевого кодирования уже была готова.
Сначала я попытался разделить видео на кадры в opencv и передать их, но после разделения я обнаружил, что видео размером 3 МБ преобразуется в кадры общего размера 80 МБ !! который не эффективен для передачи. Есть ли лучший способ сделать передачу видео? Может ли кто-нибудь из профессионалов предоставить мне пример кода на C ++? Мне сказали, что нельзя напрямую помещать видео в буфер из-за ограничения пропускной способности передачи. Мне интересно использовать разницу между кадрами, чтобы уменьшить размер передаваемого файла, но я не знаю, как это сделать в C ++.
Вот мой код для видео, разделенного на кадры.
#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 readingdouble 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;
}
Если битрейт вашего видео слишком велик для вашей полосы пропускания, вам необходимо повторно сжать его, используя стандартный видеокодек, например, h264.
Вы можете сделать это с помощью программы ffmpeg, используя что-то вроде:
ffmpeg -i <your_input_file> -c:v libx264 -crf 22 video.avi
Это будет кодировать с параметрами по умолчанию и постоянным качеством (параметр crf, чем ниже, тем выше качество), см. Вот для опций кодера h264, в вашем случае вы можете предпочесть использовать постоянный битрейт вместо постоянного качества.
Чтение видео с правильной скоростью и потоковая передача по сети было бы возможно в c библиотекой libavformat (часть библиотек ffmpeg), но, вероятно, сложно для новичка.
Одним из более простых решений было бы перенаправить вывод команды ffmpeg в вашу программу, которая выполняет сетевое кодирование.
Например:
ffmpeg -re -i input.avi -f rawvideo -c:v copy pipe:1 | ./network_encode
Это прочитает закодированный видеофайл и отправит необработанный видеопоток в вашу программу сетевого кодирования (здесь network_encode считывает данные со стандартного ввода, применяет сетевое кодирование и отправляет его)
На приемнике вы можете сделать что-то похожее для визуализации вашего видео (здесь network_decode получает данные из сети, декодирует их и записывает результат в стандартный вывод):
./network_decode | ffplay -i -