[qt4] read mpeg4 stream from network IP cam

  • jvccthread.h
  • #include <QThread>
    #include <QMutex>
    #include <QWaitCondition>
    #include <QBuffer>
    extern "C"
    {
    #include <libavformat/avformat.h>
    #include <libavcodec/avcodec.h>
    #include <libswscale/swscale.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdbool.h>
    #include <cstdio>
    }
    class jvcMpegThread : public QThread
    {
    Q_OBJECT
    public:
    jvcMpegThread(QByteArray *parent_array=0,unsigned int read_buffer_size=1024,QObject *parent=0);
    void getMpegImage(AVFrame *pFrame, int w, int h,int i);
    int read_packet(uint8_t *buf,int buf_size);

    bool readyForNextPacket;
    protected:
    void run();
    QMutex mutex;
    QWaitCondition condition;
    QBuffer *buf,*dataBuf;
    QByteArray byteArray,*dataArray;
    unsigned intbio_buffer_size;

    signals:
    void newImageSignal(QByteArray *);
    void giveMoreData();
    };
  • jvccthread.cpp
  • #include "jvccthread.h"
    #include <QDebug>
    FILE *pFile = NULL;
    AVFormatContext *pFormatCtx;
    int         i, videoStream;
    AVCodecContext  *pCodecCtx;
    AVCodec     *pCodec;
    AVFrame     *pFrame;
    AVFrame     *pFrameRGB;
    AVPacket    packet;
    int         frameFinished;
    int         numBytes;
    uint8_t     *buffer;
    unsigned char   *bio_buffer;
    AVInputFormat   *fmt;
    AVFormatParameters ap;
    ByteIOContext *io;
    static struct SwsContext *img_convert_ctx;

    static int read_packets(void *opaque,uint8_t *buf,int buf_size)
    {
    jvcMpegThread *mp=(jvcMpegThread *)opaque;
    int ret=mp->read_packet(buf,buf_size);
    //Debug("HRE");
       // int ret = fread(buf, 1, buf_size, pFile);
    return ret;
    }
    jvcMpegThread::jvcMpegThread(QByteArray *parent_array,unsigned int read_buffer_size,QObject *parent)
        :QThread(parent),dataArray(parent_array),bio_buffer_size(read_buffer_size)
    {
    buf=new QBuffer(&byteArray);
    //data=new QDataStream(buf);
    buf->open(QIODevice::WriteOnly);
    dataBuf=new QBuffer(dataArray);
    dataBuf->open(QIODevice::ReadWrite);
    readyForNextPacket=false;
       // QThread::start(QThread::LowPriority);

    }

    void jvcMpegThread::getMpegImage(AVFrame *pFrame, int w, int h,int i)
    {
    int  y,x;
     //byteArray.clear();
     buf->seek(0);
     buf->write(QString("P6\n"+QString::number(w)+" "+QString::number(h)+"\n255\n").toLatin1().data());

    // Write pixel data
    for(y=0; y<h; y++)
    {
        buf->write((char *)(pFrame->data[0]+y*pFrame->linesize[0]),w*3);
    }
    emit newImageSignal(&byteArray);
    }

    void jvcMpegThread::run()
    {
       // mutex.lock();

      //  mutex.unlock();
    //pFile = fopen("test.mpg", "rb");
    av_register_all();

    fmt=av_find_input_format("m4v");

    fmt->flags |= AVFMT_NOFILE|AVFMT_FLAG_IGNIDX;
    //bio_buffer_size=61440;
    bio_buffer=(unsigned char *)av_malloc(bio_buffer_size);
    io=new ByteIOContext;
    io->is_streamed=1;

    int ret = init_put_byte(io, bio_buffer, bio_buffer_size, 0, this, read_packets, NULL, NULL);
    if (av_open_input_stream(&pFormatCtx, io, "", fmt, NULL)!=0)
        return;
    qDebug("Stream Opened");
    if(av_find_stream_info(pFormatCtx)<0)
    {
        qDebug("Stream Info Error");
        return;
    }//qDebug("Stream Info Error"); // Couldn't find stream information
       qDebug("Stream Finded");
    // dump_format(pFormatCtx, 0, "test.mpg", false);

    videoStream=-1;
    for(i=0; i<pFormatCtx->nb_streams; i++)
        if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
        {
            videoStream=i;
            break;
        }
    if(videoStream==-1)
        return;// Didn't find a video strea
    qDebug()<<"Codec Finded"<<videoStream;

    // Get a pointer to the codec context for the video stream
    pCodecCtx=pFormatCtx->streams[videoStream]->codec;

    // Find the decoder for the video stream
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec==NULL)
        qDebug("Codec Error"); // Codec not found

    // Open codec
    if(avcodec_open(pCodecCtx, pCodec)<0)
        qDebug("Codec Open Error"); // Could not open codec

    // Hack to correct wrong frame rates that seem to be generated by some codecs
      //  if(pCodecCtx->time_base.num>1000 && pCodecCtx->time_base.den==1)
      //      pCodecCtx->time_base.den=1000;

    // Allocate video frame
    pFrame=avcodec_alloc_frame();

    // Allocate an AVFrame structure
    pFrameRGB=avcodec_alloc_frame();
    if(pFrameRGB==NULL)
        qDebug("Error");

    // Determine required buffer size and allocate buffer
    numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,pCodecCtx->height);
    qDebug()<<numBytes;
    buffer=(uint8_t *)malloc(numBytes);

    // Assign appropriate parts of buffer to image planes in pFrameRGB
    avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
        pCodecCtx->width, pCodecCtx->height);

    // Read frames and save first five frames to disk
    i=0;
    int w = pCodecCtx->width;
    int h = pCodecCtx->height;
    int dst_w=800;
    int dst_h=600;

    img_convert_ctx = sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC,NULL, NULL, NULL);
    while (av_read_frame(pFormatCtx, &packet)>=0)
        {

          // Is this a packet from the video stream?
        if(packet.stream_index==videoStream)
        {

            // Decode video frame
            avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,
                packet.data, packet.size);

            // Did we get a video frame?
            if(frameFinished)
            {
                    sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
                    i++;
                    getMpegImage(pFrameRGB, pCodecCtx->width, pCodecCtx->height,i);
            }
        }

        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
        }

    }
    int jvcMpegThread::read_packet(uint8_t *buf,int buf_size)
    {
    emit giveMoreData();
    while (!readyForNextPacket)
    {
           // qDebug("Waiting for READ");
        this->msleep(1);
    }
    readyForNextPacket=false;
    dataBuf->seek(0);
    qint64 ret=dataBuf->read((char *)buf,buf_size);
    return ret;

    }
  • mpeggstream.h
  • #include "jvccthread.h"
    #include <QTcpSocket>
    class mpegStream : public QObject
    {
    Q_OBJECT
    public:
    mpegStream(QTcpSocket *parent=0);
    public slots:
    void startStopThread(bool);
    private slots:
    void readDataStream();



    signals:
    //void newImageSignal(QByteArray *);
    void newDataForDecode(uint);
    void newDataSignal(QByteArray *);
    private:
    QByteArray block,dataArray;
    uchar *frame;
    int blockcount;
    jvcMpegThread *th;
    unsigned int read_buffer_size;
    int wait_interval;
    QTcpSocket *socket;
    };
  • mpeggstream.cpp
  • #include "mpegstream.h"


    mpegStream::mpegStream(QTcpSocket *parent)
    :socket(parent)
    {
    //file=new QFile;
    //file->open(QIODevice::ReadOnly);
    blockcount=0;
    read_buffer_size=61440/2;
    th=new jvcMpegThread(&dataArray,read_buffer_size);
    connect(th,SIGNAL(newImageSignal(QByteArray*)),this,SIGNAL(newDataSignal(QByteArray*)));
    connect(th,SIGNAL(giveMoreData()),this,SLOT(readDataStream()));
    connect(this,SIGNAL(newDataForDecode(uint)),th,SLOT(getPacket(uint)));
    block.clear();


    }

    void mpegStream::readDataStream()
    {
    //qDebug()<<block.data();
    if (socket->bytesAvailable()>200000) qDebug()<<socket->bytesAvailable();
     while (block.size()<read_buffer_size)
        {
        //qDebug()<<"Entering While"<<socket->bytesAvailable()<<block.size();
            if (socket->bytesAvailable()==0)
            {
                socket->waitForReadyRead(3000);
             //   qDebug()<<block.data();
               // qDebug("Bytes Available 0");
            }
            if (socket->bytesAvailable()+block.size()<read_buffer_size)

                block.append(socket->readAll());
            else
            {
                if (block.size()>0 && block.size()<read_buffer_size) block.append(socket->read(read_buffer_size-block.size()));
                //else if (block.size()==61 440) readyForDecode=true;
                else block=socket->read(read_buffer_size);
            }
        }
        dataArray=block;
        th->readyForNextPacket=true;
      //  qDebug()<<block.data();
        block.clear();
    }

    void mpegStream::startStopThread(bool b)
    {
    if (b) th->start(QThread::LowPriority);
        else
       {
        th->terminate();
        th->wait(100);
    }
    }