[qt4] read mpeg4 stream from network IP cam
develop/qt4 2011. 7. 6. 15:09
- 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);
}
}
'develop > qt4' 카테고리의 다른 글
크로스플랫폼 시리얼 라이브러리 - qtextserialport (0) | 2012.11.09 |
---|---|
[qt4] QFileSystemModel 경로 설정하기 (0) | 2011.07.04 |
[qt4] 일정 시점에서부터 지정한 시간이 지났는지 체크 - 타이머 (0) | 2011.06.24 |
[qt4] 디바이스들 초기화 하기 (0) | 2011.06.09 |
qlabel 색 지정하기 (0) | 2011.05.24 |