[Libav-user] Threading a h264 video decoder - timing is odd.
Jesper Taxbøl
jesper at taxboel.dk
Fri Jun 3 14:09:08 CEST 2016
Hi Guys,
I am working on a threaded video reader to spread the decode workload on
some more cores and gain some speed. My source is included below:
The thing is that I dont see a time improvement when starting two processes
instead of one. On a 80mb mp4 file it takes 6 seconds to decode the video,
while doing two in parallel takes 12 seconds. I can see that two cores's
are used 100 percent. Im on a fast SSD disk so I dont think im IO limited.
What could be the case. Is it the same decoder taht is doing all the work?
Do I perhaps need to instantiate a context or something?
kind regards
--
Jesper Taxbøl
#include "BlockReader.h"
#include <iostream>
#include <stdio.h>
#include <unistd.h>
void frameReaderThread(char* fn, Queue<AVFrame*>* q)
{
clock_t end;
clock_t begin= clock();
double elapsed_secs;
AVCodec *pCodec;
int frame_count;
AVFrame *pAVFrame;
AVPacket packet;
AVFormatContext *pFormatCtx;
int videoStreamIndex;
int audioStreamIndex;
AVCodecContext *pCodecCtx = NULL;
AVCodecContext *pCodecCtxOrig = NULL;
cout << fn << endl;
frame_count = 0;
av_init_packet(&packet);
pFormatCtx = NULL;
if(avformat_open_input(&pFormatCtx, fn, NULL, NULL)!=0)
{
cout << "Could not open file: " << fn << endl;
exit(1);
}
// Retrieve stream information
if(avformat_find_stream_info(pFormatCtx, NULL)<0)
{
cout << "Cant find stream info" << endl;
exit(1);
}
// Dump information about file onto standard error
//av_dump_format(pFormatCtx, 0, fn, 0);
videoStreamIndex = -1;
audioStreamIndex = -1;
for(unsigned int i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStreamIndex = i;
}
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)
{
audioStreamIndex = i;
}
}
//cout << "video index " << videoStreamIndex << endl;
//cout << "audio index " << audioStreamIndex << endl;
if(videoStreamIndex == -1)
{
cout << "Unable to find a video index" << endl;
exit(1);
}
// Get a pointer to the codec context for the video stream
pCodecCtxOrig = pFormatCtx->streams[videoStreamIndex]->codec;
/* find the correct video decoder */
pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id);
if (!pCodec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
//Dont know if this is required
pCodecCtx = avcodec_alloc_context3(pCodec);
if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
fprintf(stderr, "Couldn't copy codec context");
exit(1);
}
cout << "Video codec is " << pCodec->name << endl;
/* open it */
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
bool run = true;
end = clock();
elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
cout << "Prepare time: " << fn << " " << elapsed_secs << endl;
begin = clock();
do{
//Build a frame
//pAVFrame = new AVFrame();
pAVFrame = av_frame_alloc();
if (!pAVFrame) {
fprintf(stderr, "Could not allocate video frame\n");
return;
}
//Fetch packets until frame is built
do
{
/*while(q->size() > 50)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}*/
int read_bytes = av_read_frame(pFormatCtx, &packet);
if(read_bytes < 0)
{
run = false;
cout << "end of file reached" << endl;
}
else
{
int frameFinished;
if(packet.stream_index==videoStreamIndex)
{
//cout << "video frame " << frame_count++ << " " << fn
<< endl;
avcodec_decode_video2(pCodecCtx, pAVFrame,
&frameFinished, &packet);
if(frameFinished)
{
//cout << "returning frame " << frame_count++ <<
endl;
q->push(av_frame_clone(pAVFrame));
}
}else
{
if(packet.stream_index==audioStreamIndex)
{
//cout << "audio frame" << endl;
}
else
{
//cout << "other frame" << packet.stream_index <<
endl;
}
}
}
}while(run);
//av_frame_free(&pAVFrame);
}while(run);
end = clock();
elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
cout << "Decode time: " << fn << " " << elapsed_secs << endl;
begin = clock();
//Signal no more frames
q->push(NULL);
av_frame_free(&pAVFrame);
// Close the codecs
avcodec_close(pCodecCtx);
avcodec_close(pCodecCtxOrig);
// Close the video file
avformat_close_input(&pFormatCtx);
}
BlockReader::BlockReader(char* fn): Block()
{
cout << "BlockReader::Constructor "<< serial_number << " " << fn <<
endl;
//Spawn off thread to cache frames
std::thread t(frameReaderThread, fn, &frames);
t.detach();
}
AVFrame* BlockReader::getFrame(float t_seconds)
{
return frames.pop();
}
BlockReader::~BlockReader()
{
cout << "Blockreader::Destructor " << serial_number << endl;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20160603/824ac680/attachment.html>
More information about the Libav-user
mailing list