How to decode h264 stream - c++

I searched a lot but I can't find a decent library to solve to my problem. I receive a h264 stream from the network, and I want to decode it from memory and display it in real time. Something like this pseudocode below:
cv::Mat frame;
while (true)
{
if (newDataArrived)
{
void* h264Buffer; // address with current h264 stream
size_t h264BufferSize; // size of the stream
LibraryINeed::UpdateFrame(frame, h264Buffer, h264BufferSize); // !?
}
...
imshow("display", frame); // show most recent frame
}
Is there any library that provides this functionality?

Related

Opus encode & decode no error but not the same value

I have to use Opus Codec to encode & decode audio datas in C++ and I have to encapsulate the functions.
So I try to send a floats array to try to encode it and I decode the result of the Opus encoding function. Unfortunately, the result is not the same and I get a table that contains no value from the initial table.
Here is my code.
Encapsulation:
std::vector<float> codec::OpusPlugin::decode(packet_t &packet) {
std::vector<float> out(BUFFER_SIZE * NB_CHANNELS);
int ret = 0;
if (!this->decoder)
throw Exception("Can't decode since there is no decoder.");
ret = opus_decode_float(this->decoder, packet.data.data(), packet.size, reinterpret_cast<float*>(out.data()), FRAME_SIZE, 0);
if (ret < 0)
throw Exception("Error while decoding compressed data.");
return out;
}
// ENCODER
packet_t codec::OpusPlugin::encode(std::vector<float> to_encode) {
std::vector<unsigned char> data(BUFFER_SIZE * NB_CHANNELS * 2);
packet_t packet;
int ret = 0;
if (!this->encoder)
throw Exception("Can't encode since there is no decoder.");
ret = opus_encode_float(this->encoder, reinterpret_cast<float const*>(to_encode.data()), FRAME_SIZE, data.data(), data.size());
if (ret < 0)
throw Exception("Error while encoding data.");
packet.size = ret;
packet.data = data;
return packet;
}
And there is the call of the functions:
packet_t packet;
std::vector<float> floats = {0.23, 0, -0.312, 0.401230, 0.1234, -0.1543};
packet = CodecPlugin->encode(floats);
std::cout << "packet size: " << packet.size << std::endl;
std::vector<float> output = CodecPlugin->decode(packet);
for (int i = 0; i < 10; i++) {
std::cout << output.data()[i] << " ";
}
Here is the packet_t structure, where I stock the return value of encode and the unsigned char array (encoded value)
typedef struct packet_s {
int size;
std::vector<unsigned char> data;
} packet_t;
The output of the program is
*-1.44487e-15 9.3872e-16 -1.42993e-14 7.31834e-15 -5.09662e-14 1.53629e-14 -8.36825e-14 3.9531e-14 -8.72754e-14 1.0791e-13 which is not the array I initialize at the beginning.
I read a lot of times the documentation and code examples but I don't know where I did a mistake.
I hope you will be able to help me.
Thanks :)
We don't see how you initialize your encoder and decoder so we don't know what their sample rate, complexity or number of channels is. No matter how you have initialized them you are still going to have the following problems:
First Opus encoding doesn't support arbitrary frame sizes but instead 2.5ms, 5ms, 10ms, 20, 40ms or 60ms RFC 6716 - Definition of the Opus Audio Codec relevant section 2.1.4. Moreover opus supports only 8kHz, 12kHz, 16kHz, 24kHz or 48kHz sample rates. No matter which of those you have chosen your array of 10 elements doesn't correspond to any of the supported frame sizes.
Secondly Opus codec is a lossy audio codec. This means that after you encode any signal you will never (probably except some edge cases) be able to reconstruct the original signal after decoding the encoded opus frame. The best way to test if your encoder and decoder work is with a real audio sample. Opus encoding preserves the perceptual quality of the audio files. Therefore if you try to test it with arbitrary data you might not get the expected results back even if you implemented the encoding and decoding functions correctly.
What you can easily do is to make a sine function of 2000Hz(there are multiple examples on the internet) for 20ms. This means 160 array elements at a sample rate of 8000Hz if you wish to use 8kHz. A sine wave of 2kHz is within the human hearing range so the encoder is going to preserve it. Then decode it back and see whether the elements of the input and output array are similar as we've already established that it is unlikely that they are the same.
I am not good in C++ so I can't help you with code examples but the problems above hold true no matter what language is used.

OpenCV how to encode and send data of webcam video stream efficiently?

I have this OpenCV C++ code which is taking an image from the cam, encoding it and sending it to the STDOUT.
#include <unistd.h> //STDOUT_FILENO
#include "opencv2/opencv.hpp"
#include <iostream>
#include <fcntl.h>
using namespace std;
using namespace cv;
#define BUFLEN 4096
int main(int argc, char *argv[])
{
Mat frame;
std::vector<uchar> buf;
int bak, temp;
//read image as grayscale
namedWindow( "Camera", WINDOW_AUTOSIZE );
//redirect stdout to NULL in order to avoid printing to STDOUT undesired stuff
fflush(stdout);
bak = dup(1);
temp = open("/dev/null", O_WRONLY);
dup2(temp, 1);
close(temp );
VideoCapture cam(0 + CAP_V4L);
cam>>frame;
sleep(1);
if (!cam.isOpened())
{
cout << "\nCould not open reference " << 0 << endl;
return -1;
}
for (int i=0; i<5; i++)
{
cam>>frame;
}
/*Set the normal STDOUT back*/
fflush(stdout);
dup2(bak, 1);
close(bak);
//encode image and put data into the vector buf
imencode(".png",frame, buf);
//send the total size of vector to parent
cout<<buf.size()<<endl;
unsigned int written= 0;
int i = 0;
size_t toWrite = 0;
//send until all bytes have been sent
FILE * f = fdopen(STDOUT_FILENO, "w");
while (written<buf.size())
{
//send the current block of data
toWrite = BUFLEN < (buf.size()-written) ? BUFLEN : (buf.size()-written);
//written += write(STDOUT_FILENO, buf.data()+written, toWrite);
written += toWrite*fwrite ( buf.data()+written, toWrite, 1, f );
i++;
}
return 0;
}
Now instead of an image I would like to take an infinite continuous video from the cam. One solution would be to take a frame any given seconds, encode the frame and transmit it (print it to STDOUT), all actions inside an infinite loop.
Is there a better solution, more efficient than encoding and send each frame at each iteration?
Fundamentally, a video stream is a sequence of frames in a predefined order.
You could simply send the frames as images, one after another. There is nothing fundamentally wrong with that, but is not necessarily optimal (which also depends on your definition of optimal).
In communication, one of the aspects is to minimize the amount of data transferred. Simply sending the frames as images allows you to do some compression (e.g. jpeg). Better compression algorithms for video (e.g. mpeg) use the temporal properties of the sequence. If there is a (mostly) static frame, you can limit yourself sending data about the changing parts and assume the background is the same. This goes with some processing at both ends of the communication, but might increase the communication speed (assuming the link is the bottleneck). This would also add a lot of complexity to the system, so think about the potential advantages first (identify the bottlenecks).
I am not sure about the usage of your application, but sending the video stream to stdout might not necessarily be the best idea. Consider using a pipe or a socket instead (the latter allows you quite easily to transfer data over the network as well, which might be a nice outcome).

Confusion about PTS in video files and media streams

Is it possible that the PTS of a particular frame in a file is different with the PTS of the same frame in the same file while it is being streamed?
When I read a frame using av_read_frame I store the video stream in an AVStream. After I decode the frame with avcodec_decode_video2, I store the time stamp of that frame in an int64_t using av_frame_get_best_effort_timestamp. Now if the program is getting its input from a file I get a different timestamp from when I stream the input (from the same file) to the program.
To change the input type I simply change the argv argument from "/path/to/file.mp4" to something like "udp://localhost:1234", then I stream the file with ffmpeg in command line: "ffmpeg -re -i /path/to/file.mp4 -f mpegts udp://localhost:1234". Can it be because the "-f mpegts" arguments change some characteristics of the media?
Below is my code (simplified). By reading the ffmpeg mailing list archives I realized that the time_base that I'm looking for is in the AVStream and not the AVCodecContext. Instead of using av_frame_get_best_effort_timestamp I have also tried using the packet.pts but the results don't change.
I need the time stamps to have a notion of frame number in a streaming video that is being received.
I would really appreciate any sort of help.
//..
//argv[1]="/file.mp4";
argv[1]="udp://localhost:7777";
// define AVFormatContext, AVFrame, etc.
// register av, avcodec, avformat_network_init(), etc.
avformat_open_input(&pFormatCtx, argv, NULL, NULL);
avformat_find_stream_info(pFormatCtx, NULL);
// find the video stream...
// pointer to the codec context...
// open codec...
pFrame=av_frame_alloc();
while(av_read_frame(pFormatCtx, &packet)>=0) {
AVStream *strem = pFormatCtx->streams[videoStream];
if(packet.stream_index==videoStream) {
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if(frameFinished) {
int64_t perts = av_frame_get_best_effort_timestamp(pFrame);
if (isMyFrame(pFrame)){
cout << perts*av_q2d(strem->time_base) << "\n";
}
}
}
//free allocated space
}
//..
Timestamps are stored at the container level, so changing the container can change the timestamps. In addition, TS stores a timestamp for every frame (based on a 90kHz clock). MP4 only stores the frame durations with an assumed start time of 0 (this gets more complicated with bframes since the first PTS is zero, and the first DTS is < 0). So to get the time stamp all the frame durations are added. Mp4 also allows the clock rate be set. It is often 1001/3000 ticks per second for 29.97FPS, but it can be set to anything. so av_frame_get_best_effort_timestamp returns you ticks in codec->stream_base units. For TS codec->stream_base is always 1/90000

Fourcc with mac os X

I need to write a video from a sequence of images. I am using this code:
int main()
{
//Read sequence of images
Size frameSize(1360,1024);
//cout<<path<<endl;
VideoCapture sequence("path/fr%1d.jpg");
if (!sequence.isOpened())
{
cerr << "Failed to open Image Sequence!\n" << endl;
return -1;
}
//Write video
VideoWriter oVideoWriter ("path/MyVideo.avi",CV_FOURCC('8','B','P','S'), 15
, frameSize);
Mat imageGrey;
if(!oVideoWriter.isOpened())
{
cout<<"ERROR: Failed to write the video"<<endl;
return -1;
}
Mat Image;
int i=0;
while(true)
{
sequence>>Image;
if(Image.empty())
break;
cout<<i<<endl;
Mat imageArr[] = {Image, Image, Image};
merge(imageArr, 3, imageGrey);
//cvtColor(Image,imageGrey,CV_GRAY2BGR);
oVideoWriter.write(imageGrey);
i++;
}
cout<<"video written!"<<endl;
return 1;
}
I get a very dark video compared with one in Windows 7. I think it a problem of codec. What is the best codec that works on mac os x. thanks
As you said if you compared it to Windows, it's probably the codec problem. There is no best codec; some codecs are better for specific situations while worse for other cases. A common codec to use may be XVID using CV_FOURCC('X', 'V', 'I', 'D') but there is no guarantee that you have it.
A good practice is to pass -1 instead of CV_FOURCC() macro in the cv::VideoWriter constructor for your first run. A window will pop up and you can see what types of codecs you have available to use. When you are happy with one of them, find the 4CC code of that code and hardcode it in your program.
Also you may want to try Perian to have access to more codecs in Mac OS.

C++ Is live PCM fft audio processing with OpenAL?

I'm working on a project that will involve having to process PCM audio data through fft as its being played, preferably in sync. I'm using a linux g++ compiler and currently reading and playing audio data using OpenAL.
My question is this: is there a better way to process PCM audio data with an fft live as the audio is playing then using threads? If not, then what threading library would be best to use for these purposes.
this is my function that loads the wave data into an array of bytes, these can later be cast to ints for processing and all I use to play the data is OpenAL.
char* loadWAV(const char* fn, int& chan, int& samplerate, int& bps, int& size){
char buffer[4];
ifstream in(fn, ios::binary);
in.read(buffer, 4); //ChunkID "RIFF"
if(strncmp(buffer, "RIFF", 4) != 0){
cerr << "this is not a valid wave file";
return NULL;
}
in.read(buffer,4); //ChunkSize
in.read(buffer,4); //Format "WAVE"
in.read(buffer,4); // "fmt "
in.read(buffer,4); // 16
in.read(buffer,2); // 1
in.read(buffer,2); // NUMBER OF CHANNELS
chan = convertToInt(buffer,2);
in.read(buffer,4); // SAMPLE RATE
samplerate = convertToInt(buffer,4);
in.read(buffer,4); // ByteRate
in.read(buffer,2); // BlockAlign
in.read(buffer,2); // bits per sample
bps = convertToInt(buffer,2);
in.read(buffer,4); // "data"
in.read(buffer,4);
size = convertToInt(buffer,4);
char * data = new char[size];
in.read(data,size);
return data;
}
thank you for any and all help.
edit: to anyone who might be interested I wrote the function using this as a reference to know
how a WAV file is formated
Are you hoping to perform the FFT using OpenAL? I don't know if that's possible. Your code will likely be performing the FFT.
You don't need to explicitly set up any threads. However, your audio output library will probably do so on your behalf. I'm not familiar with OpenAL, but the way that a lot of audio libraries operate is by letting you specify a callback that will feed more audio into the output. Thus, your main program will load audio from the audio file, stuff it into a buffer (likely protected by a mutex) for the audio callback to read, compute an FFT over the audio window, and perhaps visualize the data for the user.
Again, the audio library will probably be managing the threading so you don't need to worry about the exact threading implementation or library. But be sure to manage shared data correctly with a mutex.