[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