PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Videowiedergabe unter Qt4



apokalypse
13-05-2007, 12:46
Hallo,

ich dekodiere ein Video unter Windows mittels ffmpeg und versuche die einzelnen Frames mittels QPainter auszugeben, jedoch zeigt er mir immer nur den letzten Frame des Videos an. Wo liegt hier mein Fehler :confused:


#ifndef WINDOW_H_
#define WINDOW_H_

#include "avformat.h"
#include <QWidget>
#include <QPainter>

class Window : public QWidget
{
Q_OBJECT

public:
Window();

protected:
virtual void paintEvent(QPaintEvent*);
virtual void keyPressEvent(QKeyEvent*);

private slots:
void play();

private:
void decode(char*);
QPixmap *fPixmap;
QPixmap *constructPixmap(AVFrame*, int, int);
};

#endif /*WINDOW_H_*/


#include "window.h"
#include <QBuffer>
#include <iostream>

using namespace std;

Window::Window()
{
// Register all available codecs
av_register_all();

fPixmap = NULL;
}

void Window::play()
{
char *avfile = "test.mpg";
decode(avfile);
}

void Window::keyPressEvent(QKeyEvent*)
{
play();
}

void Window::paintEvent(QPaintEvent*)
{
QPainter p(this);
if(fPixmap != NULL)
p.drawPixmap(10, 10, *fPixmap);
}


void Window::decode(char *input_filename)
{
int err = 0, i = 0, len1 = 0, got_picture, video_index = -1;

AVFormatContext *fcx = NULL;
AVCodecContext *ccx = NULL;
AVCodec *codec = NULL;

AVFormatParameters params;
AVPacket pkt;
AVFrame *frame = avcodec_alloc_frame();
AVFrame *frameRGB = avcodec_alloc_frame();

int numBytes;
uint8_t *buffer;

// Open the input file.
err = av_open_input_file(&fcx, input_filename, NULL, 0, &params);
if(err < 0)
cout << "Can't open file: " << input_filename << endl;
else
{
// Find the stream info.
err = av_find_stream_info(fcx);

// Find the first video stream.
for(i = 0; i <fcx->nb_streams; i++)
{
ccx = fcx->streams[i]->codec;
if(ccx->codec_type == CODEC_TYPE_VIDEO)
break;
}

video_index = i;

// Open stream.
if(video_index >= 0)
{
codec = avcodec_find_decoder(ccx->codec_id);
if(codec)
err = avcodec_open(ccx, codec);
if(err < 0)
cout << "Can't open codec." << endl;
}
else
cout << "Video stream not found." << endl;

// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, ccx->width, ccx->height);
buffer=new uint8_t[numBytes];

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

// Decode
while(true)
{
// Read a frame/packet.
if(av_read_frame(fcx, &pkt) < 0 )
break;

// If it's a video packet from our video stream...
if(pkt.stream_index == video_index)
{
// Decode the packet
len1 = avcodec_decode_video(ccx, frame, &got_picture,
pkt.data, pkt.size);

if(got_picture)
{

// Convert image to RGB
img_convert((AVPicture*)frameRGB, PIX_FMT_RGB24, (AVPicture*)frame,
ccx->pix_fmt, ccx->width, ccx->height);

// Display frames
fPixmap = constructPixmap(frameRGB, ccx->width, ccx->height);
this->update();
}

av_free_packet(&pkt);
}
}

// Clean up
av_free(frameRGB);
av_free(frame);
av_close_input_file(fcx);
}
}

QPixmap* Window::constructPixmap(AVFrame *pFrame, int width, int height)
{
char buffer[128];

QBuffer *pImageBuffer = new QBuffer();
pImageBuffer->open(QIODevice::WriteOnly);
QDataStream *pDataStream = new QDataStream(pImageBuffer);

// Header for ppm
sprintf(buffer,"P6 %d %d 255\n", width, height);
pDataStream->writeRawData(buffer, strlen(buffer));

// Writing the ppm data
for(int y = 0; y < height; y++)
pDataStream->writeRawData((char*)pFrame->data[0] + y * pFrame->linesize[0], width * 3);

pImageBuffer->close();
pImageBuffer->open(QIODevice::ReadOnly);

QPixmap *pixmap = new QPixmap();

// Convert buffer to pixmap
if(pixmap->loadFromData(pImageBuffer->buffer()))
{
pImageBuffer->close();
delete pImageBuffer;
delete pDataStream;

return pixmap;
}

cout << "Failed to construct pixmap" << endl;

// Free buffer
pImageBuffer->close();
delete pImageBuffer;
delete pDataStream;

return NULL;
}

apokalypse
13-05-2007, 17:49
Problem hat sich erledigt ;)

panzi
13-05-2007, 19:01
Und wie schnell läuft das mit QPainter als Videoausgabedevice?

apokalypse
14-05-2007, 09:33
Also es läuft auf jeden Fall flüssig, wenn ich das Bild per timer alle 15 ms aktualisiere. Werds in kürze auch noch mit opengl testen.