<div dir="ltr"><div><div><div>Hi Guys,<br><br></div>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:<br><br></div>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.<br><br></div><div>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?<br></div><div><div><br></div><div>kind regards<br></div><div><br>-- <br>Jesper Taxbøl<br><br><br><br><br><div><div>#include "BlockReader.h"<br>#include <iostream><br>#include <stdio.h><br>#include <unistd.h><br><br>void frameReaderThread(char* fn, Queue<AVFrame*>* q)<br>{<br>    clock_t end;<br>    clock_t begin= clock();<br>    double elapsed_secs;<br><br>    AVCodec *pCodec;<br>    int frame_count;<br>    AVFrame *pAVFrame;<br>    AVPacket packet;<br>    AVFormatContext *pFormatCtx;<br>    int videoStreamIndex;<br>    int audioStreamIndex;<br>    AVCodecContext *pCodecCtx = NULL;<br>    AVCodecContext *pCodecCtxOrig = NULL;<br><br>    cout << fn << endl;<br><br>    frame_count = 0;<br><br>    av_init_packet(&packet);<br><br>    pFormatCtx = NULL;<br><br>    if(avformat_open_input(&pFormatCtx, fn, NULL, NULL)!=0)<br>    {<br>        cout << "Could not open file: " << fn << endl;<br>        exit(1);<br>    }<br><br>    // Retrieve stream information<br>    if(avformat_find_stream_info(pFormatCtx, NULL)<0)<br>    {<br>        cout << "Cant find stream info" << endl;<br>        exit(1);<br>    }<br><br>    // Dump information about file onto standard error<br>    //av_dump_format(pFormatCtx, 0, fn, 0);<br><br>    videoStreamIndex = -1;<br>    audioStreamIndex = -1;<br><br>    for(unsigned int i=0; i<pFormatCtx->nb_streams; i++)<br>    {<br>        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)<br>        {<br>            videoStreamIndex = i;<br>        }<br>        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)<br>        {<br>            audioStreamIndex = i;<br>        }<br>    }<br><br>    //cout << "video index " << videoStreamIndex << endl;<br>    //cout << "audio index " << audioStreamIndex << endl;<br><br>    if(videoStreamIndex == -1)<br>    {<br>        cout << "Unable to find a video index" << endl;<br>        exit(1);<br>    }<br><br>    // Get a pointer to the codec context for the video stream<br>    pCodecCtxOrig = pFormatCtx->streams[videoStreamIndex]->codec;<br><br>    /* find the correct video decoder */<br>    pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id);<br>    if (!pCodec) {<br>        fprintf(stderr, "Codec not found\n");<br>        exit(1);<br>    }<br><br>    //Dont know if this is required<br>    pCodecCtx = avcodec_alloc_context3(pCodec);<br>    if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {<br>        fprintf(stderr, "Couldn't copy codec context");<br>        exit(1);<br>    }<br><br>    cout << "Video codec is " << pCodec->name << endl;<br><br>    /* open it */<br>    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {<br>        fprintf(stderr, "Could not open codec\n");<br>        exit(1);<br>    }<br><br><br>    bool run = true;<br><br><br>    end = clock();<br>    elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;<br>    cout << "Prepare time: " << fn << " " << elapsed_secs << endl;<br>    begin = clock();<br><br>    do{<br>        //Build a frame<br>        //pAVFrame = new AVFrame();<br>        pAVFrame = av_frame_alloc();<br><br>        if (!pAVFrame) {<br>            fprintf(stderr, "Could not allocate video frame\n");<br>            return;<br>        }<br><br>        //Fetch packets until frame is built<br>        do<br>        {<br>            /*while(q->size() > 50)<br>            {<br>                std::this_thread::sleep_for(std::chrono::milliseconds(1));<br>            }*/<br><br>            int read_bytes = av_read_frame(pFormatCtx, &packet);<br>            if(read_bytes < 0)<br>            {<br>                run = false;<br>                cout << "end of file reached" << endl;<br>            }<br>            else<br>            {<br><br>                int frameFinished;<br>                if(packet.stream_index==videoStreamIndex)<br>                {<br>                    //cout << "video frame " << frame_count++ << " " << fn << endl;<br>                    avcodec_decode_video2(pCodecCtx, pAVFrame, &frameFinished, &packet);<br>                    if(frameFinished)<br>                    {<br>                        //cout << "returning frame " << frame_count++ << endl;<br>                        q->push(av_frame_clone(pAVFrame));<br><br>                    }<br>                }else<br>                {<br>                    if(packet.stream_index==audioStreamIndex)<br>                    {<br>                        //cout << "audio frame" << endl;<br>                    }<br>                    else<br>                    {<br>                        //cout << "other frame" << packet.stream_index << endl;<br>                    }<br>                }<br>            }<br>        }while(run);<br>        //av_frame_free(&pAVFrame);<br>    }while(run);<br><br>    end = clock();<br>    elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;<br>    cout << "Decode time: " << fn << " " << elapsed_secs << endl;<br>    begin = clock();<br><br>    //Signal no more frames<br>    q->push(NULL);<br>    av_frame_free(&pAVFrame);<br><br>    // Close the codecs<br>    avcodec_close(pCodecCtx);<br>    avcodec_close(pCodecCtxOrig);<br><br>    // Close the video file<br>    avformat_close_input(&pFormatCtx);<br>}<br><br>BlockReader::BlockReader(char* fn): Block()<br>{<br>    cout << "BlockReader::Constructor "<< serial_number << " " << fn << endl;<br><br>    //Spawn off thread to cache frames<br>    std::thread t(frameReaderThread, fn, &frames);<br>    t.detach();<br>}<br><br>AVFrame* BlockReader::getFrame(float t_seconds)<br>{<br>    return frames.pop();<br>}<br><br>BlockReader::~BlockReader()<br>{<br>    cout << "Blockreader::Destructor " << serial_number << endl;<br>}<br><br><br><br><br><div class="gmail_signature" data-smartmail="gmail_signature"><br><br></div>
</div></div></div></div></div>